@dogsbay/minja 0.2.0-beta.100
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.
- package/LICENSE +21 -0
- package/README.md +623 -0
- package/bin/minja.js +1225 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +11 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +98 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +47 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +112 -0
- package/dist/context.js.map +1 -0
- package/dist/evaluator.d.ts +20 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +213 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +1160 -0
- package/dist/index.umd.js.map +7 -0
- package/dist/index.umd.min.js +12 -0
- package/dist/index.umd.min.js.map +7 -0
- package/dist/loader-fetch.d.ts +8 -0
- package/dist/loader-fetch.d.ts.map +1 -0
- package/dist/loader-fetch.js +15 -0
- package/dist/loader-fetch.js.map +1 -0
- package/dist/loader-memory.d.ts +11 -0
- package/dist/loader-memory.d.ts.map +1 -0
- package/dist/loader-memory.js +36 -0
- package/dist/loader-memory.js.map +1 -0
- package/dist/loader.d.ts +73 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +159 -0
- package/dist/loader.js.map +1 -0
- package/dist/parser.d.ts +7 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +609 -0
- package/dist/parser.js.map +1 -0
- package/dist/renderer.d.ts +13 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +494 -0
- package/dist/renderer.js.map +1 -0
- package/dist/scan.d.ts +46 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +46 -0
- package/dist/scan.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/browser.ts", "../src/evaluator.ts", "../src/parser.ts", "../src/context.ts", "../src/loader-fetch.ts", "../src/renderer.ts", "../src/loader-memory.ts", "../src/scan.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Browser-only entry point (excludes FileSystemLoader)\n */\n\nexport { render } from './renderer.js'\nexport { parse } from './parser.js'\nexport { parseExpression, evaluateExpression } from './evaluator.js'\nexport { Context } from './context.js'\nexport { FetchLoader } from './loader-fetch.js'\nexport { MemoryLoader } from './loader-memory.js'\n\nexport type {\n // AST types\n ASTNode,\n TextNode,\n VariableNode,\n SetNode,\n IfNode,\n IncludeNode,\n CommentNode,\n\n // Expression types\n Expression,\n LiteralExpression,\n VariableExpression,\n BinaryExpression,\n UnaryExpression,\n\n // Options and interfaces\n RenderOptions,\n Loader,\n IContext,\n ParseResult,\n ParseError,\n} from './types.js'\nexport { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js'\n", "/**\n * Safe expression evaluator\n * Evaluates expressions WITHOUT using eval() or new Function()\n * Only allows whitelisted operations\n */\n\nimport type { Expression, IContext } from './types.js'\n\n/**\n * Parse an expression string into an Expression AST\n * @param expr - Expression string to parse\n * @returns Expression AST\n */\nexport function parseExpression(expr: string): Expression {\n expr = expr.trim()\n\n // Handle boolean literals\n if (expr === 'true') {\n return { type: 'literal', value: true }\n }\n if (expr === 'false') {\n return { type: 'literal', value: false }\n }\n if (expr === 'null') {\n return { type: 'literal', value: null }\n }\n\n // Handle string literals (double quotes)\n if (expr.startsWith('\"') && expr.endsWith('\"')) {\n return { type: 'literal', value: expr.slice(1, -1) }\n }\n\n // Handle string literals (single quotes)\n if (expr.startsWith(\"'\") && expr.endsWith(\"'\")) {\n return { type: 'literal', value: expr.slice(1, -1) }\n }\n\n // Handle number literals\n if (/^-?\\d+(\\.\\d+)?$/.test(expr)) {\n return { type: 'literal', value: parseFloat(expr) }\n }\n\n // Handle parenthesized expressions\n if (expr.startsWith('(') && expr.endsWith(')')) {\n // Check if parentheses are balanced for the entire expression\n let depth = 0\n let balanced = true\n\n for (let i = 0; i < expr.length; i++) {\n if (expr[i] === '(') {\n depth++\n } else if (expr[i] === ')') {\n depth--\n }\n\n // If depth hits 0 before the end, the outer parens aren't wrapping everything\n if (depth === 0 && i < expr.length - 1) {\n balanced = false\n break\n }\n }\n\n // If balanced, unwrap and recursively parse\n if (balanced && depth === 0) {\n return parseExpression(expr.slice(1, -1))\n }\n }\n\n // Handle logical NOT\n if (expr.startsWith('not ')) {\n return {\n type: 'unary',\n operator: 'not',\n operand: parseExpression(expr.substring(4))\n }\n }\n\n // Handle logical OR (lowest precedence)\n const orMatch = findOperator(expr, ' or ')\n if (orMatch !== -1) {\n return {\n type: 'binary',\n operator: 'or',\n left: parseExpression(expr.substring(0, orMatch)),\n right: parseExpression(expr.substring(orMatch + 4))\n }\n }\n\n // Handle logical AND\n const andMatch = findOperator(expr, ' and ')\n if (andMatch !== -1) {\n return {\n type: 'binary',\n operator: 'and',\n left: parseExpression(expr.substring(0, andMatch)),\n right: parseExpression(expr.substring(andMatch + 5))\n }\n }\n\n // Handle comparison operators\n const comparisonOps = ['==', '!=', '<=', '>=', '<', '>']\n for (const op of comparisonOps) {\n const opMatch = findOperator(expr, ` ${op} `)\n if (opMatch !== -1) {\n return {\n type: 'binary',\n operator: op as '==' | '!=' | '<' | '>' | '<=' | '>=',\n left: parseExpression(expr.substring(0, opMatch)),\n right: parseExpression(expr.substring(opMatch + op.length + 2))\n }\n }\n }\n\n // Handle simple variable lookup (with dot notation).\n // Hyphens are allowed in identifiers so AsciiDoc-style attribute\n // names (`product-version`, `ptp-events-rest-api`) work inside\n // `{% if %}` conditions \u2014 they resolve via `hyphenToUnderscore` in\n // Context.get, just like `{{ product-version }}` interpolations.\n // Minja has no subtraction operator, so a `-` is never ambiguous\n // here; negative number literals are matched earlier.\n if (/^[\\w.-]+$/.test(expr)) {\n return { type: 'variable', name: expr }\n }\n\n // If we can't parse it, throw an error\n throw new Error(`Invalid expression: ${expr}`)\n}\n\n/**\n * Find the position of an operator, respecting string literals\n * @param expr - Expression string\n * @param operator - Operator to find\n * @returns Position of operator or -1 if not found\n */\nfunction findOperator(expr: string, operator: string): number {\n let inString: string | null = null\n let depth = 0\n\n for (let i = 0; i < expr.length; i++) {\n const char = expr[i]\n\n // Track string literals\n if ((char === '\"' || char === \"'\") && (i === 0 || expr[i - 1] !== '\\\\')) {\n if (inString === char) {\n inString = null\n } else if (inString === null) {\n inString = char\n }\n continue\n }\n\n // Track parentheses depth\n if (!inString) {\n if (char === '(') {\n depth++\n } else if (char === ')') {\n depth--\n }\n }\n\n // Look for operator at depth 0, outside strings\n if (!inString && depth === 0) {\n if (expr.substring(i, i + operator.length) === operator) {\n return i\n }\n }\n }\n\n return -1\n}\n\n/**\n * Evaluate an expression in a given context\n * @param expr - Expression to evaluate\n * @param context - Variable context\n * @returns Evaluated value\n */\nexport function evaluateExpression(expr: Expression, context: IContext): unknown {\n switch (expr.type) {\n case 'literal':\n return expr.value\n\n case 'variable':\n return context.get(expr.name)\n\n case 'binary': {\n const left = evaluateExpression(expr.left, context)\n const right = evaluateExpression(expr.right, context)\n\n switch (expr.operator) {\n case '==':\n // eslint-disable-next-line eqeqeq\n return left == right\n case '!=':\n // eslint-disable-next-line eqeqeq\n return left != right\n case '<':\n return (left as number) < (right as number)\n case '>':\n return (left as number) > (right as number)\n case '<=':\n return (left as number) <= (right as number)\n case '>=':\n return (left as number) >= (right as number)\n case 'and':\n return isTruthy(left) && isTruthy(right)\n case 'or':\n return isTruthy(left) || isTruthy(right)\n }\n break\n }\n\n case 'unary': {\n const operand = evaluateExpression(expr.operand, context)\n\n switch (expr.operator) {\n case 'not':\n return !isTruthy(operand)\n }\n break\n }\n }\n\n return undefined\n}\n\n/**\n * Determine if a value is truthy in template context\n * @param value - Value to check\n * @returns true if truthy\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === undefined || value === null || value === false) {\n return false\n }\n if (value === 0 || value === '') {\n return false\n }\n return true\n}\n", "/**\n * Template parser\n * Converts template strings into AST (Abstract Syntax Tree)\n */\n\nimport type { ASTNode, ParseResult, ParseError } from './types.js'\nimport { parseExpression } from './evaluator.js'\n\n/**\n * Statement keywords the parser understands. Openers dispatch below; the\n * end/branch keywords are consumed by their opening tags (stray ones are\n * ignored, matching historical behavior). Anything OUTSIDE this set is an\n * unknown statement and is preserved verbatim in the output \u2014 silently\n * deleting author content is never acceptable.\n */\nconst KNOWN_TAG_KEYWORDS = new Set([\n 'set',\n 'if',\n 'include',\n 'switch',\n 'leveloffset',\n 'raw',\n 'endif',\n 'elif',\n 'else',\n 'endswitch',\n 'case',\n 'endleveloffset',\n 'endraw',\n])\n\n/**\n * Parse a template string into an AST\n * @param template - Template string to parse\n * @returns Parse result with AST and errors\n */\n/**\n * Apply a closing tag's LEFT whitespace-control marker to the body it closes.\n *\n * `{%- endif %}` must strip the whitespace before it \u2014 including the newline \u2014\n * exactly as `{%-` does on an opening tag. Block bodies are extracted by\n * matching the end tag textually (`/{%-?\\s*endif\\s*-?%}/`), and the `-?` was\n * matched but never acted on, so the body kept its trailing newline. Combined\n * with the newline that follows the tag, an AsciiDoc conditional written\n * inline in a paragraph \u2014\n *\n * Welcome to the official {{ product_title }}\n * {%- if not openshift_rosa %}\n * {{ product_version }}\n * {%- endif %}\n * documentation, where you can learn\u2026\n *\n * \u2014 rendered a BLANK line after the version, splitting one sentence into two\n * paragraphs mid-clause. Jinja2 produces no blank line here.\n */\nfunction stripBodyForEndTag (body: string, endTag: string): string {\n return endTag.startsWith('{%-') ? body.replace(/[ \\t]*\\n[ \\t\\n]*$/, '') : body\n}\n\nexport function parse(template: string): ParseResult {\n const errors: ParseError[] = []\n const ast: ASTNode[] = []\n\n let position = 0\n let line = 1\n let column = 1\n\n /**\n * Create a parse error\n */\n function createError(message: string): ParseError {\n return { message, position, line, column }\n }\n\n /**\n * Advance position tracking\n */\n function advance(count: number): void {\n for (let i = 0; i < count; i++) {\n if (template[position + i] === '\\n') {\n line++\n column = 1\n } else {\n column++\n }\n }\n position += count\n }\n\n /**\n * Find the next occurrence of a string\n */\n function findNext(str: string, from: number = position): number {\n return template.indexOf(str, from)\n }\n\n /**\n * Extract text between current position and a target position\n */\n function extractTo(target: number): string {\n const text = template.substring(position, target)\n advance(target - position)\n return text\n }\n\n while (position < template.length) {\n // Look for template tags\n const varStart = findNext('{{', position)\n const tagStart = findNext('{%', position)\n const commentStart = findNext('{#', position)\n\n // Find the nearest tag\n const candidates = [\n { pos: varStart, type: 'var' },\n { pos: tagStart, type: 'tag' },\n { pos: commentStart, type: 'comment' },\n ].filter((c) => c.pos !== -1)\n\n if (candidates.length === 0) {\n // No more tags, rest is text\n const text = template.substring(position)\n if (text) {\n ast.push({ type: 'text', value: text })\n }\n break\n }\n\n // Sort to find nearest\n candidates.sort((a, b) => a.pos - b.pos)\n const nearest = candidates[0]\n\n // Add text before tag\n if (nearest.pos > position) {\n ast.push({ type: 'text', value: extractTo(nearest.pos) })\n }\n\n // Parse the tag\n if (nearest.type === 'var') {\n // Variable: {{ name }}\n advance(2) // Skip {{\n const endPos = findNext('}}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed variable tag'))\n break\n }\n\n const varName = extractTo(endPos).trim()\n advance(2) // Skip }}\n\n ast.push({ type: 'variable', name: varName })\n } else if (nearest.type === 'comment') {\n // Comment: {# ... #}\n // Auto-strip newlines for comments (they produce no output)\n // Only strip if the comment is on its own line\n if (ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n // Only strip if previous text ends with newline (comment is on its own line)\n if (/\\n[ \\t]*$/.test(lastNode.value)) {\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t]*$/, '')\n }\n }\n\n advance(2) // Skip {#\n const endPos = findNext('#}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed comment tag'))\n break\n }\n\n const commentText = extractTo(endPos)\n advance(2) // Skip #}\n\n ast.push({ type: 'comment', value: commentText })\n\n // Auto-strip following newline if comment is on its own line\n if (position < template.length && template[position] === '\\n') {\n advance(1)\n // Also skip any indentation on the next line\n while (position < template.length && /[ \\t]/.test(template[position])) {\n advance(1)\n }\n }\n } else if (nearest.type === 'tag') {\n // Statement tag: {% ... %}\n const tagStart = position\n advance(2) // Skip {%\n const endPos = findNext('%}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed statement tag'))\n break\n }\n\n // Peek the keyword BEFORE whitespace-control processing, so raw\n // blocks and unknown tags are handled without side effects.\n const peeked = template.substring(position, endPos).trim()\n const peekKeyword =\n peeked.replace(/^-\\s*/, '').replace(/\\s*-$/, '').split(/\\s+/)[0] ?? ''\n\n if (peekKeyword === 'raw') {\n // {% raw %} ... {% endraw %} \u2014 Jinja semantics: everything between\n // the markers passes through COMPLETELY unevaluated; the markers\n // themselves produce no output. Whitespace-control markers are\n // honored on both tags.\n const openerLeftStrip = peeked.startsWith('-')\n const openerRightStrip = peeked.endsWith('-')\n if (openerLeftStrip && ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n extractTo(endPos)\n advance(2) // Skip %}\n if (openerRightStrip) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n const endrawMatch = /\\{%-?\\s*endraw\\s*-?%\\}/.exec(template.substring(position))\n if (!endrawMatch) {\n errors.push(createError('Unclosed raw block'))\n break\n }\n const endrawAbs = position + endrawMatch.index\n let content = extractTo(endrawAbs)\n const endrawTag = endrawMatch[0]\n if (endrawTag.startsWith('{%-')) {\n content = content.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n advance(endrawTag.length)\n if (endrawTag.endsWith('-%}')) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n if (content) {\n ast.push({ type: 'text', value: content })\n }\n continue\n }\n\n if (!KNOWN_TAG_KEYWORDS.has(peekKeyword)) {\n // Unknown statement: preserve the tag verbatim (it was previously\n // silently dropped). No whitespace control is applied \u2014 the bytes\n // pass through exactly as authored.\n extractTo(endPos)\n advance(2) // Skip %}\n ast.push({ type: 'text', value: template.substring(tagStart, endPos + 2) })\n continue\n }\n\n let statement = extractTo(endPos).trim()\n\n // Check for whitespace control characters\n const hasLeftStrip = statement.startsWith('-')\n const hasRightStrip = statement.endsWith('-')\n\n // Strip whitespace control characters from statement\n if (hasLeftStrip) {\n statement = statement.substring(1).trim()\n // Strip trailing whitespace from previous text node\n if (ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n }\n if (hasRightStrip) {\n statement = statement.substring(0, statement.length - 1).trim()\n }\n\n advance(2) // Skip %}\n\n // If right strip, consume following whitespace\n if (hasRightStrip) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n\n // Parse different statement types\n if (statement.startsWith('set ')) {\n // {% set var = value %}\n const setMatch = /^set\\s+(\\w+)\\s*=\\s*(.+)$/.exec(statement)\n if (setMatch) {\n try {\n const expr = parseExpression(setMatch[2])\n\n ast.push({\n type: 'set',\n name: setMatch[1],\n value: expr,\n })\n } catch (error) {\n errors.push(createError(`Invalid set expression: ${(error as Error).message}`))\n }\n } else {\n errors.push(createError('Invalid set syntax'))\n }\n } else if (statement.startsWith('if ')) {\n // {% if condition %} ... {% elif %} ... {% else %} ... {% endif %}\n const condition = statement.substring(3).trim()\n\n try {\n const expr = parseExpression(condition)\n\n // Find the body and elif/else/endif blocks\n const { trueBranch, elifBranches, elseBranch, parseErrors } = parseIfBlock()\n errors.push(...parseErrors)\n\n ast.push({\n type: 'if',\n condition: expr,\n trueBranch,\n elifBranches: elifBranches.length > 0 ? elifBranches : undefined,\n elseBranch: elseBranch.length > 0 ? elseBranch : undefined,\n })\n } catch (error) {\n errors.push(createError(`Invalid if expression: ${(error as Error).message}`))\n }\n } else if (statement.startsWith('include ')) {\n // {% include \"path\" %}\n const includeMatch = /^include\\s+[\"']([^\"']+)[\"']/.exec(statement)\n if (includeMatch) {\n ast.push({\n type: 'include',\n path: includeMatch[1],\n })\n } else {\n errors.push(createError('Invalid include syntax'))\n }\n } else if (statement.startsWith('switch ')) {\n // {% switch variable %} ... {% case \"value\" %} ... {% endswitch %}\n const switchExpr = statement.substring(7).trim()\n\n try {\n const expr = parseExpression(switchExpr)\n const { cases, parseErrors } = parseSwitchBlock()\n errors.push(...parseErrors)\n\n ast.push({\n type: 'switch',\n expression: expr,\n cases,\n })\n } catch (error) {\n errors.push(createError(`Invalid switch expression: ${(error as Error).message}`))\n }\n } else if (statement.startsWith('leveloffset ')) {\n // {% leveloffset +1 %} or {% leveloffset 2 %} or {% leveloffset -1 %}\n const offsetMatch = /^leveloffset\\s+([-+]?\\d+)$/.exec(statement)\n\n if (!offsetMatch) {\n errors.push(createError('Invalid leveloffset syntax'))\n } else {\n const offsetStr = offsetMatch[1]\n const isRelative = offsetStr.startsWith('+') || offsetStr.startsWith('-')\n const offset = parseInt(offsetStr, 10)\n\n if (isNaN(offset)) {\n errors.push(createError('Invalid leveloffset value'))\n } else {\n // Find matching endleveloffset accounting for nesting\n let depth = 0\n let searchPos = position\n let endPos = -1\n\n while (searchPos < template.length) {\n const leveloffsetMatch = /{%-?\\s*leveloffset\\s+[-+]?\\d+\\s*-?%}/.exec(template.substring(searchPos))\n const endleveloffsetMatch = /{%-?\\s*endleveloffset\\s*-?%}/.exec(template.substring(searchPos))\n\n const leveloffsetPos = leveloffsetMatch ? searchPos + leveloffsetMatch.index : Infinity\n const endleveloffsetPos = endleveloffsetMatch ? searchPos + endleveloffsetMatch.index : Infinity\n\n if (leveloffsetPos < endleveloffsetPos) {\n // Found nested leveloffset\n depth++\n searchPos = leveloffsetPos + (leveloffsetMatch?.[0].length || 0)\n } else if (endleveloffsetPos < Infinity) {\n // Found endleveloffset\n if (depth === 0) {\n // This is our matching endleveloffset\n endPos = endleveloffsetPos\n break\n } else {\n depth--\n searchPos = endleveloffsetPos + (endleveloffsetMatch?.[0].length || 0)\n }\n } else {\n // No more tags found\n break\n }\n }\n\n if (endPos === -1) {\n errors.push(createError('Missing endleveloffset'))\n } else {\n const bodyTemplate = extractTo(endPos)\n // Find and skip the endleveloffset tag\n const endMatch = /{%-?\\s*endleveloffset\\s*-?%}/.exec(template.substring(position))\n if (endMatch) {\n advance(endMatch[0].length)\n }\n\n const bodyResult = parse(bodyTemplate)\n errors.push(...bodyResult.errors)\n\n ast.push({\n type: 'leveloffset',\n offset,\n isRelative,\n body: bodyResult.ast,\n })\n }\n }\n }\n }\n // Ignore endif, endswitch, case, endleveloffset, etc. - they're handled by their opening tags\n }\n }\n\n return { ast, errors }\n\n /**\n * Find an end tag like {% endif %}\n */\n function findEndTag(tagName: string): { start: number; length: number; tag: string } | null {\n // `-?` on BOTH sides: without it this could not match `{%- endif %}`, so an\n // `{% else %}` branch closed with a whitespace-controlled endif failed to\n // parse at all \u2014 the page threw \"Missing endif after else\" and the build\n // preprocessor copied it through UNRENDERED, variables and directives and\n // all. Three OpenShift pages were shipping that way.\n const pattern = new RegExp(`{%-?\\\\s*${tagName}\\\\s*-?%}`)\n const match = pattern.exec(template.substring(position))\n\n if (match) {\n return {\n start: position + match.index,\n length: match[0].length,\n tag: match[0],\n }\n }\n\n return null\n }\n\n /**\n * Parse an if block with elif and else support\n */\n function parseIfBlock(): {\n trueBranch: ASTNode[]\n elifBranches: Array<{ condition: import('./types.js').Expression; body: ASTNode[] }>\n elseBranch: ASTNode[]\n parseErrors: ParseError[]\n } {\n const elifBranches: Array<{ condition: import('./types.js').Expression; body: ASTNode[] }> = []\n const parseErrors: ParseError[] = []\n let elseBranch: ASTNode[] = []\n\n // Find the next elif, else, or endif\n let depth = 0\n let searchPos = position\n\n while (searchPos < template.length) {\n const ifMatch = /{%-?\\s*if\\s+/.exec(template.substring(searchPos))\n const elifMatch = /{%-?\\s*elif\\s+/.exec(template.substring(searchPos))\n const elseMatch = /{%-?\\s*else\\s*-?%}/.exec(template.substring(searchPos))\n const endifMatch = /{%-?\\s*endif\\s*-?%}/.exec(template.substring(searchPos))\n\n // Find the nearest match\n const matches = [\n { type: 'if', match: ifMatch, pos: ifMatch ? searchPos + ifMatch.index : Infinity },\n { type: 'elif', match: elifMatch, pos: elifMatch ? searchPos + elifMatch.index : Infinity },\n { type: 'else', match: elseMatch, pos: elseMatch ? searchPos + elseMatch.index : Infinity },\n { type: 'endif', match: endifMatch, pos: endifMatch ? searchPos + endifMatch.index : Infinity },\n ].sort((a, b) => a.pos - b.pos)\n\n const nearest = matches[0]\n\n if (!nearest.match || nearest.pos === Infinity) {\n parseErrors.push(createError('Missing endif'))\n break\n }\n\n if (nearest.type === 'if') {\n depth++\n searchPos = nearest.pos + nearest.match[0].length\n } else if (nearest.type === 'endif') {\n if (depth === 0) {\n // This is our endif\n const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0])\n advance(nearest.match[0].length)\n if (nearest.match[0].endsWith('-%}')) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) advance(1)\n }\n\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n\n return {\n trueBranch: bodyResult.ast,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n } else {\n depth--\n searchPos = nearest.pos + nearest.match[0].length\n }\n } else if (depth === 0 && (nearest.type === 'elif' || nearest.type === 'else')) {\n // Parse the body before elif/else\n const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0])\n const bodyResult = parse(bodyTemplate)\n\n if (elifBranches.length === 0 && elseBranch.length === 0) {\n // This is the trueBranch (before first elif/else)\n parseErrors.push(...bodyResult.errors)\n const trueBranch = bodyResult.ast\n\n // Now handle elif or else\n if (nearest.type === 'elif') {\n // Extract elif condition\n advance(nearest.match[0].length)\n const condMatch = /^([^%]+)%}/.exec(template.substring(position))\n if (condMatch) {\n const condStr = condMatch[1].trim()\n advance(condMatch[0].length)\n\n try {\n const elifCondition = parseExpression(condStr)\n const elifResult = parseIfBlock()\n parseErrors.push(...elifResult.parseErrors)\n\n elifBranches.push({\n condition: elifCondition,\n body: elifResult.trueBranch,\n })\n elifBranches.push(...(elifResult.elifBranches || []))\n elseBranch = elifResult.elseBranch\n\n return {\n trueBranch,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n } catch (error) {\n parseErrors.push(createError(`Invalid elif expression: ${(error as Error).message}`))\n }\n }\n } else {\n // else\n advance(nearest.match[0].length)\n\n // Find endif for else block\n const endifMatch = findEndTag('endif')\n if (!endifMatch) {\n parseErrors.push(createError('Missing endif after else'))\n } else {\n const elseBodyTemplate = stripBodyForEndTag(\n extractTo(endifMatch.start),\n endifMatch.tag,\n )\n advance(endifMatch.length)\n\n const elseBodyResult = parse(elseBodyTemplate)\n parseErrors.push(...elseBodyResult.errors)\n elseBranch = elseBodyResult.ast\n }\n\n return {\n trueBranch,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n }\n }\n } else {\n searchPos = nearest.pos + nearest.match[0].length\n }\n }\n\n return {\n trueBranch: [],\n elifBranches,\n elseBranch,\n parseErrors,\n }\n }\n\n /**\n * Parse a switch block with case support\n */\n function parseSwitchBlock(): {\n cases: Array<{ value: import('./types.js').Expression; body: ASTNode[] }>\n parseErrors: ParseError[]\n } {\n const cases: Array<{ value: import('./types.js').Expression; body: ASTNode[] }> = []\n const parseErrors: ParseError[] = []\n\n while (position < template.length) {\n // Find the next case or endswitch\n const caseMatch = /{%-?\\s*case\\s+/.exec(template.substring(position))\n const endswitchMatch = /{%-?\\s*endswitch\\s*-?%}/.exec(template.substring(position))\n\n // Find which comes first\n const casePos = caseMatch ? position + caseMatch.index : Infinity\n const endswitchPos = endswitchMatch ? position + endswitchMatch.index : Infinity\n\n if (endswitchPos < casePos) {\n // Found endswitch before any case (or no case)\n // Parse any remaining content before endswitch as the last case body\n if (cases.length > 0 && position < endswitchPos) {\n const bodyTemplate = extractTo(endswitchPos)\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n cases[cases.length - 1].body = bodyResult.ast\n }\n\n // Skip endswitch\n advance(endswitchPos - position + (endswitchMatch?.[0].length || 0))\n break\n } else if (casePos < Infinity) {\n // Found a case\n // If there's a previous case, parse its body\n if (cases.length > 0 && position < casePos) {\n const bodyTemplate = extractTo(casePos)\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n cases[cases.length - 1].body = bodyResult.ast\n } else if (position < casePos) {\n // Content before first case - skip it\n extractTo(casePos)\n }\n\n // Parse the case value\n advance(caseMatch![0].length)\n\n // Extract the case value (until %})\n const valueMatch = /([^%]+)%}/.exec(template.substring(position))\n if (valueMatch) {\n const valueStr = valueMatch[1].trim()\n advance(valueMatch[0].length)\n\n try {\n const caseValue = parseExpression(valueStr)\n cases.push({\n value: caseValue,\n body: [], // Will be filled in next iteration or at endswitch\n })\n } catch (error) {\n parseErrors.push(createError(`Invalid case value: ${(error as Error).message}`))\n }\n } else {\n parseErrors.push(createError('Invalid case syntax'))\n break\n }\n } else {\n // No case or endswitch found\n parseErrors.push(createError('Missing endswitch'))\n break\n }\n }\n\n return { cases, parseErrors }\n }\n}\n", "/**\n * Context management for variable scoping\n * Supports nested scopes with inheritance\n */\n\nimport type { IContext } from './types.js'\n\nexport interface ContextOptions {\n /**\n * Convert hyphenated variable names to underscores during lookup.\n */\n hyphenToUnderscore?: boolean\n}\n\nexport class Context implements IContext {\n private variables: Map<string, unknown>\n private parent: Context | null\n private options: ContextOptions\n\n constructor(parent?: Context, options?: ContextOptions) {\n this.variables = new Map()\n this.parent = parent || null\n this.options = options || parent?.options || {}\n }\n\n /**\n * Get a variable from the context (supports dot notation)\n * @param name - Variable name (can use dot notation like \"obj.prop.subprop\")\n * @returns The variable value or undefined\n */\n get(name: string): unknown {\n // Convert hyphens to underscores if option is enabled\n const normalizedName = this.options.hyphenToUnderscore\n ? name.replace(/-/g, '_')\n : name\n\n const parts = normalizedName.split('.')\n const rootName = parts[0]\n\n // Look up the root variable in current scope or parent scopes\n let value: unknown\n if (this.variables.has(rootName)) {\n value = this.variables.get(rootName)\n } else if (this.parent) {\n value = this.parent.get(rootName)\n } else {\n return undefined\n }\n\n // Navigate nested properties\n for (let i = 1; i < parts.length; i++) {\n if (value === null || value === undefined) {\n return undefined\n }\n\n // Only allow property access on plain objects (prevent prototype pollution)\n if (typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n\n // Prevent access to prototype chain\n if (!Object.prototype.hasOwnProperty.call(value, parts[i])) {\n return undefined\n }\n\n value = (value as Record<string, unknown>)[parts[i]]\n }\n\n return value\n }\n\n /**\n * Set a variable in the current context\n * @param name - Variable name (can use dot notation)\n * @param value - Value to set\n */\n set(name: string, value: unknown): void {\n const parts = name.split('.')\n\n if (parts.length === 1) {\n // Simple assignment\n this.variables.set(name, value)\n return\n }\n\n // Nested assignment - navigate to parent object\n const rootName = parts[0]\n let target = this.variables.get(rootName) as Record<string, unknown> | undefined\n\n if (!target || typeof target !== 'object' || Array.isArray(target)) {\n // Create new object if root doesn't exist or isn't an object\n target = {}\n this.variables.set(rootName, target)\n }\n\n // Navigate to the parent of the target property\n for (let i = 1; i < parts.length - 1; i++) {\n const key = parts[i]\n\n if (\n !target[key] ||\n typeof target[key] !== 'object' ||\n Array.isArray(target[key])\n ) {\n target[key] = {}\n }\n\n target = target[key] as Record<string, unknown>\n }\n\n // Set the final property\n target[parts[parts.length - 1]] = value\n }\n\n /**\n * Create a child scope\n * @returns A new Context with this context as parent\n */\n push(): Context {\n return new Context(this, this.options)\n }\n\n /**\n * Return to parent scope\n * @returns The parent context or null if at root\n */\n pop(): Context | null {\n return this.parent\n }\n\n /**\n * Create a context from a plain object\n * @param data - Plain object to convert to context\n * @param options - Context options\n * @returns New Context instance\n */\n static from(data: Record<string, unknown>, options?: ContextOptions): Context {\n const ctx = new Context(undefined, options)\n for (const [key, value] of Object.entries(data)) {\n ctx.set(key, value)\n }\n return ctx\n }\n}\n", "/**\n * Fetch-based loader for browsers and service workers\n */\n\nimport type { Loader } from './types.js'\n\nexport class FetchLoader implements Loader {\n async load(path: string, basePath?: string): Promise<string> {\n const url = basePath ? new URL(path, basePath).href : path\n const fetchUrl = `${url}?preventCache=${Date.now()}`\n\n const response = await fetch(fetchUrl)\n\n if (!response.ok) {\n throw new Error(`Failed to load ${url}: ${response.status} ${response.statusText}`)\n }\n\n return await response.text()\n }\n}\n", "/**\n * Template renderer\n * Combines parser, evaluator, and loader to render templates\n */\n\nimport type { ASTNode, Expression, RenderOptions, Loader } from './types.js'\nimport { parse } from './parser.js'\nimport { Context } from './context.js'\nimport { evaluateExpression } from './evaluator.js'\nimport { FetchLoader } from './loader-fetch.js'\n\n/**\n * Transform markdown headings by applying level offset\n * Clamps to valid markdown range (1-6)\n * @param text - Text content to transform\n * @param offset - Level offset to apply\n * @returns Transformed text with adjusted heading levels\n */\nfunction transformHeadings(\n text: string,\n offset: number,\n initialFence: string | null = null,\n fenceOut?: { fence: string | null },\n): string {\n if (offset === 0) {\n if (fenceOut) fenceOut.fence = initialFence\n return text\n }\n\n // Fence-aware: only shift ATX headings that are NOT inside a fenced code\n // block. A line-anchored regex would otherwise rewrite `# oc get pods`\n // (a shell prompt / comment) inside a ```terminal block to `## \u2026`,\n // mutating code-block content \u2014 which the no-code-block-mutation rule\n // forbids. Issue #020 / task #404.\n const lines = text.split('\\n')\n // Fence state CARRIES ACROSS text nodes: a directive inside a listing\n // splits the template into several text nodes, and restarting the state\n // per node lost the open fence \u2014 `#` comments at column 0 inside the\n // second half were shifted to `###` (issue #043, managing-ce's\n // ClusterRole manifest; the same class as issue #020).\n let fence: string | null = initialFence // active opening fence run (e.g. \"```\") while inside a code block\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n const fenceMatch = line.match(/^\\s*(`{3,}|~{3,})/)\n if (fenceMatch) {\n const run = fenceMatch[1]\n if (fence === null) {\n // Opening fence (an info string may follow on this line).\n fence = run\n } else if (run[0] === fence[0] && run.length >= fence.length && line.trim() === run) {\n // Closing fence: bare marker, same char, length >= opening (CommonMark).\n fence = null\n }\n continue // never treat a fence line as a heading\n }\n if (fence !== null) {\n continue // inside a code block \u2014 leave the line verbatim\n }\n const m = line.match(/^(#{1,6})(\\s+)/)\n if (m) {\n const newLevel = Math.max(1, Math.min(6, m[1].length + offset))\n lines[i] = '#'.repeat(newLevel) + line.slice(m[1].length)\n }\n }\n if (fenceOut) fenceOut.fence = fence\n return lines.join('\\n')\n}\n\n/**\n * Resolve a relative path against a base path\n * @param path - Relative or absolute path\n * @param basePath - Base path to resolve against\n * @returns Resolved path\n */\nfunction resolvePath(path: string, basePath: string): string {\n // If path is absolute, return as-is\n if (path.startsWith('/')) {\n return path\n }\n\n // Ensure basePath ends with /\n const base = basePath.endsWith('/') ? basePath : basePath + '/'\n\n // Combine and normalize\n const combined = base + path\n\n // Normalize . and .. segments\n const parts = combined.split('/')\n const resolved: string[] = []\n\n for (const part of parts) {\n if (part === '.' || part === '') {\n continue\n } else if (part === '..') {\n resolved.pop()\n } else {\n resolved.push(part)\n }\n }\n\n // Preserve leading slash if original had one\n const prefix = combined.startsWith('/') ? '/' : ''\n return prefix + resolved.join('/')\n}\n\n/**\n * Render a template string\n * @param template - Template string to render\n * @param options - Render options\n * @returns Rendered output\n */\nexport async function render(template: string, options: RenderOptions = {}): Promise<string> {\n const {\n loader = new FetchLoader(),\n context: initialContext = {},\n basePath = '',\n maxIncludeDepth = 10,\n timeout = 5000,\n hyphenToUnderscore = false,\n undefinedBehavior = 'empty',\n undefinedConditions = 'preserve',\n } = options\n\n // Create timeout promise\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error('Template rendering timeout')), timeout)\n })\n\n // Render with timeout\n const renderPromise = renderInternal(template, {\n loader,\n context: Context.from(\n {\n ...initialContext,\n // Built-in variables\n date: new Date().toISOString().split('T')[0],\n timestamp: Date.now(),\n _levelOffset: 0,\n },\n { hyphenToUnderscore }\n ),\n includeDepth: 0,\n maxIncludeDepth,\n basePath,\n undefinedBehavior,\n undefinedConditions,\n })\n\n return await Promise.race([renderPromise, timeoutPromise])\n}\n\ninterface InternalRenderOptions {\n loader: Loader\n context: Context\n includeDepth: number\n maxIncludeDepth: number\n basePath: string\n undefinedBehavior: 'empty' | 'throw' | 'preserve' | 'asciidoc-literal'\n undefinedConditions: 'preserve' | 'falsy'\n}\n\n/**\n * Internal rendering function with depth tracking\n */\nasync function renderInternal(\n template: string,\n options: InternalRenderOptions\n): Promise<string> {\n const { includeDepth, maxIncludeDepth } = options\n\n // Check recursion depth\n if (includeDepth > maxIncludeDepth) {\n throw new Error(`Maximum include depth (${maxIncludeDepth}) exceeded`)\n }\n\n // Parse template\n const parseResult = parse(template)\n\n if (parseResult.errors.length > 0) {\n const errorMessages = parseResult.errors.map((e) => e.message).join(', ')\n throw new Error(`Parse errors: ${errorMessages}`)\n }\n\n // Render AST\n return await renderNodes(parseResult.ast, options)\n}\n\n/**\n * Render an array of AST nodes\n */\nasync function renderNodes(nodes: ASTNode[], options: InternalRenderOptions): Promise<string> {\n const parts: string[] = []\n\n for (const node of nodes) {\n let rendered = await renderNode(node, options)\n // An {% include %} that sits alone on an INDENTED line splices content\n // into that indentation context (a list item, an open block in a step):\n // re-indent every non-empty spliced line to the directive's own column.\n // Verbatim splicing put included bullets/fences at column 0 inside a\n // level-2 step, shattering the list and orphaning everything after\n // (the \":::important in a code block\" class, cnf-image-based-upgrade).\n // Top-level includes have no leading indent and are untouched.\n if (node.type === 'include' && rendered && parts.length > 0) {\n const tail = /(?:^|\\n)([ \\t]+)$/.exec(parts[parts.length - 1])\n if (tail) {\n rendered = rendered.replace(/\\n(?=[^\\n])/g, '\\n' + tail[1])\n }\n }\n parts.push(rendered)\n }\n\n return parts.join('')\n}\n\n/**\n * Render a single AST node\n */\nasync function renderNode(node: ASTNode, options: InternalRenderOptions): Promise<string> {\n const { loader, context, includeDepth, maxIncludeDepth, basePath } = options\n\n switch (node.type) {\n case 'text': {\n // Apply leveloffset if active\n const currentOffset = context.get('_levelOffset') as number || 0\n if (currentOffset === 0) {\n return node.value\n }\n const fenceOut = { fence: null as string | null }\n const out = transformHeadings(\n node.value,\n currentOffset,\n (context.get('_levelOffsetFence') as string | null) ?? null,\n fenceOut,\n )\n context.set('_levelOffsetFence', fenceOut.fence)\n return out\n }\n\n case 'variable': {\n const value = context.get(node.name)\n if (value === undefined || value === null) {\n // Apply the undefined-variable policy. See RenderOptions.undefinedBehavior.\n switch (options.undefinedBehavior) {\n case 'throw':\n throw new Error(`Undefined variable: ${node.name}`)\n case 'preserve':\n // Round-trip the source form so downstream tooling (or a\n // second-pass minja run with the value supplied) can pick\n // up where we left off.\n return `{{ ${node.name} }}`\n case 'asciidoc-literal':\n // Terminal build of an AsciiDoc-migrated corpus: every ref\n // came from an `{name}` attribute reference, so an\n // unresolvable one is a literal placeholder \u2014 render what\n // asciidoctor renders for an undefined attribute.\n return `{${node.name}}`\n case 'empty':\n default:\n return ''\n }\n }\n const str = String(value)\n // If the value contains template syntax, re-process it\n if (str.includes('{{') || str.includes('{%')) {\n return await renderInternal(str, options)\n }\n return str\n }\n\n case 'set': {\n const value = evaluateExpression(node.value, context)\n context.set(node.name, value)\n return ''\n }\n\n case 'comment':\n return ''\n\n case 'if': {\n // In preserve mode, an `if` whose condition references an\n // undefined identifier can't be evaluated \u2014 we don't know\n // which branch to take. Preserve the whole `{% if \u2026 %}\u2026{% endif %}`\n // verbatim so a second pass (with the value supplied) can\n // resolve it. See plans/format-asciidoc-import.md.\n //\n // Except when `undefinedConditions === 'falsy'`: this is a\n // terminal build with no later pass, so treat the undefined\n // reference as falsy (AsciiDoc `ifdef::attr[]` semantics) and\n // evaluate now rather than leak the directive to readers.\n if ((options.undefinedBehavior === 'preserve' || options.undefinedBehavior === 'asciidoc-literal') && options.undefinedConditions !== 'falsy') {\n const undefinedRefs = findUndefinedRefs(node.condition, context)\n if (undefinedRefs.length > 0) {\n return ifNodeToSource(node)\n }\n if (node.elifBranches) {\n for (const elif of node.elifBranches) {\n if (findUndefinedRefs(elif.condition, context).length > 0) {\n return ifNodeToSource(node)\n }\n }\n }\n }\n\n const condition = evaluateExpression(node.condition, context)\n\n if (isTruthy(condition)) {\n return await renderNodes(node.trueBranch, options)\n }\n\n // Check elif branches\n if (node.elifBranches) {\n for (const elifBranch of node.elifBranches) {\n const elifCondition = evaluateExpression(elifBranch.condition, context)\n if (isTruthy(elifCondition)) {\n return await renderNodes(elifBranch.body, options)\n }\n }\n }\n\n // Render else branch if present\n if (node.elseBranch) {\n return await renderNodes(node.elseBranch, options)\n }\n\n return ''\n }\n\n case 'include': {\n try {\n // Load the included file\n const includedContent = await loader.load(node.path, basePath)\n\n // Determine new base path for nested includes\n let newBasePath = basePath\n\n // If path looks like a URL, extract base\n if (node.path.includes('://')) {\n const url = new URL(node.path)\n newBasePath = url.href.substring(0, url.href.lastIndexOf('/') + 1)\n } else if (basePath) {\n // Relative path - resolve against current base\n if (basePath.includes('://')) {\n const url = new URL(node.path, basePath)\n newBasePath = url.href.substring(0, url.href.lastIndexOf('/') + 1)\n } else {\n // File path - resolve relative to current base and extract directory\n const resolvedPath = resolvePath(node.path, basePath)\n const lastSlash = resolvedPath.lastIndexOf('/')\n newBasePath = lastSlash >= 0 ? resolvedPath.substring(0, lastSlash + 1) : basePath\n }\n } else if (node.path.includes('/')) {\n // No base path but include has directory - use that as base\n const lastSlash = node.path.lastIndexOf('/')\n newBasePath = node.path.substring(0, lastSlash + 1)\n }\n\n // Render the included template (recursive)\n return await renderInternal(includedContent, {\n loader,\n context,\n includeDepth: includeDepth + 1,\n maxIncludeDepth,\n basePath: newBasePath,\n undefinedBehavior: options.undefinedBehavior,\n undefinedConditions: options.undefinedConditions,\n })\n } catch (error) {\n // A containment refusal is a SECURITY event, not a missing file:\n // neither preserved for a later pass (no later pass may resolve\n // it) nor degraded to a comment \u2014 the render fails hard (#027).\n if (error instanceof Error && error.name === 'IncludeContainmentError') {\n throw error\n }\n // In `preserve` mode, an unresolvable include is preserved\n // as the original directive so a later renderer pass (with\n // the file in place) can resolve it. Matches the semantic\n // of `preserve` for undefined variables. Without this,\n // multi-stage pipelines (e.g. dogsbay's convert + build\n // preprocessor for AsciiDoc imports) lose the directive at\n // stage 1 because targets only exist after stage 2 has\n // converted sibling files.\n if (options.undefinedBehavior === 'preserve' || options.undefinedBehavior === 'asciidoc-literal') {\n return `{% include \"${node.path}\" %}`\n }\n const message = error instanceof Error ? error.message : String(error)\n console.error(`Failed to include ${node.path}:`, message)\n return `<!-- Include error: ${node.path} -->`\n }\n }\n\n case 'switch': {\n const switchValue = evaluateExpression(node.expression, context)\n\n // Find matching case\n for (const caseItem of node.cases) {\n const caseValue = evaluateExpression(caseItem.value, context)\n // eslint-disable-next-line eqeqeq\n if (switchValue == caseValue) {\n return await renderNodes(caseItem.body, options)\n }\n }\n\n // No matching case found\n return ''\n }\n\n case 'leveloffset': {\n // Calculate new offset (relative or absolute)\n const parentOffset = context.get('_levelOffset') as number || 0\n const newOffset = node.isRelative ? parentOffset + node.offset : node.offset\n\n // Store current offset to restore later\n const previousOffset = parentOffset\n\n // Set new offset in context\n context.set('_levelOffset', newOffset)\n // Fresh scope: a fence left open by unrelated earlier content must\n // not suppress heading shifts here. Save the outer state so a NESTED\n // leveloffset sitting inside an open fence doesn't wipe it \u2014 without\n // the restore, the outer fence's real closer was later mis-read as an\n // opener, flipping fence state for the rest of the render.\n const previousFence = context.get('_levelOffsetFence') ?? null\n context.set('_levelOffsetFence', null)\n\n try {\n // Render body with offset active\n const result = await renderNodes(node.body, options)\n return result\n } finally {\n // Always restore previous offset + the outer fence state\n context.set('_levelOffset', previousOffset)\n context.set('_levelOffsetFence', previousFence)\n }\n }\n\n default:\n // TypeScript exhaustiveness check\n const _exhaustive: never = node\n return _exhaustive\n }\n}\n\n/**\n * Determine if a value is truthy\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === undefined || value === null || value === false) {\n return false\n }\n if (value === 0 || value === '') {\n return false\n }\n return true\n}\n\n// ============================================================================\n// Preserve-mode helpers \u2014 round-trip AST back to Jinja source so an\n// undefined-referencing block can survive into the rendered output for\n// a downstream pass to resolve.\n// ============================================================================\n\n/**\n * Walk an expression AST, return the names of any `variable` references\n * whose context lookup is undefined. Empty array = all refs are bound.\n */\nfunction findUndefinedRefs(expr: Expression, context: Context): string[] {\n const out: string[] = []\n function walk(e: Expression): void {\n switch (e.type) {\n case 'variable':\n if (context.get(e.name) === undefined) out.push(e.name)\n break\n case 'binary':\n walk(e.left)\n walk(e.right)\n break\n case 'unary':\n walk(e.operand)\n break\n case 'literal':\n break\n }\n }\n walk(expr)\n return out\n}\n\n/**\n * Serialize an Expression back to Jinja source. Used by preserve mode\n * to reconstruct `{% if \u2026 %}` headers when the condition can't be\n * evaluated. Operator precedence isn't tracked; the output is\n * conservatively parenthesized for binary/unary so a re-parse round-\n * trips to the same AST shape (modulo redundant parens).\n */\nfunction expressionToSource(expr: Expression): string {\n switch (expr.type) {\n case 'literal':\n if (typeof expr.value === 'string') return JSON.stringify(expr.value)\n if (expr.value === null) return 'null'\n return String(expr.value)\n case 'variable':\n return expr.name\n case 'unary':\n return `not ${expressionToSource(expr.operand)}`\n case 'binary':\n return `(${expressionToSource(expr.left)} ${expr.operator} ${expressionToSource(expr.right)})`\n }\n}\n\n/**\n * Serialize ASTNode[] back to Jinja source. Mirrors the parser's syntax\n * for every node type so a preserved block can be re-rendered later\n * with the missing values supplied.\n *\n * Throws on shapes we don't support (deep nested includes, switch);\n * preserve mode is opt-in and a hard error here beats silent\n * truncation. The shapes covered are everything md2md emits in the\n * AsciiDoc pipeline.\n */\nfunction nodesToSource(nodes: ASTNode[]): string {\n return nodes.map(nodeToSource).join('')\n}\n\nfunction nodeToSource(node: ASTNode): string {\n switch (node.type) {\n case 'text':\n return node.value\n case 'variable':\n return `{{ ${node.name} }}`\n case 'set':\n return `{% set ${node.name} = ${expressionToSource(node.value)} %}`\n case 'comment':\n // Parser strips comment content; emit a placeholder so the block\n // structure round-trips even when the prose inside doesn't.\n return '{# \u2026 #}'\n case 'if':\n return ifNodeToSource(node)\n case 'include':\n return `{% include \"${node.path}\" %}`\n case 'leveloffset': {\n const sign = node.isRelative && node.offset >= 0 ? '+' : ''\n return `{% leveloffset ${sign}${node.offset} %}${nodesToSource(node.body)}{% endleveloffset %}`\n }\n case 'switch': {\n // Conservative round-trip; switch isn't on the AsciiDoc hot path\n // but we have an AST shape, so emit it.\n const cases = node.cases\n .map((c) => `{% case ${expressionToSource(c.value)} %}${nodesToSource(c.body)}`)\n .join('')\n return `{% switch ${expressionToSource(node.expression)} %}${cases}{% endswitch %}`\n }\n }\n}\n\nfunction ifNodeToSource(node: Extract<ASTNode, { type: 'if' }>): string {\n const parts = [`{% if ${expressionToSource(node.condition)} %}`, nodesToSource(node.trueBranch)]\n if (node.elifBranches) {\n for (const elif of node.elifBranches) {\n parts.push(`{% elif ${expressionToSource(elif.condition)} %}`, nodesToSource(elif.body))\n }\n }\n if (node.elseBranch) {\n parts.push(`{% else %}`, nodesToSource(node.elseBranch))\n }\n parts.push(`{% endif %}`)\n return parts.join('')\n}\n", "/**\n * Memory-based loader for testing\n */\n\nimport type { Loader } from './types.js'\n\nexport class MemoryLoader implements Loader {\n private files: Map<string, string>\n\n constructor(files: Record<string, string> = {}) {\n this.files = new Map(Object.entries(files))\n }\n\n addFile(path: string, content: string): void {\n this.files.set(path, content)\n }\n\n async load(path: string, basePath?: string): Promise<string> {\n // Resolve path with normalization of . and .. segments\n const combined = basePath && !path.startsWith('/')\n ? `${basePath}/${path}`\n : path\n\n const parts = combined.split('/')\n const normalized: string[] = []\n for (const part of parts) {\n if (part === '.' || part === '') continue\n if (part === '..') { normalized.pop(); continue }\n normalized.push(part)\n }\n const prefix = combined.startsWith('/') ? '/' : ''\n const resolvedPath = prefix + normalized.join('/')\n\n const content = this.files.get(resolvedPath)\n\n if (content === undefined) {\n throw new Error(`File not found: ${resolvedPath}`)\n }\n\n return content\n }\n}\n", "/**\n * Scanning-grammar mirrors of parser statements, for tools that need to\n * FIND directives in raw text without running the full parser (workspace\n * indexers, linters). Kept next to the parser so grammar changes update\n * both; tests/scan.test.ts asserts parser agreement for every form the\n * scan regex matches.\n */\n\n/**\n * Fresh regex matching a complete `{% include \"path\" %}` statement,\n * capturing the path. Factory (not a shared const) because the global\n * flag makes RegExp objects stateful.\n *\n * Grammar notes, matching parser.ts:\n * - `{%-` / `-%}` whitespace-trim markers are accepted.\n * - At least one whitespace character is required after `include`.\n * - The path is quoted with `\"` or `'` and contains no quote chars.\n */\nexport const includeDirectiveRe = (): RegExp =>\n /\\{%-?\\s*include\\s+[\"']([^\"']+)[\"']\\s*-?%\\}/g;\n\n/** All `{% include %}` paths in a text, in order. */\nexport const scanIncludes = (text: string): string[] =>\n [...text.matchAll(includeDirectiveRe())].map((match) => match[1]);\n\n/**\n * Fresh regex matching a complete `{{ \u2026 }}` variable/expression output,\n * capturing the raw inner source (whitespace-trim markers accepted, not\n * captured). Grammar mirror of parser.ts's `{{`\u2192`}}` scan.\n */\nexport const variableRe = (): RegExp => /\\{\\{-?([\\s\\S]*?)-?\\}\\}/g;\n\n/**\n * Fresh regex matching a complete `{% \u2026 %}` statement tag, capturing the\n * keyword and the raw remainder (up to the closing marker). Grammar mirror\n * of parser.ts's `{%`\u2192`%}` scan \u2014 the keyword set is NOT validated here;\n * consumers classify (if/elif/else/endif/include/set/\u2026) themselves.\n */\nexport const directiveTagRe = (): RegExp =>\n /\\{%-?\\s*([A-Za-z_][A-Za-z0-9_]*)([\\s\\S]*?)-?%\\}/g;\n\n/**\n * Fresh regex matching a complete `{# \u2026 #}` comment. Grammar mirror of\n * parser.ts's `{#`\u2192`#}` scan.\n */\nexport const commentRe = (): RegExp => /\\{#[\\s\\S]*?#\\}/g;\n\n/**\n * Fresh regex matching a complete `{% raw %}\u2026{% endraw %}` block, capturing\n * the verbatim inner content. Grammar mirror of parser.ts's raw handling.\n * Consumers that classify individual tags (directiveTagRe) should match\n * raw blocks FIRST \u2014 the inner content is not directive syntax.\n */\nexport const rawBlockRe = (): RegExp =>\n /\\{%-?\\s*raw\\s*-?%\\}([\\s\\S]*?)\\{%-?\\s*endraw\\s*-?%\\}/g;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["tagStart", "endPos", "endifMatch", "isTruthy"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* minja v0.2.0-beta.100
|
|
3
|
+
* Minimal, secure Jinja2/Nunjucks subset for documentation preprocessing
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
"use strict";var minja=(()=>{var Z=Object.defineProperty;var oe=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var le=(e,s)=>{for(var n in s)Z(e,n,{get:s[n],enumerable:!0})},fe=(e,s,n,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let i of ae(s))!ce.call(e,i)&&i!==n&&Z(e,i,{get:()=>s[i],enumerable:!(t=oe(s,i))||t.enumerable});return e};var ue=e=>fe(Z({},"__esModule",{value:!0}),e);var me={};le(me,{Context:()=>W,FetchLoader:()=>j,MemoryLoader:()=>V,commentRe:()=>re,directiveTagRe:()=>ne,evaluateExpression:()=>k,includeDirectiveRe:()=>q,parse:()=>N,parseExpression:()=>I,rawBlockRe:()=>ie,render:()=>ee,scanIncludes:()=>te,variableRe:()=>se});function I(e){if(e=e.trim(),e==="true")return{type:"literal",value:!0};if(e==="false")return{type:"literal",value:!1};if(e==="null")return{type:"literal",value:null};if(e.startsWith('"')&&e.endsWith('"'))return{type:"literal",value:e.slice(1,-1)};if(e.startsWith("'")&&e.endsWith("'"))return{type:"literal",value:e.slice(1,-1)};if(/^-?\d+(\.\d+)?$/.test(e))return{type:"literal",value:parseFloat(e)};if(e.startsWith("(")&&e.endsWith(")")){let i=0,r=!0;for(let o=0;o<e.length;o++)if(e[o]==="("?i++:e[o]===")"&&i--,i===0&&o<e.length-1){r=!1;break}if(r&&i===0)return I(e.slice(1,-1))}if(e.startsWith("not "))return{type:"unary",operator:"not",operand:I(e.substring(4))};let s=G(e," or ");if(s!==-1)return{type:"binary",operator:"or",left:I(e.substring(0,s)),right:I(e.substring(s+4))};let n=G(e," and ");if(n!==-1)return{type:"binary",operator:"and",left:I(e.substring(0,n)),right:I(e.substring(n+5))};let t=["==","!=","<=",">=","<",">"];for(let i of t){let r=G(e,` ${i} `);if(r!==-1)return{type:"binary",operator:i,left:I(e.substring(0,r)),right:I(e.substring(r+i.length+2))}}if(/^[\w.-]+$/.test(e))return{type:"variable",name:e};throw new Error(`Invalid expression: ${e}`)}function G(e,s){let n=null,t=0;for(let i=0;i<e.length;i++){let r=e[i];if((r==='"'||r==="'")&&(i===0||e[i-1]!=="\\")){n===r?n=null:n===null&&(n=r);continue}if(n||(r==="("?t++:r===")"&&t--),!n&&t===0&&e.substring(i,i+s.length)===s)return i}return-1}function k(e,s){switch(e.type){case"literal":return e.value;case"variable":return s.get(e.name);case"binary":{let n=k(e.left,s),t=k(e.right,s);switch(e.operator){case"==":return n==t;case"!=":return n!=t;case"<":return n<t;case">":return n>t;case"<=":return n<=t;case">=":return n>=t;case"and":return U(n)&&U(t);case"or":return U(n)||U(t)}break}case"unary":{let n=k(e.operand,s);switch(e.operator){case"not":return!U(n)}break}}}function U(e){return!(e==null||e===!1||e===0||e==="")}var he=new Set(["set","if","include","switch","leveloffset","raw","endif","elif","else","endswitch","case","endleveloffset","endraw"]);function H(e,s){return s.startsWith("{%-")?e.replace(/[ \t]*\n[ \t\n]*$/,""):e}function N(e){let s=[],n=[],t=0,i=1,r=1;function o(f){return{message:f,position:t,line:i,column:r}}function c(f){for(let h=0;h<f;h++)e[t+h]===`
|
|
7
|
+
`?(i++,r=1):r++;t+=f}function l(f,h=t){return e.indexOf(f,h)}function a(f){let h=e.substring(t,f);return c(f-t),h}for(;t<e.length;){let f=l("{{",t),h=l("{%",t),b=l("{#",t),T=[{pos:f,type:"var"},{pos:h,type:"tag"},{pos:b,type:"comment"}].filter(g=>g.pos!==-1);if(T.length===0){let g=e.substring(t);g&&n.push({type:"text",value:g});break}T.sort((g,m)=>g.pos-m.pos);let p=T[0];if(p.pos>t&&n.push({type:"text",value:a(p.pos)}),p.type==="var"){c(2);let g=l("}}",t);if(g===-1){s.push(o("Unclosed variable tag"));break}let m=a(g).trim();c(2),n.push({type:"variable",name:m})}else if(p.type==="comment"){if(n.length>0&&n[n.length-1].type==="text"){let w=n[n.length-1];/\n[ \t]*$/.test(w.value)&&(w.value=w.value.replace(/[ \t]*\n[ \t]*$/,""))}c(2);let g=l("#}",t);if(g===-1){s.push(o("Unclosed comment tag"));break}let m=a(g);if(c(2),n.push({type:"comment",value:m}),t<e.length&&e[t]===`
|
|
8
|
+
`)for(c(1);t<e.length&&/[ \t]/.test(e[t]);)c(1)}else if(p.type==="tag"){let g=t;c(2);let m=l("%}",t);if(m===-1){s.push(o("Unclosed statement tag"));break}let w=e.substring(t,m).trim(),S=w.replace(/^-\s*/,"").replace(/\s*-$/,"").split(/\s+/)[0]??"";if(S==="raw"){let d=w.startsWith("-"),v=w.endsWith("-");if(d&&n.length>0&&n[n.length-1].type==="text"){let A=n[n.length-1];A.value=A.value.replace(/[ \t]*\n[ \t\n]*$/,"")}if(a(m),c(2),v)for(;t<e.length&&/[ \t\n]/.test(e[t]);)c(1);let E=/\{%-?\s*endraw\s*-?%\}/.exec(e.substring(t));if(!E){s.push(o("Unclosed raw block"));break}let B=t+E.index,$=a(B),R=E[0];if(R.startsWith("{%-")&&($=$.replace(/[ \t]*\n[ \t\n]*$/,"")),c(R.length),R.endsWith("-%}"))for(;t<e.length&&/[ \t\n]/.test(e[t]);)c(1);$&&n.push({type:"text",value:$});continue}if(!he.has(S)){a(m),c(2),n.push({type:"text",value:e.substring(g,m+2)});continue}let x=a(m).trim(),y=x.startsWith("-"),P=x.endsWith("-");if(y&&(x=x.substring(1).trim(),n.length>0&&n[n.length-1].type==="text")){let d=n[n.length-1];d.value=d.value.replace(/[ \t]*\n[ \t\n]*$/,"")}if(P&&(x=x.substring(0,x.length-1).trim()),c(2),P)for(;t<e.length&&/[ \t\n]/.test(e[t]);)c(1);if(x.startsWith("set ")){let d=/^set\s+(\w+)\s*=\s*(.+)$/.exec(x);if(d)try{let v=I(d[2]);n.push({type:"set",name:d[1],value:v})}catch(v){s.push(o(`Invalid set expression: ${v.message}`))}else s.push(o("Invalid set syntax"))}else if(x.startsWith("if ")){let d=x.substring(3).trim();try{let v=I(d),{trueBranch:E,elifBranches:B,elseBranch:$,parseErrors:R}=O();s.push(...R),n.push({type:"if",condition:v,trueBranch:E,elifBranches:B.length>0?B:void 0,elseBranch:$.length>0?$:void 0})}catch(v){s.push(o(`Invalid if expression: ${v.message}`))}}else if(x.startsWith("include ")){let d=/^include\s+["']([^"']+)["']/.exec(x);d?n.push({type:"include",path:d[1]}):s.push(o("Invalid include syntax"))}else if(x.startsWith("switch ")){let d=x.substring(7).trim();try{let v=I(d),{cases:E,parseErrors:B}=K();s.push(...B),n.push({type:"switch",expression:v,cases:E})}catch(v){s.push(o(`Invalid switch expression: ${v.message}`))}}else if(x.startsWith("leveloffset ")){let d=/^leveloffset\s+([-+]?\d+)$/.exec(x);if(!d)s.push(o("Invalid leveloffset syntax"));else{let v=d[1],E=v.startsWith("+")||v.startsWith("-"),B=parseInt(v,10);if(isNaN(B))s.push(o("Invalid leveloffset value"));else{let $=0,R=t,A=-1;for(;R<e.length;){let D=/{%-?\s*leveloffset\s+[-+]?\d+\s*-?%}/.exec(e.substring(R)),C=/{%-?\s*endleveloffset\s*-?%}/.exec(e.substring(R)),L=D?R+D.index:1/0,z=C?R+C.index:1/0;if(L<z)$++,R=L+(D?.[0].length||0);else if(z<1/0)if($===0){A=z;break}else $--,R=z+(C?.[0].length||0);else break}if(A===-1)s.push(o("Missing endleveloffset"));else{let D=a(A),C=/{%-?\s*endleveloffset\s*-?%}/.exec(e.substring(t));C&&c(C[0].length);let L=N(D);s.push(...L.errors),n.push({type:"leveloffset",offset:B,isRelative:E,body:L.ast})}}}}}}return{ast:n,errors:s};function u(f){let b=new RegExp(`{%-?\\s*${f}\\s*-?%}`).exec(e.substring(t));return b?{start:t+b.index,length:b[0].length,tag:b[0]}:null}function O(){let f=[],h=[],b=[],T=0,p=t;for(;p<e.length;){let g=/{%-?\s*if\s+/.exec(e.substring(p)),m=/{%-?\s*elif\s+/.exec(e.substring(p)),w=/{%-?\s*else\s*-?%}/.exec(e.substring(p)),S=/{%-?\s*endif\s*-?%}/.exec(e.substring(p)),y=[{type:"if",match:g,pos:g?p+g.index:1/0},{type:"elif",match:m,pos:m?p+m.index:1/0},{type:"else",match:w,pos:w?p+w.index:1/0},{type:"endif",match:S,pos:S?p+S.index:1/0}].sort((P,d)=>P.pos-d.pos)[0];if(!y.match||y.pos===1/0){h.push(o("Missing endif"));break}if(y.type==="if")T++,p=y.pos+y.match[0].length;else if(y.type==="endif")if(T===0){let P=H(a(y.pos),y.match[0]);if(c(y.match[0].length),y.match[0].endsWith("-%}"))for(;t<e.length&&/[ \t\n]/.test(e[t]);)c(1);let d=N(P);return h.push(...d.errors),{trueBranch:d.ast,elifBranches:f,elseBranch:b,parseErrors:h}}else T--,p=y.pos+y.match[0].length;else if(T===0&&(y.type==="elif"||y.type==="else")){let P=H(a(y.pos),y.match[0]),d=N(P);if(f.length===0&&b.length===0){h.push(...d.errors);let v=d.ast;if(y.type==="elif"){c(y.match[0].length);let E=/^([^%]+)%}/.exec(e.substring(t));if(E){let B=E[1].trim();c(E[0].length);try{let $=I(B),R=O();return h.push(...R.parseErrors),f.push({condition:$,body:R.trueBranch}),f.push(...R.elifBranches||[]),b=R.elseBranch,{trueBranch:v,elifBranches:f,elseBranch:b,parseErrors:h}}catch($){h.push(o(`Invalid elif expression: ${$.message}`))}}}else{c(y.match[0].length);let E=u("endif");if(!E)h.push(o("Missing endif after else"));else{let B=H(a(E.start),E.tag);c(E.length);let $=N(B);h.push(...$.errors),b=$.ast}return{trueBranch:v,elifBranches:f,elseBranch:b,parseErrors:h}}}}else p=y.pos+y.match[0].length}return{trueBranch:[],elifBranches:f,elseBranch:b,parseErrors:h}}function K(){let f=[],h=[];for(;t<e.length;){let b=/{%-?\s*case\s+/.exec(e.substring(t)),T=/{%-?\s*endswitch\s*-?%}/.exec(e.substring(t)),p=b?t+b.index:1/0,g=T?t+T.index:1/0;if(g<p){if(f.length>0&&t<g){let m=a(g),w=N(m);h.push(...w.errors),f[f.length-1].body=w.ast}c(g-t+(T?.[0].length||0));break}else if(p<1/0){if(f.length>0&&t<p){let w=a(p),S=N(w);h.push(...S.errors),f[f.length-1].body=S.ast}else t<p&&a(p);c(b[0].length);let m=/([^%]+)%}/.exec(e.substring(t));if(m){let w=m[1].trim();c(m[0].length);try{let S=I(w);f.push({value:S,body:[]})}catch(S){h.push(o(`Invalid case value: ${S.message}`))}}else{h.push(o("Invalid case syntax"));break}}else{h.push(o("Missing endswitch"));break}}return{cases:f,parseErrors:h}}}var W=class e{constructor(s,n){this.variables=new Map,this.parent=s||null,this.options=n||s?.options||{}}get(s){let t=(this.options.hyphenToUnderscore?s.replace(/-/g,"_"):s).split("."),i=t[0],r;if(this.variables.has(i))r=this.variables.get(i);else if(this.parent)r=this.parent.get(i);else return;for(let o=1;o<t.length;o++){if(r==null||typeof r!="object"||Array.isArray(r)||!Object.prototype.hasOwnProperty.call(r,t[o]))return;r=r[t[o]]}return r}set(s,n){let t=s.split(".");if(t.length===1){this.variables.set(s,n);return}let i=t[0],r=this.variables.get(i);(!r||typeof r!="object"||Array.isArray(r))&&(r={},this.variables.set(i,r));for(let o=1;o<t.length-1;o++){let c=t[o];(!r[c]||typeof r[c]!="object"||Array.isArray(r[c]))&&(r[c]={}),r=r[c]}r[t[t.length-1]]=n}push(){return new e(this,this.options)}pop(){return this.parent}static from(s,n){let t=new e(void 0,n);for(let[i,r]of Object.entries(s))t.set(i,r);return t}};var j=class{async load(s,n){let t=n?new URL(s,n).href:s,i=`${t}?preventCache=${Date.now()}`,r=await fetch(i);if(!r.ok)throw new Error(`Failed to load ${t}: ${r.status} ${r.statusText}`);return await r.text()}};function de(e,s,n=null,t){if(s===0)return t&&(t.fence=n),e;let i=e.split(`
|
|
9
|
+
`),r=n;for(let o=0;o<i.length;o++){let c=i[o],l=c.match(/^\s*(`{3,}|~{3,})/);if(l){let u=l[1];r===null?r=u:u[0]===r[0]&&u.length>=r.length&&c.trim()===u&&(r=null);continue}if(r!==null)continue;let a=c.match(/^(#{1,6})(\s+)/);if(a){let u=Math.max(1,Math.min(6,a[1].length+s));i[o]="#".repeat(u)+c.slice(a[1].length)}}return t&&(t.fence=r),i.join(`
|
|
10
|
+
`)}function pe(e,s){if(e.startsWith("/"))return e;let t=(s.endsWith("/")?s:s+"/")+e,i=t.split("/"),r=[];for(let c of i)c==="."||c===""||(c===".."?r.pop():r.push(c));return(t.startsWith("/")?"/":"")+r.join("/")}async function ee(e,s={}){let{loader:n=new j,context:t={},basePath:i="",maxIncludeDepth:r=10,timeout:o=5e3,hyphenToUnderscore:c=!1,undefinedBehavior:l="empty",undefinedConditions:a="preserve"}=s,u=new Promise((K,f)=>{setTimeout(()=>f(new Error("Template rendering timeout")),o)}),O=J(e,{loader:n,context:W.from({...t,date:new Date().toISOString().split("T")[0],timestamp:Date.now(),_levelOffset:0},{hyphenToUnderscore:c}),includeDepth:0,maxIncludeDepth:r,basePath:i,undefinedBehavior:l,undefinedConditions:a});return await Promise.race([O,u])}async function J(e,s){let{includeDepth:n,maxIncludeDepth:t}=s;if(n>t)throw new Error(`Maximum include depth (${t}) exceeded`);let i=N(e);if(i.errors.length>0){let r=i.errors.map(o=>o.message).join(", ");throw new Error(`Parse errors: ${r}`)}return await _(i.ast,s)}async function _(e,s){let n=[];for(let t of e){let i=await ge(t,s);if(t.type==="include"&&i&&n.length>0){let r=/(?:^|\n)([ \t]+)$/.exec(n[n.length-1]);r&&(i=i.replace(/\n(?=[^\n])/g,`
|
|
11
|
+
`+r[1]))}n.push(i)}return n.join("")}async function ge(e,s){let{loader:n,context:t,includeDepth:i,maxIncludeDepth:r,basePath:o}=s;switch(e.type){case"text":{let l=t.get("_levelOffset")||0;if(l===0)return e.value;let a={fence:null},u=de(e.value,l,t.get("_levelOffsetFence")??null,a);return t.set("_levelOffsetFence",a.fence),u}case"variable":{let l=t.get(e.name);if(l==null)switch(s.undefinedBehavior){case"throw":throw new Error(`Undefined variable: ${e.name}`);case"preserve":return`{{ ${e.name} }}`;case"asciidoc-literal":return`{${e.name}}`;case"empty":default:return""}let a=String(l);return a.includes("{{")||a.includes("{%")?await J(a,s):a}case"set":{let l=k(e.value,t);return t.set(e.name,l),""}case"comment":return"";case"if":{if((s.undefinedBehavior==="preserve"||s.undefinedBehavior==="asciidoc-literal")&&s.undefinedConditions!=="falsy"){if(X(e.condition,t).length>0)return Y(e);if(e.elifBranches){for(let u of e.elifBranches)if(X(u.condition,t).length>0)return Y(e)}}let l=k(e.condition,t);if(Q(l))return await _(e.trueBranch,s);if(e.elifBranches)for(let a of e.elifBranches){let u=k(a.condition,t);if(Q(u))return await _(a.body,s)}return e.elseBranch?await _(e.elseBranch,s):""}case"include":try{let l=await n.load(e.path,o),a=o;if(e.path.includes("://")){let u=new URL(e.path);a=u.href.substring(0,u.href.lastIndexOf("/")+1)}else if(o)if(o.includes("://")){let u=new URL(e.path,o);a=u.href.substring(0,u.href.lastIndexOf("/")+1)}else{let u=pe(e.path,o),O=u.lastIndexOf("/");a=O>=0?u.substring(0,O+1):o}else if(e.path.includes("/")){let u=e.path.lastIndexOf("/");a=e.path.substring(0,u+1)}return await J(l,{loader:n,context:t,includeDepth:i+1,maxIncludeDepth:r,basePath:a,undefinedBehavior:s.undefinedBehavior,undefinedConditions:s.undefinedConditions})}catch(l){if(l instanceof Error&&l.name==="IncludeContainmentError")throw l;if(s.undefinedBehavior==="preserve"||s.undefinedBehavior==="asciidoc-literal")return`{% include "${e.path}" %}`;let a=l instanceof Error?l.message:String(l);return console.error(`Failed to include ${e.path}:`,a),`<!-- Include error: ${e.path} -->`}case"switch":{let l=k(e.expression,t);for(let a of e.cases){let u=k(a.value,t);if(l==u)return await _(a.body,s)}return""}case"leveloffset":{let l=t.get("_levelOffset")||0,a=e.isRelative?l+e.offset:e.offset,u=l;t.set("_levelOffset",a);let O=t.get("_levelOffsetFence")??null;t.set("_levelOffsetFence",null);try{return await _(e.body,s)}finally{t.set("_levelOffset",u),t.set("_levelOffsetFence",O)}}default:return e}}function Q(e){return!(e==null||e===!1||e===0||e==="")}function X(e,s){let n=[];function t(i){switch(i.type){case"variable":s.get(i.name)===void 0&&n.push(i.name);break;case"binary":t(i.left),t(i.right);break;case"unary":t(i.operand);break;case"literal":break}}return t(e),n}function M(e){switch(e.type){case"literal":return typeof e.value=="string"?JSON.stringify(e.value):e.value===null?"null":String(e.value);case"variable":return e.name;case"unary":return`not ${M(e.operand)}`;case"binary":return`(${M(e.left)} ${e.operator} ${M(e.right)})`}}function F(e){return e.map(ye).join("")}function ye(e){switch(e.type){case"text":return e.value;case"variable":return`{{ ${e.name} }}`;case"set":return`{% set ${e.name} = ${M(e.value)} %}`;case"comment":return"{# \u2026 #}";case"if":return Y(e);case"include":return`{% include "${e.path}" %}`;case"leveloffset":return`{% leveloffset ${e.isRelative&&e.offset>=0?"+":""}${e.offset} %}${F(e.body)}{% endleveloffset %}`;case"switch":{let s=e.cases.map(n=>`{% case ${M(n.value)} %}${F(n.body)}`).join("");return`{% switch ${M(e.expression)} %}${s}{% endswitch %}`}}}function Y(e){let s=[`{% if ${M(e.condition)} %}`,F(e.trueBranch)];if(e.elifBranches)for(let n of e.elifBranches)s.push(`{% elif ${M(n.condition)} %}`,F(n.body));return e.elseBranch&&s.push("{% else %}",F(e.elseBranch)),s.push("{% endif %}"),s.join("")}var V=class{constructor(s={}){this.files=new Map(Object.entries(s))}addFile(s,n){this.files.set(s,n)}async load(s,n){let t=n&&!s.startsWith("/")?`${n}/${s}`:s,i=t.split("/"),r=[];for(let a of i)if(!(a==="."||a==="")){if(a===".."){r.pop();continue}r.push(a)}let c=(t.startsWith("/")?"/":"")+r.join("/"),l=this.files.get(c);if(l===void 0)throw new Error(`File not found: ${c}`);return l}};var q=()=>/\{%-?\s*include\s+["']([^"']+)["']\s*-?%\}/g,te=e=>[...e.matchAll(q())].map(s=>s[1]),se=()=>/\{\{-?([\s\S]*?)-?\}\}/g,ne=()=>/\{%-?\s*([A-Za-z_][A-Za-z0-9_]*)([\s\S]*?)-?%\}/g,re=()=>/\{#[\s\S]*?#\}/g,ie=()=>/\{%-?\s*raw\s*-?%\}([\s\S]*?)\{%-?\s*endraw\s*-?%\}/g;return ue(me);})();
|
|
12
|
+
//# sourceMappingURL=index.umd.min.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/browser.ts", "../src/evaluator.ts", "../src/parser.ts", "../src/context.ts", "../src/loader-fetch.ts", "../src/renderer.ts", "../src/loader-memory.ts", "../src/scan.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Browser-only entry point (excludes FileSystemLoader)\n */\n\nexport { render } from './renderer.js'\nexport { parse } from './parser.js'\nexport { parseExpression, evaluateExpression } from './evaluator.js'\nexport { Context } from './context.js'\nexport { FetchLoader } from './loader-fetch.js'\nexport { MemoryLoader } from './loader-memory.js'\n\nexport type {\n // AST types\n ASTNode,\n TextNode,\n VariableNode,\n SetNode,\n IfNode,\n IncludeNode,\n CommentNode,\n\n // Expression types\n Expression,\n LiteralExpression,\n VariableExpression,\n BinaryExpression,\n UnaryExpression,\n\n // Options and interfaces\n RenderOptions,\n Loader,\n IContext,\n ParseResult,\n ParseError,\n} from './types.js'\nexport { includeDirectiveRe, scanIncludes, variableRe, directiveTagRe, commentRe, rawBlockRe } from './scan.js'\n", "/**\n * Safe expression evaluator\n * Evaluates expressions WITHOUT using eval() or new Function()\n * Only allows whitelisted operations\n */\n\nimport type { Expression, IContext } from './types.js'\n\n/**\n * Parse an expression string into an Expression AST\n * @param expr - Expression string to parse\n * @returns Expression AST\n */\nexport function parseExpression(expr: string): Expression {\n expr = expr.trim()\n\n // Handle boolean literals\n if (expr === 'true') {\n return { type: 'literal', value: true }\n }\n if (expr === 'false') {\n return { type: 'literal', value: false }\n }\n if (expr === 'null') {\n return { type: 'literal', value: null }\n }\n\n // Handle string literals (double quotes)\n if (expr.startsWith('\"') && expr.endsWith('\"')) {\n return { type: 'literal', value: expr.slice(1, -1) }\n }\n\n // Handle string literals (single quotes)\n if (expr.startsWith(\"'\") && expr.endsWith(\"'\")) {\n return { type: 'literal', value: expr.slice(1, -1) }\n }\n\n // Handle number literals\n if (/^-?\\d+(\\.\\d+)?$/.test(expr)) {\n return { type: 'literal', value: parseFloat(expr) }\n }\n\n // Handle parenthesized expressions\n if (expr.startsWith('(') && expr.endsWith(')')) {\n // Check if parentheses are balanced for the entire expression\n let depth = 0\n let balanced = true\n\n for (let i = 0; i < expr.length; i++) {\n if (expr[i] === '(') {\n depth++\n } else if (expr[i] === ')') {\n depth--\n }\n\n // If depth hits 0 before the end, the outer parens aren't wrapping everything\n if (depth === 0 && i < expr.length - 1) {\n balanced = false\n break\n }\n }\n\n // If balanced, unwrap and recursively parse\n if (balanced && depth === 0) {\n return parseExpression(expr.slice(1, -1))\n }\n }\n\n // Handle logical NOT\n if (expr.startsWith('not ')) {\n return {\n type: 'unary',\n operator: 'not',\n operand: parseExpression(expr.substring(4))\n }\n }\n\n // Handle logical OR (lowest precedence)\n const orMatch = findOperator(expr, ' or ')\n if (orMatch !== -1) {\n return {\n type: 'binary',\n operator: 'or',\n left: parseExpression(expr.substring(0, orMatch)),\n right: parseExpression(expr.substring(orMatch + 4))\n }\n }\n\n // Handle logical AND\n const andMatch = findOperator(expr, ' and ')\n if (andMatch !== -1) {\n return {\n type: 'binary',\n operator: 'and',\n left: parseExpression(expr.substring(0, andMatch)),\n right: parseExpression(expr.substring(andMatch + 5))\n }\n }\n\n // Handle comparison operators\n const comparisonOps = ['==', '!=', '<=', '>=', '<', '>']\n for (const op of comparisonOps) {\n const opMatch = findOperator(expr, ` ${op} `)\n if (opMatch !== -1) {\n return {\n type: 'binary',\n operator: op as '==' | '!=' | '<' | '>' | '<=' | '>=',\n left: parseExpression(expr.substring(0, opMatch)),\n right: parseExpression(expr.substring(opMatch + op.length + 2))\n }\n }\n }\n\n // Handle simple variable lookup (with dot notation).\n // Hyphens are allowed in identifiers so AsciiDoc-style attribute\n // names (`product-version`, `ptp-events-rest-api`) work inside\n // `{% if %}` conditions \u2014 they resolve via `hyphenToUnderscore` in\n // Context.get, just like `{{ product-version }}` interpolations.\n // Minja has no subtraction operator, so a `-` is never ambiguous\n // here; negative number literals are matched earlier.\n if (/^[\\w.-]+$/.test(expr)) {\n return { type: 'variable', name: expr }\n }\n\n // If we can't parse it, throw an error\n throw new Error(`Invalid expression: ${expr}`)\n}\n\n/**\n * Find the position of an operator, respecting string literals\n * @param expr - Expression string\n * @param operator - Operator to find\n * @returns Position of operator or -1 if not found\n */\nfunction findOperator(expr: string, operator: string): number {\n let inString: string | null = null\n let depth = 0\n\n for (let i = 0; i < expr.length; i++) {\n const char = expr[i]\n\n // Track string literals\n if ((char === '\"' || char === \"'\") && (i === 0 || expr[i - 1] !== '\\\\')) {\n if (inString === char) {\n inString = null\n } else if (inString === null) {\n inString = char\n }\n continue\n }\n\n // Track parentheses depth\n if (!inString) {\n if (char === '(') {\n depth++\n } else if (char === ')') {\n depth--\n }\n }\n\n // Look for operator at depth 0, outside strings\n if (!inString && depth === 0) {\n if (expr.substring(i, i + operator.length) === operator) {\n return i\n }\n }\n }\n\n return -1\n}\n\n/**\n * Evaluate an expression in a given context\n * @param expr - Expression to evaluate\n * @param context - Variable context\n * @returns Evaluated value\n */\nexport function evaluateExpression(expr: Expression, context: IContext): unknown {\n switch (expr.type) {\n case 'literal':\n return expr.value\n\n case 'variable':\n return context.get(expr.name)\n\n case 'binary': {\n const left = evaluateExpression(expr.left, context)\n const right = evaluateExpression(expr.right, context)\n\n switch (expr.operator) {\n case '==':\n // eslint-disable-next-line eqeqeq\n return left == right\n case '!=':\n // eslint-disable-next-line eqeqeq\n return left != right\n case '<':\n return (left as number) < (right as number)\n case '>':\n return (left as number) > (right as number)\n case '<=':\n return (left as number) <= (right as number)\n case '>=':\n return (left as number) >= (right as number)\n case 'and':\n return isTruthy(left) && isTruthy(right)\n case 'or':\n return isTruthy(left) || isTruthy(right)\n }\n break\n }\n\n case 'unary': {\n const operand = evaluateExpression(expr.operand, context)\n\n switch (expr.operator) {\n case 'not':\n return !isTruthy(operand)\n }\n break\n }\n }\n\n return undefined\n}\n\n/**\n * Determine if a value is truthy in template context\n * @param value - Value to check\n * @returns true if truthy\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === undefined || value === null || value === false) {\n return false\n }\n if (value === 0 || value === '') {\n return false\n }\n return true\n}\n", "/**\n * Template parser\n * Converts template strings into AST (Abstract Syntax Tree)\n */\n\nimport type { ASTNode, ParseResult, ParseError } from './types.js'\nimport { parseExpression } from './evaluator.js'\n\n/**\n * Statement keywords the parser understands. Openers dispatch below; the\n * end/branch keywords are consumed by their opening tags (stray ones are\n * ignored, matching historical behavior). Anything OUTSIDE this set is an\n * unknown statement and is preserved verbatim in the output \u2014 silently\n * deleting author content is never acceptable.\n */\nconst KNOWN_TAG_KEYWORDS = new Set([\n 'set',\n 'if',\n 'include',\n 'switch',\n 'leveloffset',\n 'raw',\n 'endif',\n 'elif',\n 'else',\n 'endswitch',\n 'case',\n 'endleveloffset',\n 'endraw',\n])\n\n/**\n * Parse a template string into an AST\n * @param template - Template string to parse\n * @returns Parse result with AST and errors\n */\n/**\n * Apply a closing tag's LEFT whitespace-control marker to the body it closes.\n *\n * `{%- endif %}` must strip the whitespace before it \u2014 including the newline \u2014\n * exactly as `{%-` does on an opening tag. Block bodies are extracted by\n * matching the end tag textually (`/{%-?\\s*endif\\s*-?%}/`), and the `-?` was\n * matched but never acted on, so the body kept its trailing newline. Combined\n * with the newline that follows the tag, an AsciiDoc conditional written\n * inline in a paragraph \u2014\n *\n * Welcome to the official {{ product_title }}\n * {%- if not openshift_rosa %}\n * {{ product_version }}\n * {%- endif %}\n * documentation, where you can learn\u2026\n *\n * \u2014 rendered a BLANK line after the version, splitting one sentence into two\n * paragraphs mid-clause. Jinja2 produces no blank line here.\n */\nfunction stripBodyForEndTag (body: string, endTag: string): string {\n return endTag.startsWith('{%-') ? body.replace(/[ \\t]*\\n[ \\t\\n]*$/, '') : body\n}\n\nexport function parse(template: string): ParseResult {\n const errors: ParseError[] = []\n const ast: ASTNode[] = []\n\n let position = 0\n let line = 1\n let column = 1\n\n /**\n * Create a parse error\n */\n function createError(message: string): ParseError {\n return { message, position, line, column }\n }\n\n /**\n * Advance position tracking\n */\n function advance(count: number): void {\n for (let i = 0; i < count; i++) {\n if (template[position + i] === '\\n') {\n line++\n column = 1\n } else {\n column++\n }\n }\n position += count\n }\n\n /**\n * Find the next occurrence of a string\n */\n function findNext(str: string, from: number = position): number {\n return template.indexOf(str, from)\n }\n\n /**\n * Extract text between current position and a target position\n */\n function extractTo(target: number): string {\n const text = template.substring(position, target)\n advance(target - position)\n return text\n }\n\n while (position < template.length) {\n // Look for template tags\n const varStart = findNext('{{', position)\n const tagStart = findNext('{%', position)\n const commentStart = findNext('{#', position)\n\n // Find the nearest tag\n const candidates = [\n { pos: varStart, type: 'var' },\n { pos: tagStart, type: 'tag' },\n { pos: commentStart, type: 'comment' },\n ].filter((c) => c.pos !== -1)\n\n if (candidates.length === 0) {\n // No more tags, rest is text\n const text = template.substring(position)\n if (text) {\n ast.push({ type: 'text', value: text })\n }\n break\n }\n\n // Sort to find nearest\n candidates.sort((a, b) => a.pos - b.pos)\n const nearest = candidates[0]\n\n // Add text before tag\n if (nearest.pos > position) {\n ast.push({ type: 'text', value: extractTo(nearest.pos) })\n }\n\n // Parse the tag\n if (nearest.type === 'var') {\n // Variable: {{ name }}\n advance(2) // Skip {{\n const endPos = findNext('}}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed variable tag'))\n break\n }\n\n const varName = extractTo(endPos).trim()\n advance(2) // Skip }}\n\n ast.push({ type: 'variable', name: varName })\n } else if (nearest.type === 'comment') {\n // Comment: {# ... #}\n // Auto-strip newlines for comments (they produce no output)\n // Only strip if the comment is on its own line\n if (ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n // Only strip if previous text ends with newline (comment is on its own line)\n if (/\\n[ \\t]*$/.test(lastNode.value)) {\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t]*$/, '')\n }\n }\n\n advance(2) // Skip {#\n const endPos = findNext('#}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed comment tag'))\n break\n }\n\n const commentText = extractTo(endPos)\n advance(2) // Skip #}\n\n ast.push({ type: 'comment', value: commentText })\n\n // Auto-strip following newline if comment is on its own line\n if (position < template.length && template[position] === '\\n') {\n advance(1)\n // Also skip any indentation on the next line\n while (position < template.length && /[ \\t]/.test(template[position])) {\n advance(1)\n }\n }\n } else if (nearest.type === 'tag') {\n // Statement tag: {% ... %}\n const tagStart = position\n advance(2) // Skip {%\n const endPos = findNext('%}', position)\n\n if (endPos === -1) {\n errors.push(createError('Unclosed statement tag'))\n break\n }\n\n // Peek the keyword BEFORE whitespace-control processing, so raw\n // blocks and unknown tags are handled without side effects.\n const peeked = template.substring(position, endPos).trim()\n const peekKeyword =\n peeked.replace(/^-\\s*/, '').replace(/\\s*-$/, '').split(/\\s+/)[0] ?? ''\n\n if (peekKeyword === 'raw') {\n // {% raw %} ... {% endraw %} \u2014 Jinja semantics: everything between\n // the markers passes through COMPLETELY unevaluated; the markers\n // themselves produce no output. Whitespace-control markers are\n // honored on both tags.\n const openerLeftStrip = peeked.startsWith('-')\n const openerRightStrip = peeked.endsWith('-')\n if (openerLeftStrip && ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n extractTo(endPos)\n advance(2) // Skip %}\n if (openerRightStrip) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n const endrawMatch = /\\{%-?\\s*endraw\\s*-?%\\}/.exec(template.substring(position))\n if (!endrawMatch) {\n errors.push(createError('Unclosed raw block'))\n break\n }\n const endrawAbs = position + endrawMatch.index\n let content = extractTo(endrawAbs)\n const endrawTag = endrawMatch[0]\n if (endrawTag.startsWith('{%-')) {\n content = content.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n advance(endrawTag.length)\n if (endrawTag.endsWith('-%}')) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n if (content) {\n ast.push({ type: 'text', value: content })\n }\n continue\n }\n\n if (!KNOWN_TAG_KEYWORDS.has(peekKeyword)) {\n // Unknown statement: preserve the tag verbatim (it was previously\n // silently dropped). No whitespace control is applied \u2014 the bytes\n // pass through exactly as authored.\n extractTo(endPos)\n advance(2) // Skip %}\n ast.push({ type: 'text', value: template.substring(tagStart, endPos + 2) })\n continue\n }\n\n let statement = extractTo(endPos).trim()\n\n // Check for whitespace control characters\n const hasLeftStrip = statement.startsWith('-')\n const hasRightStrip = statement.endsWith('-')\n\n // Strip whitespace control characters from statement\n if (hasLeftStrip) {\n statement = statement.substring(1).trim()\n // Strip trailing whitespace from previous text node\n if (ast.length > 0 && ast[ast.length - 1].type === 'text') {\n const lastNode = ast[ast.length - 1] as { type: 'text'; value: string }\n lastNode.value = lastNode.value.replace(/[ \\t]*\\n[ \\t\\n]*$/, '')\n }\n }\n if (hasRightStrip) {\n statement = statement.substring(0, statement.length - 1).trim()\n }\n\n advance(2) // Skip %}\n\n // If right strip, consume following whitespace\n if (hasRightStrip) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) {\n advance(1)\n }\n }\n\n // Parse different statement types\n if (statement.startsWith('set ')) {\n // {% set var = value %}\n const setMatch = /^set\\s+(\\w+)\\s*=\\s*(.+)$/.exec(statement)\n if (setMatch) {\n try {\n const expr = parseExpression(setMatch[2])\n\n ast.push({\n type: 'set',\n name: setMatch[1],\n value: expr,\n })\n } catch (error) {\n errors.push(createError(`Invalid set expression: ${(error as Error).message}`))\n }\n } else {\n errors.push(createError('Invalid set syntax'))\n }\n } else if (statement.startsWith('if ')) {\n // {% if condition %} ... {% elif %} ... {% else %} ... {% endif %}\n const condition = statement.substring(3).trim()\n\n try {\n const expr = parseExpression(condition)\n\n // Find the body and elif/else/endif blocks\n const { trueBranch, elifBranches, elseBranch, parseErrors } = parseIfBlock()\n errors.push(...parseErrors)\n\n ast.push({\n type: 'if',\n condition: expr,\n trueBranch,\n elifBranches: elifBranches.length > 0 ? elifBranches : undefined,\n elseBranch: elseBranch.length > 0 ? elseBranch : undefined,\n })\n } catch (error) {\n errors.push(createError(`Invalid if expression: ${(error as Error).message}`))\n }\n } else if (statement.startsWith('include ')) {\n // {% include \"path\" %}\n const includeMatch = /^include\\s+[\"']([^\"']+)[\"']/.exec(statement)\n if (includeMatch) {\n ast.push({\n type: 'include',\n path: includeMatch[1],\n })\n } else {\n errors.push(createError('Invalid include syntax'))\n }\n } else if (statement.startsWith('switch ')) {\n // {% switch variable %} ... {% case \"value\" %} ... {% endswitch %}\n const switchExpr = statement.substring(7).trim()\n\n try {\n const expr = parseExpression(switchExpr)\n const { cases, parseErrors } = parseSwitchBlock()\n errors.push(...parseErrors)\n\n ast.push({\n type: 'switch',\n expression: expr,\n cases,\n })\n } catch (error) {\n errors.push(createError(`Invalid switch expression: ${(error as Error).message}`))\n }\n } else if (statement.startsWith('leveloffset ')) {\n // {% leveloffset +1 %} or {% leveloffset 2 %} or {% leveloffset -1 %}\n const offsetMatch = /^leveloffset\\s+([-+]?\\d+)$/.exec(statement)\n\n if (!offsetMatch) {\n errors.push(createError('Invalid leveloffset syntax'))\n } else {\n const offsetStr = offsetMatch[1]\n const isRelative = offsetStr.startsWith('+') || offsetStr.startsWith('-')\n const offset = parseInt(offsetStr, 10)\n\n if (isNaN(offset)) {\n errors.push(createError('Invalid leveloffset value'))\n } else {\n // Find matching endleveloffset accounting for nesting\n let depth = 0\n let searchPos = position\n let endPos = -1\n\n while (searchPos < template.length) {\n const leveloffsetMatch = /{%-?\\s*leveloffset\\s+[-+]?\\d+\\s*-?%}/.exec(template.substring(searchPos))\n const endleveloffsetMatch = /{%-?\\s*endleveloffset\\s*-?%}/.exec(template.substring(searchPos))\n\n const leveloffsetPos = leveloffsetMatch ? searchPos + leveloffsetMatch.index : Infinity\n const endleveloffsetPos = endleveloffsetMatch ? searchPos + endleveloffsetMatch.index : Infinity\n\n if (leveloffsetPos < endleveloffsetPos) {\n // Found nested leveloffset\n depth++\n searchPos = leveloffsetPos + (leveloffsetMatch?.[0].length || 0)\n } else if (endleveloffsetPos < Infinity) {\n // Found endleveloffset\n if (depth === 0) {\n // This is our matching endleveloffset\n endPos = endleveloffsetPos\n break\n } else {\n depth--\n searchPos = endleveloffsetPos + (endleveloffsetMatch?.[0].length || 0)\n }\n } else {\n // No more tags found\n break\n }\n }\n\n if (endPos === -1) {\n errors.push(createError('Missing endleveloffset'))\n } else {\n const bodyTemplate = extractTo(endPos)\n // Find and skip the endleveloffset tag\n const endMatch = /{%-?\\s*endleveloffset\\s*-?%}/.exec(template.substring(position))\n if (endMatch) {\n advance(endMatch[0].length)\n }\n\n const bodyResult = parse(bodyTemplate)\n errors.push(...bodyResult.errors)\n\n ast.push({\n type: 'leveloffset',\n offset,\n isRelative,\n body: bodyResult.ast,\n })\n }\n }\n }\n }\n // Ignore endif, endswitch, case, endleveloffset, etc. - they're handled by their opening tags\n }\n }\n\n return { ast, errors }\n\n /**\n * Find an end tag like {% endif %}\n */\n function findEndTag(tagName: string): { start: number; length: number; tag: string } | null {\n // `-?` on BOTH sides: without it this could not match `{%- endif %}`, so an\n // `{% else %}` branch closed with a whitespace-controlled endif failed to\n // parse at all \u2014 the page threw \"Missing endif after else\" and the build\n // preprocessor copied it through UNRENDERED, variables and directives and\n // all. Three OpenShift pages were shipping that way.\n const pattern = new RegExp(`{%-?\\\\s*${tagName}\\\\s*-?%}`)\n const match = pattern.exec(template.substring(position))\n\n if (match) {\n return {\n start: position + match.index,\n length: match[0].length,\n tag: match[0],\n }\n }\n\n return null\n }\n\n /**\n * Parse an if block with elif and else support\n */\n function parseIfBlock(): {\n trueBranch: ASTNode[]\n elifBranches: Array<{ condition: import('./types.js').Expression; body: ASTNode[] }>\n elseBranch: ASTNode[]\n parseErrors: ParseError[]\n } {\n const elifBranches: Array<{ condition: import('./types.js').Expression; body: ASTNode[] }> = []\n const parseErrors: ParseError[] = []\n let elseBranch: ASTNode[] = []\n\n // Find the next elif, else, or endif\n let depth = 0\n let searchPos = position\n\n while (searchPos < template.length) {\n const ifMatch = /{%-?\\s*if\\s+/.exec(template.substring(searchPos))\n const elifMatch = /{%-?\\s*elif\\s+/.exec(template.substring(searchPos))\n const elseMatch = /{%-?\\s*else\\s*-?%}/.exec(template.substring(searchPos))\n const endifMatch = /{%-?\\s*endif\\s*-?%}/.exec(template.substring(searchPos))\n\n // Find the nearest match\n const matches = [\n { type: 'if', match: ifMatch, pos: ifMatch ? searchPos + ifMatch.index : Infinity },\n { type: 'elif', match: elifMatch, pos: elifMatch ? searchPos + elifMatch.index : Infinity },\n { type: 'else', match: elseMatch, pos: elseMatch ? searchPos + elseMatch.index : Infinity },\n { type: 'endif', match: endifMatch, pos: endifMatch ? searchPos + endifMatch.index : Infinity },\n ].sort((a, b) => a.pos - b.pos)\n\n const nearest = matches[0]\n\n if (!nearest.match || nearest.pos === Infinity) {\n parseErrors.push(createError('Missing endif'))\n break\n }\n\n if (nearest.type === 'if') {\n depth++\n searchPos = nearest.pos + nearest.match[0].length\n } else if (nearest.type === 'endif') {\n if (depth === 0) {\n // This is our endif\n const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0])\n advance(nearest.match[0].length)\n if (nearest.match[0].endsWith('-%}')) {\n while (position < template.length && /[ \\t\\n]/.test(template[position])) advance(1)\n }\n\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n\n return {\n trueBranch: bodyResult.ast,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n } else {\n depth--\n searchPos = nearest.pos + nearest.match[0].length\n }\n } else if (depth === 0 && (nearest.type === 'elif' || nearest.type === 'else')) {\n // Parse the body before elif/else\n const bodyTemplate = stripBodyForEndTag(extractTo(nearest.pos), nearest.match[0])\n const bodyResult = parse(bodyTemplate)\n\n if (elifBranches.length === 0 && elseBranch.length === 0) {\n // This is the trueBranch (before first elif/else)\n parseErrors.push(...bodyResult.errors)\n const trueBranch = bodyResult.ast\n\n // Now handle elif or else\n if (nearest.type === 'elif') {\n // Extract elif condition\n advance(nearest.match[0].length)\n const condMatch = /^([^%]+)%}/.exec(template.substring(position))\n if (condMatch) {\n const condStr = condMatch[1].trim()\n advance(condMatch[0].length)\n\n try {\n const elifCondition = parseExpression(condStr)\n const elifResult = parseIfBlock()\n parseErrors.push(...elifResult.parseErrors)\n\n elifBranches.push({\n condition: elifCondition,\n body: elifResult.trueBranch,\n })\n elifBranches.push(...(elifResult.elifBranches || []))\n elseBranch = elifResult.elseBranch\n\n return {\n trueBranch,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n } catch (error) {\n parseErrors.push(createError(`Invalid elif expression: ${(error as Error).message}`))\n }\n }\n } else {\n // else\n advance(nearest.match[0].length)\n\n // Find endif for else block\n const endifMatch = findEndTag('endif')\n if (!endifMatch) {\n parseErrors.push(createError('Missing endif after else'))\n } else {\n const elseBodyTemplate = stripBodyForEndTag(\n extractTo(endifMatch.start),\n endifMatch.tag,\n )\n advance(endifMatch.length)\n\n const elseBodyResult = parse(elseBodyTemplate)\n parseErrors.push(...elseBodyResult.errors)\n elseBranch = elseBodyResult.ast\n }\n\n return {\n trueBranch,\n elifBranches,\n elseBranch,\n parseErrors,\n }\n }\n }\n } else {\n searchPos = nearest.pos + nearest.match[0].length\n }\n }\n\n return {\n trueBranch: [],\n elifBranches,\n elseBranch,\n parseErrors,\n }\n }\n\n /**\n * Parse a switch block with case support\n */\n function parseSwitchBlock(): {\n cases: Array<{ value: import('./types.js').Expression; body: ASTNode[] }>\n parseErrors: ParseError[]\n } {\n const cases: Array<{ value: import('./types.js').Expression; body: ASTNode[] }> = []\n const parseErrors: ParseError[] = []\n\n while (position < template.length) {\n // Find the next case or endswitch\n const caseMatch = /{%-?\\s*case\\s+/.exec(template.substring(position))\n const endswitchMatch = /{%-?\\s*endswitch\\s*-?%}/.exec(template.substring(position))\n\n // Find which comes first\n const casePos = caseMatch ? position + caseMatch.index : Infinity\n const endswitchPos = endswitchMatch ? position + endswitchMatch.index : Infinity\n\n if (endswitchPos < casePos) {\n // Found endswitch before any case (or no case)\n // Parse any remaining content before endswitch as the last case body\n if (cases.length > 0 && position < endswitchPos) {\n const bodyTemplate = extractTo(endswitchPos)\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n cases[cases.length - 1].body = bodyResult.ast\n }\n\n // Skip endswitch\n advance(endswitchPos - position + (endswitchMatch?.[0].length || 0))\n break\n } else if (casePos < Infinity) {\n // Found a case\n // If there's a previous case, parse its body\n if (cases.length > 0 && position < casePos) {\n const bodyTemplate = extractTo(casePos)\n const bodyResult = parse(bodyTemplate)\n parseErrors.push(...bodyResult.errors)\n cases[cases.length - 1].body = bodyResult.ast\n } else if (position < casePos) {\n // Content before first case - skip it\n extractTo(casePos)\n }\n\n // Parse the case value\n advance(caseMatch![0].length)\n\n // Extract the case value (until %})\n const valueMatch = /([^%]+)%}/.exec(template.substring(position))\n if (valueMatch) {\n const valueStr = valueMatch[1].trim()\n advance(valueMatch[0].length)\n\n try {\n const caseValue = parseExpression(valueStr)\n cases.push({\n value: caseValue,\n body: [], // Will be filled in next iteration or at endswitch\n })\n } catch (error) {\n parseErrors.push(createError(`Invalid case value: ${(error as Error).message}`))\n }\n } else {\n parseErrors.push(createError('Invalid case syntax'))\n break\n }\n } else {\n // No case or endswitch found\n parseErrors.push(createError('Missing endswitch'))\n break\n }\n }\n\n return { cases, parseErrors }\n }\n}\n", "/**\n * Context management for variable scoping\n * Supports nested scopes with inheritance\n */\n\nimport type { IContext } from './types.js'\n\nexport interface ContextOptions {\n /**\n * Convert hyphenated variable names to underscores during lookup.\n */\n hyphenToUnderscore?: boolean\n}\n\nexport class Context implements IContext {\n private variables: Map<string, unknown>\n private parent: Context | null\n private options: ContextOptions\n\n constructor(parent?: Context, options?: ContextOptions) {\n this.variables = new Map()\n this.parent = parent || null\n this.options = options || parent?.options || {}\n }\n\n /**\n * Get a variable from the context (supports dot notation)\n * @param name - Variable name (can use dot notation like \"obj.prop.subprop\")\n * @returns The variable value or undefined\n */\n get(name: string): unknown {\n // Convert hyphens to underscores if option is enabled\n const normalizedName = this.options.hyphenToUnderscore\n ? name.replace(/-/g, '_')\n : name\n\n const parts = normalizedName.split('.')\n const rootName = parts[0]\n\n // Look up the root variable in current scope or parent scopes\n let value: unknown\n if (this.variables.has(rootName)) {\n value = this.variables.get(rootName)\n } else if (this.parent) {\n value = this.parent.get(rootName)\n } else {\n return undefined\n }\n\n // Navigate nested properties\n for (let i = 1; i < parts.length; i++) {\n if (value === null || value === undefined) {\n return undefined\n }\n\n // Only allow property access on plain objects (prevent prototype pollution)\n if (typeof value !== 'object' || Array.isArray(value)) {\n return undefined\n }\n\n // Prevent access to prototype chain\n if (!Object.prototype.hasOwnProperty.call(value, parts[i])) {\n return undefined\n }\n\n value = (value as Record<string, unknown>)[parts[i]]\n }\n\n return value\n }\n\n /**\n * Set a variable in the current context\n * @param name - Variable name (can use dot notation)\n * @param value - Value to set\n */\n set(name: string, value: unknown): void {\n const parts = name.split('.')\n\n if (parts.length === 1) {\n // Simple assignment\n this.variables.set(name, value)\n return\n }\n\n // Nested assignment - navigate to parent object\n const rootName = parts[0]\n let target = this.variables.get(rootName) as Record<string, unknown> | undefined\n\n if (!target || typeof target !== 'object' || Array.isArray(target)) {\n // Create new object if root doesn't exist or isn't an object\n target = {}\n this.variables.set(rootName, target)\n }\n\n // Navigate to the parent of the target property\n for (let i = 1; i < parts.length - 1; i++) {\n const key = parts[i]\n\n if (\n !target[key] ||\n typeof target[key] !== 'object' ||\n Array.isArray(target[key])\n ) {\n target[key] = {}\n }\n\n target = target[key] as Record<string, unknown>\n }\n\n // Set the final property\n target[parts[parts.length - 1]] = value\n }\n\n /**\n * Create a child scope\n * @returns A new Context with this context as parent\n */\n push(): Context {\n return new Context(this, this.options)\n }\n\n /**\n * Return to parent scope\n * @returns The parent context or null if at root\n */\n pop(): Context | null {\n return this.parent\n }\n\n /**\n * Create a context from a plain object\n * @param data - Plain object to convert to context\n * @param options - Context options\n * @returns New Context instance\n */\n static from(data: Record<string, unknown>, options?: ContextOptions): Context {\n const ctx = new Context(undefined, options)\n for (const [key, value] of Object.entries(data)) {\n ctx.set(key, value)\n }\n return ctx\n }\n}\n", "/**\n * Fetch-based loader for browsers and service workers\n */\n\nimport type { Loader } from './types.js'\n\nexport class FetchLoader implements Loader {\n async load(path: string, basePath?: string): Promise<string> {\n const url = basePath ? new URL(path, basePath).href : path\n const fetchUrl = `${url}?preventCache=${Date.now()}`\n\n const response = await fetch(fetchUrl)\n\n if (!response.ok) {\n throw new Error(`Failed to load ${url}: ${response.status} ${response.statusText}`)\n }\n\n return await response.text()\n }\n}\n", "/**\n * Template renderer\n * Combines parser, evaluator, and loader to render templates\n */\n\nimport type { ASTNode, Expression, RenderOptions, Loader } from './types.js'\nimport { parse } from './parser.js'\nimport { Context } from './context.js'\nimport { evaluateExpression } from './evaluator.js'\nimport { FetchLoader } from './loader-fetch.js'\n\n/**\n * Transform markdown headings by applying level offset\n * Clamps to valid markdown range (1-6)\n * @param text - Text content to transform\n * @param offset - Level offset to apply\n * @returns Transformed text with adjusted heading levels\n */\nfunction transformHeadings(\n text: string,\n offset: number,\n initialFence: string | null = null,\n fenceOut?: { fence: string | null },\n): string {\n if (offset === 0) {\n if (fenceOut) fenceOut.fence = initialFence\n return text\n }\n\n // Fence-aware: only shift ATX headings that are NOT inside a fenced code\n // block. A line-anchored regex would otherwise rewrite `# oc get pods`\n // (a shell prompt / comment) inside a ```terminal block to `## \u2026`,\n // mutating code-block content \u2014 which the no-code-block-mutation rule\n // forbids. Issue #020 / task #404.\n const lines = text.split('\\n')\n // Fence state CARRIES ACROSS text nodes: a directive inside a listing\n // splits the template into several text nodes, and restarting the state\n // per node lost the open fence \u2014 `#` comments at column 0 inside the\n // second half were shifted to `###` (issue #043, managing-ce's\n // ClusterRole manifest; the same class as issue #020).\n let fence: string | null = initialFence // active opening fence run (e.g. \"```\") while inside a code block\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n const fenceMatch = line.match(/^\\s*(`{3,}|~{3,})/)\n if (fenceMatch) {\n const run = fenceMatch[1]\n if (fence === null) {\n // Opening fence (an info string may follow on this line).\n fence = run\n } else if (run[0] === fence[0] && run.length >= fence.length && line.trim() === run) {\n // Closing fence: bare marker, same char, length >= opening (CommonMark).\n fence = null\n }\n continue // never treat a fence line as a heading\n }\n if (fence !== null) {\n continue // inside a code block \u2014 leave the line verbatim\n }\n const m = line.match(/^(#{1,6})(\\s+)/)\n if (m) {\n const newLevel = Math.max(1, Math.min(6, m[1].length + offset))\n lines[i] = '#'.repeat(newLevel) + line.slice(m[1].length)\n }\n }\n if (fenceOut) fenceOut.fence = fence\n return lines.join('\\n')\n}\n\n/**\n * Resolve a relative path against a base path\n * @param path - Relative or absolute path\n * @param basePath - Base path to resolve against\n * @returns Resolved path\n */\nfunction resolvePath(path: string, basePath: string): string {\n // If path is absolute, return as-is\n if (path.startsWith('/')) {\n return path\n }\n\n // Ensure basePath ends with /\n const base = basePath.endsWith('/') ? basePath : basePath + '/'\n\n // Combine and normalize\n const combined = base + path\n\n // Normalize . and .. segments\n const parts = combined.split('/')\n const resolved: string[] = []\n\n for (const part of parts) {\n if (part === '.' || part === '') {\n continue\n } else if (part === '..') {\n resolved.pop()\n } else {\n resolved.push(part)\n }\n }\n\n // Preserve leading slash if original had one\n const prefix = combined.startsWith('/') ? '/' : ''\n return prefix + resolved.join('/')\n}\n\n/**\n * Render a template string\n * @param template - Template string to render\n * @param options - Render options\n * @returns Rendered output\n */\nexport async function render(template: string, options: RenderOptions = {}): Promise<string> {\n const {\n loader = new FetchLoader(),\n context: initialContext = {},\n basePath = '',\n maxIncludeDepth = 10,\n timeout = 5000,\n hyphenToUnderscore = false,\n undefinedBehavior = 'empty',\n undefinedConditions = 'preserve',\n } = options\n\n // Create timeout promise\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => reject(new Error('Template rendering timeout')), timeout)\n })\n\n // Render with timeout\n const renderPromise = renderInternal(template, {\n loader,\n context: Context.from(\n {\n ...initialContext,\n // Built-in variables\n date: new Date().toISOString().split('T')[0],\n timestamp: Date.now(),\n _levelOffset: 0,\n },\n { hyphenToUnderscore }\n ),\n includeDepth: 0,\n maxIncludeDepth,\n basePath,\n undefinedBehavior,\n undefinedConditions,\n })\n\n return await Promise.race([renderPromise, timeoutPromise])\n}\n\ninterface InternalRenderOptions {\n loader: Loader\n context: Context\n includeDepth: number\n maxIncludeDepth: number\n basePath: string\n undefinedBehavior: 'empty' | 'throw' | 'preserve' | 'asciidoc-literal'\n undefinedConditions: 'preserve' | 'falsy'\n}\n\n/**\n * Internal rendering function with depth tracking\n */\nasync function renderInternal(\n template: string,\n options: InternalRenderOptions\n): Promise<string> {\n const { includeDepth, maxIncludeDepth } = options\n\n // Check recursion depth\n if (includeDepth > maxIncludeDepth) {\n throw new Error(`Maximum include depth (${maxIncludeDepth}) exceeded`)\n }\n\n // Parse template\n const parseResult = parse(template)\n\n if (parseResult.errors.length > 0) {\n const errorMessages = parseResult.errors.map((e) => e.message).join(', ')\n throw new Error(`Parse errors: ${errorMessages}`)\n }\n\n // Render AST\n return await renderNodes(parseResult.ast, options)\n}\n\n/**\n * Render an array of AST nodes\n */\nasync function renderNodes(nodes: ASTNode[], options: InternalRenderOptions): Promise<string> {\n const parts: string[] = []\n\n for (const node of nodes) {\n let rendered = await renderNode(node, options)\n // An {% include %} that sits alone on an INDENTED line splices content\n // into that indentation context (a list item, an open block in a step):\n // re-indent every non-empty spliced line to the directive's own column.\n // Verbatim splicing put included bullets/fences at column 0 inside a\n // level-2 step, shattering the list and orphaning everything after\n // (the \":::important in a code block\" class, cnf-image-based-upgrade).\n // Top-level includes have no leading indent and are untouched.\n if (node.type === 'include' && rendered && parts.length > 0) {\n const tail = /(?:^|\\n)([ \\t]+)$/.exec(parts[parts.length - 1])\n if (tail) {\n rendered = rendered.replace(/\\n(?=[^\\n])/g, '\\n' + tail[1])\n }\n }\n parts.push(rendered)\n }\n\n return parts.join('')\n}\n\n/**\n * Render a single AST node\n */\nasync function renderNode(node: ASTNode, options: InternalRenderOptions): Promise<string> {\n const { loader, context, includeDepth, maxIncludeDepth, basePath } = options\n\n switch (node.type) {\n case 'text': {\n // Apply leveloffset if active\n const currentOffset = context.get('_levelOffset') as number || 0\n if (currentOffset === 0) {\n return node.value\n }\n const fenceOut = { fence: null as string | null }\n const out = transformHeadings(\n node.value,\n currentOffset,\n (context.get('_levelOffsetFence') as string | null) ?? null,\n fenceOut,\n )\n context.set('_levelOffsetFence', fenceOut.fence)\n return out\n }\n\n case 'variable': {\n const value = context.get(node.name)\n if (value === undefined || value === null) {\n // Apply the undefined-variable policy. See RenderOptions.undefinedBehavior.\n switch (options.undefinedBehavior) {\n case 'throw':\n throw new Error(`Undefined variable: ${node.name}`)\n case 'preserve':\n // Round-trip the source form so downstream tooling (or a\n // second-pass minja run with the value supplied) can pick\n // up where we left off.\n return `{{ ${node.name} }}`\n case 'asciidoc-literal':\n // Terminal build of an AsciiDoc-migrated corpus: every ref\n // came from an `{name}` attribute reference, so an\n // unresolvable one is a literal placeholder \u2014 render what\n // asciidoctor renders for an undefined attribute.\n return `{${node.name}}`\n case 'empty':\n default:\n return ''\n }\n }\n const str = String(value)\n // If the value contains template syntax, re-process it\n if (str.includes('{{') || str.includes('{%')) {\n return await renderInternal(str, options)\n }\n return str\n }\n\n case 'set': {\n const value = evaluateExpression(node.value, context)\n context.set(node.name, value)\n return ''\n }\n\n case 'comment':\n return ''\n\n case 'if': {\n // In preserve mode, an `if` whose condition references an\n // undefined identifier can't be evaluated \u2014 we don't know\n // which branch to take. Preserve the whole `{% if \u2026 %}\u2026{% endif %}`\n // verbatim so a second pass (with the value supplied) can\n // resolve it. See plans/format-asciidoc-import.md.\n //\n // Except when `undefinedConditions === 'falsy'`: this is a\n // terminal build with no later pass, so treat the undefined\n // reference as falsy (AsciiDoc `ifdef::attr[]` semantics) and\n // evaluate now rather than leak the directive to readers.\n if ((options.undefinedBehavior === 'preserve' || options.undefinedBehavior === 'asciidoc-literal') && options.undefinedConditions !== 'falsy') {\n const undefinedRefs = findUndefinedRefs(node.condition, context)\n if (undefinedRefs.length > 0) {\n return ifNodeToSource(node)\n }\n if (node.elifBranches) {\n for (const elif of node.elifBranches) {\n if (findUndefinedRefs(elif.condition, context).length > 0) {\n return ifNodeToSource(node)\n }\n }\n }\n }\n\n const condition = evaluateExpression(node.condition, context)\n\n if (isTruthy(condition)) {\n return await renderNodes(node.trueBranch, options)\n }\n\n // Check elif branches\n if (node.elifBranches) {\n for (const elifBranch of node.elifBranches) {\n const elifCondition = evaluateExpression(elifBranch.condition, context)\n if (isTruthy(elifCondition)) {\n return await renderNodes(elifBranch.body, options)\n }\n }\n }\n\n // Render else branch if present\n if (node.elseBranch) {\n return await renderNodes(node.elseBranch, options)\n }\n\n return ''\n }\n\n case 'include': {\n try {\n // Load the included file\n const includedContent = await loader.load(node.path, basePath)\n\n // Determine new base path for nested includes\n let newBasePath = basePath\n\n // If path looks like a URL, extract base\n if (node.path.includes('://')) {\n const url = new URL(node.path)\n newBasePath = url.href.substring(0, url.href.lastIndexOf('/') + 1)\n } else if (basePath) {\n // Relative path - resolve against current base\n if (basePath.includes('://')) {\n const url = new URL(node.path, basePath)\n newBasePath = url.href.substring(0, url.href.lastIndexOf('/') + 1)\n } else {\n // File path - resolve relative to current base and extract directory\n const resolvedPath = resolvePath(node.path, basePath)\n const lastSlash = resolvedPath.lastIndexOf('/')\n newBasePath = lastSlash >= 0 ? resolvedPath.substring(0, lastSlash + 1) : basePath\n }\n } else if (node.path.includes('/')) {\n // No base path but include has directory - use that as base\n const lastSlash = node.path.lastIndexOf('/')\n newBasePath = node.path.substring(0, lastSlash + 1)\n }\n\n // Render the included template (recursive)\n return await renderInternal(includedContent, {\n loader,\n context,\n includeDepth: includeDepth + 1,\n maxIncludeDepth,\n basePath: newBasePath,\n undefinedBehavior: options.undefinedBehavior,\n undefinedConditions: options.undefinedConditions,\n })\n } catch (error) {\n // A containment refusal is a SECURITY event, not a missing file:\n // neither preserved for a later pass (no later pass may resolve\n // it) nor degraded to a comment \u2014 the render fails hard (#027).\n if (error instanceof Error && error.name === 'IncludeContainmentError') {\n throw error\n }\n // In `preserve` mode, an unresolvable include is preserved\n // as the original directive so a later renderer pass (with\n // the file in place) can resolve it. Matches the semantic\n // of `preserve` for undefined variables. Without this,\n // multi-stage pipelines (e.g. dogsbay's convert + build\n // preprocessor for AsciiDoc imports) lose the directive at\n // stage 1 because targets only exist after stage 2 has\n // converted sibling files.\n if (options.undefinedBehavior === 'preserve' || options.undefinedBehavior === 'asciidoc-literal') {\n return `{% include \"${node.path}\" %}`\n }\n const message = error instanceof Error ? error.message : String(error)\n console.error(`Failed to include ${node.path}:`, message)\n return `<!-- Include error: ${node.path} -->`\n }\n }\n\n case 'switch': {\n const switchValue = evaluateExpression(node.expression, context)\n\n // Find matching case\n for (const caseItem of node.cases) {\n const caseValue = evaluateExpression(caseItem.value, context)\n // eslint-disable-next-line eqeqeq\n if (switchValue == caseValue) {\n return await renderNodes(caseItem.body, options)\n }\n }\n\n // No matching case found\n return ''\n }\n\n case 'leveloffset': {\n // Calculate new offset (relative or absolute)\n const parentOffset = context.get('_levelOffset') as number || 0\n const newOffset = node.isRelative ? parentOffset + node.offset : node.offset\n\n // Store current offset to restore later\n const previousOffset = parentOffset\n\n // Set new offset in context\n context.set('_levelOffset', newOffset)\n // Fresh scope: a fence left open by unrelated earlier content must\n // not suppress heading shifts here. Save the outer state so a NESTED\n // leveloffset sitting inside an open fence doesn't wipe it \u2014 without\n // the restore, the outer fence's real closer was later mis-read as an\n // opener, flipping fence state for the rest of the render.\n const previousFence = context.get('_levelOffsetFence') ?? null\n context.set('_levelOffsetFence', null)\n\n try {\n // Render body with offset active\n const result = await renderNodes(node.body, options)\n return result\n } finally {\n // Always restore previous offset + the outer fence state\n context.set('_levelOffset', previousOffset)\n context.set('_levelOffsetFence', previousFence)\n }\n }\n\n default:\n // TypeScript exhaustiveness check\n const _exhaustive: never = node\n return _exhaustive\n }\n}\n\n/**\n * Determine if a value is truthy\n */\nfunction isTruthy(value: unknown): boolean {\n if (value === undefined || value === null || value === false) {\n return false\n }\n if (value === 0 || value === '') {\n return false\n }\n return true\n}\n\n// ============================================================================\n// Preserve-mode helpers \u2014 round-trip AST back to Jinja source so an\n// undefined-referencing block can survive into the rendered output for\n// a downstream pass to resolve.\n// ============================================================================\n\n/**\n * Walk an expression AST, return the names of any `variable` references\n * whose context lookup is undefined. Empty array = all refs are bound.\n */\nfunction findUndefinedRefs(expr: Expression, context: Context): string[] {\n const out: string[] = []\n function walk(e: Expression): void {\n switch (e.type) {\n case 'variable':\n if (context.get(e.name) === undefined) out.push(e.name)\n break\n case 'binary':\n walk(e.left)\n walk(e.right)\n break\n case 'unary':\n walk(e.operand)\n break\n case 'literal':\n break\n }\n }\n walk(expr)\n return out\n}\n\n/**\n * Serialize an Expression back to Jinja source. Used by preserve mode\n * to reconstruct `{% if \u2026 %}` headers when the condition can't be\n * evaluated. Operator precedence isn't tracked; the output is\n * conservatively parenthesized for binary/unary so a re-parse round-\n * trips to the same AST shape (modulo redundant parens).\n */\nfunction expressionToSource(expr: Expression): string {\n switch (expr.type) {\n case 'literal':\n if (typeof expr.value === 'string') return JSON.stringify(expr.value)\n if (expr.value === null) return 'null'\n return String(expr.value)\n case 'variable':\n return expr.name\n case 'unary':\n return `not ${expressionToSource(expr.operand)}`\n case 'binary':\n return `(${expressionToSource(expr.left)} ${expr.operator} ${expressionToSource(expr.right)})`\n }\n}\n\n/**\n * Serialize ASTNode[] back to Jinja source. Mirrors the parser's syntax\n * for every node type so a preserved block can be re-rendered later\n * with the missing values supplied.\n *\n * Throws on shapes we don't support (deep nested includes, switch);\n * preserve mode is opt-in and a hard error here beats silent\n * truncation. The shapes covered are everything md2md emits in the\n * AsciiDoc pipeline.\n */\nfunction nodesToSource(nodes: ASTNode[]): string {\n return nodes.map(nodeToSource).join('')\n}\n\nfunction nodeToSource(node: ASTNode): string {\n switch (node.type) {\n case 'text':\n return node.value\n case 'variable':\n return `{{ ${node.name} }}`\n case 'set':\n return `{% set ${node.name} = ${expressionToSource(node.value)} %}`\n case 'comment':\n // Parser strips comment content; emit a placeholder so the block\n // structure round-trips even when the prose inside doesn't.\n return '{# \u2026 #}'\n case 'if':\n return ifNodeToSource(node)\n case 'include':\n return `{% include \"${node.path}\" %}`\n case 'leveloffset': {\n const sign = node.isRelative && node.offset >= 0 ? '+' : ''\n return `{% leveloffset ${sign}${node.offset} %}${nodesToSource(node.body)}{% endleveloffset %}`\n }\n case 'switch': {\n // Conservative round-trip; switch isn't on the AsciiDoc hot path\n // but we have an AST shape, so emit it.\n const cases = node.cases\n .map((c) => `{% case ${expressionToSource(c.value)} %}${nodesToSource(c.body)}`)\n .join('')\n return `{% switch ${expressionToSource(node.expression)} %}${cases}{% endswitch %}`\n }\n }\n}\n\nfunction ifNodeToSource(node: Extract<ASTNode, { type: 'if' }>): string {\n const parts = [`{% if ${expressionToSource(node.condition)} %}`, nodesToSource(node.trueBranch)]\n if (node.elifBranches) {\n for (const elif of node.elifBranches) {\n parts.push(`{% elif ${expressionToSource(elif.condition)} %}`, nodesToSource(elif.body))\n }\n }\n if (node.elseBranch) {\n parts.push(`{% else %}`, nodesToSource(node.elseBranch))\n }\n parts.push(`{% endif %}`)\n return parts.join('')\n}\n", "/**\n * Memory-based loader for testing\n */\n\nimport type { Loader } from './types.js'\n\nexport class MemoryLoader implements Loader {\n private files: Map<string, string>\n\n constructor(files: Record<string, string> = {}) {\n this.files = new Map(Object.entries(files))\n }\n\n addFile(path: string, content: string): void {\n this.files.set(path, content)\n }\n\n async load(path: string, basePath?: string): Promise<string> {\n // Resolve path with normalization of . and .. segments\n const combined = basePath && !path.startsWith('/')\n ? `${basePath}/${path}`\n : path\n\n const parts = combined.split('/')\n const normalized: string[] = []\n for (const part of parts) {\n if (part === '.' || part === '') continue\n if (part === '..') { normalized.pop(); continue }\n normalized.push(part)\n }\n const prefix = combined.startsWith('/') ? '/' : ''\n const resolvedPath = prefix + normalized.join('/')\n\n const content = this.files.get(resolvedPath)\n\n if (content === undefined) {\n throw new Error(`File not found: ${resolvedPath}`)\n }\n\n return content\n }\n}\n", "/**\n * Scanning-grammar mirrors of parser statements, for tools that need to\n * FIND directives in raw text without running the full parser (workspace\n * indexers, linters). Kept next to the parser so grammar changes update\n * both; tests/scan.test.ts asserts parser agreement for every form the\n * scan regex matches.\n */\n\n/**\n * Fresh regex matching a complete `{% include \"path\" %}` statement,\n * capturing the path. Factory (not a shared const) because the global\n * flag makes RegExp objects stateful.\n *\n * Grammar notes, matching parser.ts:\n * - `{%-` / `-%}` whitespace-trim markers are accepted.\n * - At least one whitespace character is required after `include`.\n * - The path is quoted with `\"` or `'` and contains no quote chars.\n */\nexport const includeDirectiveRe = (): RegExp =>\n /\\{%-?\\s*include\\s+[\"']([^\"']+)[\"']\\s*-?%\\}/g;\n\n/** All `{% include %}` paths in a text, in order. */\nexport const scanIncludes = (text: string): string[] =>\n [...text.matchAll(includeDirectiveRe())].map((match) => match[1]);\n\n/**\n * Fresh regex matching a complete `{{ \u2026 }}` variable/expression output,\n * capturing the raw inner source (whitespace-trim markers accepted, not\n * captured). Grammar mirror of parser.ts's `{{`\u2192`}}` scan.\n */\nexport const variableRe = (): RegExp => /\\{\\{-?([\\s\\S]*?)-?\\}\\}/g;\n\n/**\n * Fresh regex matching a complete `{% \u2026 %}` statement tag, capturing the\n * keyword and the raw remainder (up to the closing marker). Grammar mirror\n * of parser.ts's `{%`\u2192`%}` scan \u2014 the keyword set is NOT validated here;\n * consumers classify (if/elif/else/endif/include/set/\u2026) themselves.\n */\nexport const directiveTagRe = (): RegExp =>\n /\\{%-?\\s*([A-Za-z_][A-Za-z0-9_]*)([\\s\\S]*?)-?%\\}/g;\n\n/**\n * Fresh regex matching a complete `{# \u2026 #}` comment. Grammar mirror of\n * parser.ts's `{#`\u2192`#}` scan.\n */\nexport const commentRe = (): RegExp => /\\{#[\\s\\S]*?#\\}/g;\n\n/**\n * Fresh regex matching a complete `{% raw %}\u2026{% endraw %}` block, capturing\n * the verbatim inner content. Grammar mirror of parser.ts's raw handling.\n * Consumers that classify individual tags (directiveTagRe) should match\n * raw blocks FIRST \u2014 the inner content is not directive syntax.\n */\nexport const rawBlockRe = (): RegExp =>\n /\\{%-?\\s*raw\\s*-?%\\}([\\s\\S]*?)\\{%-?\\s*endraw\\s*-?%\\}/g;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["browser_exports", "__export", "Context", "FetchLoader", "MemoryLoader", "commentRe", "directiveTagRe", "evaluateExpression", "includeDirectiveRe", "parse", "parseExpression", "rawBlockRe", "render", "scanIncludes", "variableRe", "parseExpression", "expr", "depth", "balanced", "i", "orMatch", "findOperator", "andMatch", "comparisonOps", "op", "opMatch", "operator", "inString", "char", "evaluateExpression", "context", "left", "right", "isTruthy", "operand", "value", "KNOWN_TAG_KEYWORDS", "stripBodyForEndTag", "body", "endTag", "parse", "template", "errors", "ast", "position", "line", "column", "createError", "message", "advance", "count", "i", "findNext", "str", "from", "extractTo", "target", "text", "varStart", "tagStart", "commentStart", "candidates", "c", "a", "b", "nearest", "endPos", "varName", "lastNode", "commentText", "peeked", "peekKeyword", "openerLeftStrip", "openerRightStrip", "endrawMatch", "endrawAbs", "content", "endrawTag", "statement", "hasLeftStrip", "hasRightStrip", "setMatch", "expr", "parseExpression", "error", "condition", "trueBranch", "elifBranches", "elseBranch", "parseErrors", "parseIfBlock", "includeMatch", "switchExpr", "cases", "parseSwitchBlock", "offsetMatch", "offsetStr", "isRelative", "offset", "depth", "searchPos", "leveloffsetMatch", "endleveloffsetMatch", "leveloffsetPos", "endleveloffsetPos", "bodyTemplate", "endMatch", "bodyResult", "findEndTag", "tagName", "match", "ifMatch", "elifMatch", "elseMatch", "endifMatch", "condMatch", "condStr", "elifCondition", "elifResult", "elseBodyTemplate", "elseBodyResult", "caseMatch", "endswitchMatch", "casePos", "endswitchPos", "valueMatch", "valueStr", "caseValue", "Context", "_Context", "parent", "options", "name", "parts", "rootName", "value", "i", "target", "key", "data", "ctx", "FetchLoader", "path", "basePath", "url", "fetchUrl", "response", "transformHeadings", "text", "offset", "initialFence", "fenceOut", "lines", "fence", "i", "line", "fenceMatch", "run", "m", "newLevel", "resolvePath", "path", "basePath", "combined", "parts", "resolved", "part", "render", "template", "options", "loader", "FetchLoader", "initialContext", "maxIncludeDepth", "timeout", "hyphenToUnderscore", "undefinedBehavior", "undefinedConditions", "timeoutPromise", "_", "reject", "renderPromise", "renderInternal", "Context", "includeDepth", "parseResult", "parse", "errorMessages", "e", "renderNodes", "nodes", "node", "rendered", "renderNode", "tail", "context", "currentOffset", "out", "value", "str", "evaluateExpression", "findUndefinedRefs", "ifNodeToSource", "elif", "condition", "isTruthy", "elifBranch", "elifCondition", "includedContent", "newBasePath", "url", "resolvedPath", "lastSlash", "error", "message", "switchValue", "caseItem", "caseValue", "parentOffset", "newOffset", "previousOffset", "previousFence", "expr", "walk", "expressionToSource", "nodesToSource", "nodeToSource", "cases", "c", "MemoryLoader", "files", "path", "content", "basePath", "combined", "parts", "normalized", "part", "resolvedPath", "includeDirectiveRe", "scanIncludes", "text", "match", "variableRe", "directiveTagRe", "commentRe", "rawBlockRe"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch-based loader for browsers and service workers
|
|
3
|
+
*/
|
|
4
|
+
import type { Loader } from './types.js';
|
|
5
|
+
export declare class FetchLoader implements Loader {
|
|
6
|
+
load(path: string, basePath?: string): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=loader-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-fetch.d.ts","sourceRoot":"","sources":["../src/loader-fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,qBAAa,WAAY,YAAW,MAAM;IAClC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAY7D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch-based loader for browsers and service workers
|
|
3
|
+
*/
|
|
4
|
+
export class FetchLoader {
|
|
5
|
+
async load(path, basePath) {
|
|
6
|
+
const url = basePath ? new URL(path, basePath).href : path;
|
|
7
|
+
const fetchUrl = `${url}?preventCache=${Date.now()}`;
|
|
8
|
+
const response = await fetch(fetchUrl);
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new Error(`Failed to load ${url}: ${response.status} ${response.statusText}`);
|
|
11
|
+
}
|
|
12
|
+
return await response.text();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=loader-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-fetch.js","sourceRoot":"","sources":["../src/loader-fetch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,OAAO,WAAW;IACtB,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,QAAiB;QACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAC1D,MAAM,QAAQ,GAAG,GAAG,GAAG,iBAAiB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;QAEpD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAA;QAEtC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,kBAAkB,GAAG,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAA;QACrF,CAAC;QAED,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-based loader for testing
|
|
3
|
+
*/
|
|
4
|
+
import type { Loader } from './types.js';
|
|
5
|
+
export declare class MemoryLoader implements Loader {
|
|
6
|
+
private files;
|
|
7
|
+
constructor(files?: Record<string, string>);
|
|
8
|
+
addFile(path: string, content: string): void;
|
|
9
|
+
load(path: string, basePath?: string): Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=loader-memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-memory.d.ts","sourceRoot":"","sources":["../src/loader-memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAExC,qBAAa,YAAa,YAAW,MAAM;IACzC,OAAO,CAAC,KAAK,CAAqB;gBAEtB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;IAI9C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAItC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAwB7D"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory-based loader for testing
|
|
3
|
+
*/
|
|
4
|
+
export class MemoryLoader {
|
|
5
|
+
constructor(files = {}) {
|
|
6
|
+
this.files = new Map(Object.entries(files));
|
|
7
|
+
}
|
|
8
|
+
addFile(path, content) {
|
|
9
|
+
this.files.set(path, content);
|
|
10
|
+
}
|
|
11
|
+
async load(path, basePath) {
|
|
12
|
+
// Resolve path with normalization of . and .. segments
|
|
13
|
+
const combined = basePath && !path.startsWith('/')
|
|
14
|
+
? `${basePath}/${path}`
|
|
15
|
+
: path;
|
|
16
|
+
const parts = combined.split('/');
|
|
17
|
+
const normalized = [];
|
|
18
|
+
for (const part of parts) {
|
|
19
|
+
if (part === '.' || part === '')
|
|
20
|
+
continue;
|
|
21
|
+
if (part === '..') {
|
|
22
|
+
normalized.pop();
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
normalized.push(part);
|
|
26
|
+
}
|
|
27
|
+
const prefix = combined.startsWith('/') ? '/' : '';
|
|
28
|
+
const resolvedPath = prefix + normalized.join('/');
|
|
29
|
+
const content = this.files.get(resolvedPath);
|
|
30
|
+
if (content === undefined) {
|
|
31
|
+
throw new Error(`File not found: ${resolvedPath}`);
|
|
32
|
+
}
|
|
33
|
+
return content;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=loader-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader-memory.js","sourceRoot":"","sources":["../src/loader-memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,OAAO,YAAY;IAGvB,YAAY,QAAgC,EAAE;QAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;IAC7C,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,OAAe;QACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,QAAiB;QACxC,uDAAuD;QACvD,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAChD,CAAC,CAAC,GAAG,QAAQ,IAAI,IAAI,EAAE;YACvB,CAAC,CAAC,IAAI,CAAA;QAER,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACjC,MAAM,UAAU,GAAa,EAAE,CAAA;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,EAAE;gBAAE,SAAQ;YACzC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAAC,UAAU,CAAC,GAAG,EAAE,CAAC;gBAAC,SAAQ;YAAC,CAAC;YACjD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACvB,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QAClD,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAElD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAE5C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAA;QACpD,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;CACF"}
|