@xaendar/compiler 0.3.33 → 0.3.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"xaendar-compiler.es.js","names":[],"sources":["../../../packages/compiler/src/lexer/types/lexer-state.enum.ts","../../../packages/compiler/src/lexer/types/token-type.enum.ts","../../../packages/compiler/src/lexer/states/attribute.state.ts","../../../packages/compiler/src/lexer/utils/consume-flow-control-condition.utils.ts","../../../packages/compiler/src/lexer/states/case-flow-control-condition.state.ts","../../../packages/compiler/src/lexer/states/const-declaration.ts","../../../packages/compiler/src/lexer/states/event.state.ts","../../../packages/compiler/src/lexer/states/flow-control-block.state.ts","../../../packages/compiler/src/lexer/states/default-flow-control-condition.state.ts","../../../packages/compiler/src/lexer/states/flow-control.ts","../../../packages/compiler/src/lexer/states/interpolation-expression.state.ts","../../../packages/compiler/src/lexer/states/interpolation-literal.state.ts","../../../packages/compiler/src/utils/chars.utils.ts","../../../packages/compiler/src/lexer/states/interpolation.state.ts","../../../packages/compiler/src/lexer/states/tag-body.state.ts","../../../packages/compiler/src/lexer/states/tag-close.state.ts","../../../packages/compiler/src/lexer/states/tag-open-end.state.ts","../../../packages/compiler/src/lexer/states/tag-open-name.state.ts","../../../packages/compiler/src/lexer/states/text.state.ts","../../../packages/compiler/src/lexer/types/lexer-cursor.model.ts","../../../packages/compiler/src/lexer/lexer.ts","../../../packages/compiler/src/parser/models/parser-cursor.model.ts","../../../packages/compiler/src/parser/types/node.enum.ts","../../../packages/compiler/src/parser/states/parse-const-declaration.state.ts","../../../packages/compiler/src/parser/states/parse-interpolation.state.ts","../../../packages/compiler/src/parser/states/parse-attribute.state.ts","../../../packages/compiler/src/parser/states/parse-event.state.ts","../../../packages/compiler/src/parser/states/parse-element.state.ts","../../../packages/compiler/src/parser/utils/expression-validator.ts","../../../packages/compiler/src/parser/states/parse-block-children.state.ts","../../../packages/compiler/src/parser/states/parse-for.state.ts","../../../packages/compiler/src/parser/states/parse-if.state.ts","../../../packages/compiler/src/parser/states/parse-switch.state.ts","../../../packages/compiler/src/parser/states/parse-text.state.ts","../../../packages/compiler/src/parser/parser.ts","../../../packages/compiler/src/render-generator/models/render-context.model.ts","../../../packages/compiler/src/render-generator/utils/render-generator.utils.ts","../../../packages/compiler/src/render-generator/states/process-const-declaration.state.ts","../../../packages/compiler/src/render-generator/states/process-element.state.ts","../../../packages/compiler/src/render-generator/states/process-for.state.ts","../../../packages/compiler/src/render-generator/states/process-if.state.ts","../../../packages/compiler/src/render-generator/states/process-switch.state.ts","../../../packages/compiler/src/render-generator/states/process-text-and-interpolation.state.ts","../../../packages/compiler/src/render-generator/render-generator.ts","../../../packages/compiler/src/compile.ts"],"sourcesContent":["/**\r\n * Represents the set of states the lexer can be in while processing template input.\r\n */\r\nexport enum LexerState {\r\n /**\r\n * Initial state before any input has been processed.\r\n */\r\n START = 'start',\r\n /**\r\n * Consuming plain text content between tags or at the top level.\r\n */\r\n TEXT = 'text',\r\n /**\r\n * Consuming the opening tag name after `<`.\r\n */\r\n TAG_OPEN_NAME = 'tag-open-name',\r\n /**\r\n * Inside an open tag body, scanning for attributes, events, or the closing `>`.\r\n */\r\n TAG_BODY = 'tag-body',\r\n /**\r\n * Processing the end of an open tag: `>` or `/>`.\r\n */\r\n TAG_OPEN_END = 'tag-open-end',\r\n /**\r\n * Consuming a closing tag `</tagName>`.\r\n */\r\n TAG_CLOSE = 'tag-close',\r\n /**\r\n * Consuming an HTML attribute name and its optional value.\r\n */\r\n ATTRIBUTE = 'attribute',\r\n /**\r\n * Consuming a DOM event binding starting with `@`.\r\n */\r\n EVENT = 'event',\r\n /**\r\n * Dispatching a flow-control keyword (@if, @for, @switch, etc.).\r\n */\r\n FLOW_CONTROL = 'flow-control',\r\n /**\r\n * Consuming the condition expression `(...)` of a flow-control directive.\r\n */\r\n FLOW_CONTROL_CONDITION = 'flow-control-condition',\r\n /**\r\n * Consuming the condition expression `(...)` of a @case directive.\r\n * This is needed to correctly handle special consecutives @case \r\n */\r\n CASE_FLOW_CONTROL_CONDITION = 'case-flow-control-condition',\r\n /**\r\n * Consuming the opening `{` of a flow-control block body.\r\n */\r\n FLOW_CONTROL_BLOCK = 'flow-control-block',\r\n /**\r\n * Dispatching between an expression or literal interpolation after `{`.\r\n */\r\n INTERPOLATION = 'interpolation',\r\n /**\r\n * Consuming a JavaScript expression inside `{ }`.\r\n */\r\n INTERPOLATION_EXPRESSION = 'interpolation-expression',\r\n /**\r\n * Consuming a template-literal string inside `` {`...`} ``.\r\n */\r\n INTERPOLATION_LITERAL = 'interpolation-literal',\r\n /**\r\n * Consuming a `@const name = expression;` declaration.\r\n */\r\n CONST_DECLARATION = 'const-declaration'\r\n}\r\n","/**\r\n * Discriminant values that identify the type of each token emitted by the lexer.\r\n */\r\nexport enum TokenType {\r\n /**\r\n * A plain text node between tags or at the top level.\r\n */\r\n TEXT,\r\n /**\r\n * The name portion of an opening tag, e.g. `div` in `<div`.\r\n */\r\n TAG_OPEN_NAME,\r\n /**\r\n * A self-closing tag marker `/>`.\r\n */\r\n TAG_SELF_CLOSE,\r\n /**\r\n * The closing `>` of an opening tag.\r\n */\r\n TAG_OPEN_END,\r\n /**\r\n * The name portion of a closing tag, e.g. `div` in `</div>`.\r\n */\r\n TAG_CLOSE_NAME,\r\n /**\r\n * An HTML attribute and its optional value.\r\n */\r\n ATTRIBUTE,\r\n /**\r\n * A DOM event binding declared with `@eventName=handler`.\r\n */\r\n EVENT,\r\n /**\r\n * A template-literal interpolation string enclosed in `` {`...`} ``.\r\n */\r\n INTERPOLATION_LITERAL,\r\n /**\r\n * A JavaScript expression interpolation enclosed in `{ }`.\r\n */\r\n INTERPOLATION_EXPRESSION,\r\n /**\r\n * A `@const name = expression;` template-level constant declaration.\r\n */\r\n CONST_DECLARATION,\r\n /**\r\n * Opening keyword of an `@if` directive.\r\n */\r\n IF,\r\n /**\r\n * Opening keyword of a `@for` directive.\r\n */\r\n FOR,\r\n /**\r\n * Opening keyword of an `@else` branch.\r\n */\r\n ELSE,\r\n /**\r\n * Opening keyword of an `@else if` branch.\r\n */\r\n ELSE_IF,\r\n /**\r\n * Opening keyword of a `@switch` directive.\r\n */\r\n SWITCH,\r\n /**\r\n * Opening keyword of a `@case` branch.\r\n */\r\n CASE,\r\n /**\r\n * Opening keyword of a `@default` branch.\r\n */\r\n DEFAULT,\r\n /**\r\n * The condition expression `(...)` associated with a flow-control directive.\r\n */\r\n CONDITION,\r\n /**\r\n * The opening `{` of a flow-control block body.\r\n */\r\n BLOCK_OPEN,\r\n /**\r\n * The closing `}` of a flow-control block body.\r\n */\r\n BLOCK_CLOSE,\r\n /**\r\n * Sentinel token emitted when the end of the input is reached.\r\n */\r\n EOF\r\n}\r\n","import { GREATER_THEN, LEFT_BRACE, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes an attribute name and optional value from the current position,\r\n * transitioning back to TAG_BODY when a space, `/`, or `>` is encountered.\r\n * If the attribute value is an interpolation, pushes the INTERPOLATION state.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of the attribute.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the ATTRIBUTE token and next state.\r\n */\r\nexport function consumeAttribute(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let attribute = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{\r\n type: TokenType.ATTRIBUTE,\r\n parts: [attribute]\r\n }] \r\n };\r\n read = false;\r\n break;\r\n\r\n case LEFT_BRACE:\r\n retVal = {\r\n state: LexerState.INTERPOLATION,\r\n tokens: [{\r\n type: TokenType.ATTRIBUTE,\r\n parts: [attribute]\r\n }],\r\n pushState: true \r\n };\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n attribute = `${attribute}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { LPAREN, RPAREN } from \"../../costants/chars.constants\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type\";\r\n\r\nexport function consumeFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): string {\r\n cursor.skipSpaces();\r\n\r\n if (cursor.peek() !== LPAREN) {\r\n throw new Error(`Expected '(' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`)\r\n }\r\n\r\n // consume '('\r\n cursor.advance();\r\n\r\n let expression = '';\r\n let depth = 1;\r\n\r\n while (depth > 0) {\r\n const code = cursor.peek();\r\n\r\n switch (code) {\r\n case LPAREN:\r\n depth++;\r\n expression = addCharacter(cursor, expression);\r\n break;\r\n\r\n case RPAREN:\r\n depth--;\r\n if (!depth) {\r\n cursor.advance();\r\n break;\r\n }\r\n\r\n expression = addCharacter(cursor, expression);\r\n break;\r\n\r\n default:\r\n expression = addCharacter(cursor, expression);\r\n }\r\n }\r\n\r\n return expression;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param expression The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nexport function addCharacter(cursor: LexerCursor, expression: string): string {\r\n cursor.advance();\r\n return `${expression}${cursor.currentChar.value}`;\r\n}","import { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\nimport { consumeFlowControlCondition } from \"../utils/consume-flow-control-condition.utils.js\";\r\n\r\n/**\r\n * Consumes the condition expression `(...)` of a flow-control directive,\r\n * handling nested parentheses correctly. Emits a CONDITION token with the\r\n * raw expression string and transitions to FLOW_CONTROL_BLOCK.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening `(`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.\r\n */\r\nexport function consumeCaseFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n const condition = consumeFlowControlCondition(cursor, _context);\r\n cursor.skipSpaces();\r\n\r\n return {\r\n state: cursor.peekMatch('@case') ? LexerState.FLOW_CONTROL : LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.CONDITION,\r\n parts: [condition]\r\n }],\r\n popState: true\r\n };\r\n}\r\n","import { EQUAL_THEN, SEMICOLON, SPACE } from \"../../costants/chars.constants\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model\";\r\nimport { LexerState } from \"../types/lexer-state.enum\";\r\nimport { TokenType } from \"../types/token-type.enum\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type\";\r\n\r\n/**\r\n * Consumes a `@const name = expression;` declaration from the current position.\r\n * Expects the cursor to be positioned after the `@const ` keyword.\r\n * Emits a CONST_DECLARATION token containing the variable name and initializer expression.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of the variable name.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONST_DECLARATION token and the TEXT state.\r\n */\r\nexport function consumeConstDeclaration(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let varName = '';\r\n let expression = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n /*\r\n Skip all possible spaces between the 'const' identifier and the '='\r\n @const varName\r\n or\r\n @const varName\r\n */\r\n cursor.skipSpaces();\r\n\r\n while(read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n read = false;\r\n break;\r\n\r\n default: \r\n cursor.advance();\r\n varName = `${varName}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n /*\r\n Skip all possible spaces between the varName and the '='\r\n varName =\r\n or\r\n varName =\r\n */\r\n cursor.skipSpaces();\r\n\r\n const nextChar = cursor.peek();\r\n if (nextChar !== EQUAL_THEN) {\r\n throw new Error(`Unexpected character ${String.fromCharCode(nextChar)}.\\nExpected '=' `);\r\n }\r\n \r\n cursor.advance();\r\n /*\r\n Skip all possible spaces between the '=' and the expression\r\n = user.name\r\n or\r\n = user.name\r\n */\r\n cursor.skipSpaces();\r\n read = true\r\n\r\n while(read) {\r\n switch (cursor.peek()) {\r\n case SEMICOLON:\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.CONST_DECLARATION,\r\n parts: [varName, expression]\r\n }]\r\n }\r\n read = false;\r\n break;\r\n\r\n default: \r\n cursor.advance();\r\n expression = `${expression}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n // Consume ';'\r\n cursor.advance();\r\n expression = `${expression};`\r\n\r\n return retVal;\r\n}","import { GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a DOM event binding starting with `@` and reads until a delimiter\r\n * (space, `/`, or `>`) is found. Emits an EVENT token containing the raw binding string.\r\n *\r\n * @param cursor The lexer cursor positioned on the `@` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the EVENT token and the TAG_BODY state.\r\n */\r\nexport function consumeEvent(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let event = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '@' character\r\n cursor.advance();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n /*\r\n Special case to handle syntax sugar for event bindings:\r\n If the desired function to be binded is the equal to the event name\r\n with the \"on\" prefix, automatically generate the binding string.\r\n Ex: @click=\"onClick\" can be written as @click, and the emitted token will have \"onClick\" as part\r\n */\r\n if (!event.includes('=')) {\r\n event = `${event}=on${event[0]!.toUpperCase()}${event.slice(1)}($event)`;\r\n }\r\n\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{ \r\n type: TokenType.EVENT, \r\n parts: [event] \r\n }]\r\n };\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n event = `${event}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { LEFT_BRACE } from \"../../costants/chars.constants.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Consumes the opening `{` of a flow control block body,\r\n * skipping any leading whitespace before it.\r\n *\r\n * Emits a BLOCK_OPEN token and transitions to TEXT,\r\n * pushing FLOW_CONTROL_BLOCK onto the state stack.\r\n * This allows consumeText to later recognise the matching `}` as a BLOCK_CLOSE\r\n * rather than as an interpolation boundary.\r\n *\r\n * Used by: @if, @for, @switch, @case, @else, @default\r\n */\r\nexport function consumeFlowControlBlock(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n cursor.skipSpaces();\r\n\r\n if (cursor.peek() !== LEFT_BRACE) {\r\n throw new Error(`Expected '{' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);\r\n }\r\n\r\n // consume '{'\r\n cursor.advance();\r\n\r\n return {\r\n state: LexerState.TEXT,\r\n tokens: [{ type: TokenType.BLOCK_OPEN }],\r\n pushState: true\r\n };\r\n}\r\n","import { CR, LF } from \"../../costants/chars.constants.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\nimport { consumeFlowControlCondition } from \"../utils/consume-flow-control-condition.utils.js\";\r\n\r\n/**\r\n * Consumes the condition expression `(...)` of a flow-control directive,\r\n * handling nested parentheses correctly. Emits a CONDITION token with the\r\n * raw expression string and transitions to FLOW_CONTROL_BLOCK.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening `(`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.\r\n */\r\nexport function consumeDefaultFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n return {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.CONDITION,\r\n parts: [consumeFlowControlCondition(cursor, _context)]\r\n }],\r\n popState: true\r\n };\r\n}\r\n","import { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Dispatches on a `@keyword` to determine which flow-control directive begins here.\r\n * Recognises `@if`, `@for`, `@else`, `@switch`, `@case`, `@default`, and `@const`.\r\n * Advances the cursor past the keyword and transitions to the appropriate next state.\r\n *\r\n * @param cursor The lexer cursor positioned on the `@` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the matching flow-control token and next state.\r\n */\r\nexport function consumeFlowControl(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '@' character\r\n cursor.advance();\r\n\r\n if (cursor.peekMatch('for ')) {\r\n cursor.advance(4);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.FOR\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('if ')) {\r\n cursor.advance(2);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.IF\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('else if ')) {\r\n cursor.advance(8);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.ELSE_IF\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('else ')) {\r\n cursor.advance(5);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.ELSE\r\n }]\r\n }\r\n } else if (cursor.peekMatch('switch ')) {\r\n cursor.advance(7);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.SWITCH\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('case ')) {\r\n cursor.advance(5);\r\n retVal = {\r\n state: LexerState.CASE_FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.CASE\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('default ')) {\r\n cursor.advance(8);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.DEFAULT\r\n }]\r\n }\r\n } else if (cursor.peekMatch('const ')) {\r\n cursor.advance(6);\r\n retVal = {\r\n state: LexerState.CONST_DECLARATION\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { LEFT_BRACE, RIGHT_BRACE, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a JavaScript expression interpolation `{ expression }`, tracking nested\r\n * brace depth. Emits an INTERPOLATION_EXPRESSION token and pops the state stack to\r\n * return to the previous state (ATTRIBUTE or TEXT).\r\n *\r\n * @param cursor The lexer cursor positioned at the first character of the expression.\r\n * @param context Lexer context used to retrieve the previous state for restoration.\r\n * @returns Transition result with the INTERPOLATION_EXPRESSION token and restored state.\r\n */\r\nexport function consumeInterpolationExpression(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let interpolation = '';\r\n let deep = 1\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case LEFT_BRACE:\r\n deep++;\r\n interpolation = addCharacter(cursor, interpolation);\r\n break;\r\n\r\n case RIGHT_BRACE:\r\n deep--;\r\n \r\n if (deep === 0) {\r\n cursor.advance();\r\n /*\r\n After an interpolation we have to understanad where to transite\r\n The next state depends from the previous state\r\n */\r\n const previousState = context.history.pop();\r\n let state!: LexerState;\r\n\r\n switch (previousState) {\r\n case LexerState.ATTRIBUTE:\r\n /*\r\n This is a special case to handle syntax sugar for attribute interpolations:\r\n If the attribute name and the variable binded have the same indentifier it can be written\r\n from attribute={attribute} to {attribute}\r\n \r\n In this case the attribute token emitted by the previosu state will have an empty string\r\n as part and we need to fill it with the actual interpolation content\r\n\r\n This is tricky but it allows to avoid unnecessary complication in the parser and\r\n render generator, by keeping this syntax sugar as a purely lexical feature and\r\n by redirecting to the standard flow for attribute interpolations after the lexer\r\n */\r\n const lastToken = context.tokens[context.tokens.length - 1];\r\n if (lastToken?.type === TokenType.ATTRIBUTE && !lastToken.parts[0]) {\r\n lastToken.parts[0] = `${interpolation}=`;\r\n }\r\n state = LexerState.TAG_BODY\r\n break;\r\n\r\n case LexerState.TEXT:\r\n state = LexerState.TEXT\r\n };\r\n\r\n retVal = {\r\n state,\r\n tokens: [{ \r\n type: TokenType.INTERPOLATION_EXPRESSION, \r\n parts: [interpolation] \r\n }],\r\n popState: true\r\n }\r\n read = false;\r\n } else {\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n\r\n break;\r\n\r\n default:\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n }\r\n\r\n return retVal;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param interpolation The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nfunction addCharacter(cursor: LexerCursor, interpolation: string): string {\r\n cursor.advance(1);\r\n return `${interpolation}${cursor.currentChar.value}`;\r\n}","import { GRAVE_ACCENT, RIGHT_BRACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a template-literal interpolation `` {`...`} ``, collecting characters\r\n * until the closing backtick followed by `}`. Emits an INTERPOLATION_LITERAL token\r\n * and pops the state stack to return to the previous state.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening backtick.\r\n * @param context Lexer context used to retrieve the previous state for restoration.\r\n * @returns Transition result with the INTERPOLATION_LITERAL token and restored state.\r\n */\r\nexport function consumeInterpolationliteral(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let interpolation = '`';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '`' character\r\n cursor.advance();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case GRAVE_ACCENT:\r\n interpolation = addCharacter(cursor, interpolation);\r\n\r\n if (cursor.peek() === RIGHT_BRACE) {\r\n // Consume '}'\r\n cursor.advance();\r\n /*\r\n After an interpolation we have to understanad where to transite\r\n The next state depends from the previous state\r\n */\r\n const previousState = context.history.pop();\r\n let state!: LexerState;\r\n\r\n switch (previousState) {\r\n case LexerState.ATTRIBUTE:\r\n state = LexerState.TAG_BODY\r\n break;\r\n\r\n case LexerState.TEXT:\r\n state = LexerState.TEXT\r\n };\r\n\r\n retVal = {\r\n state,\r\n tokens: [{\r\n type: TokenType.INTERPOLATION_LITERAL,\r\n parts: [interpolation]\r\n }],\r\n popState: true\r\n }\r\n read = false;\r\n } else {\r\n /*\r\n If ` is not followed by }, it means the interpolation is not closed\r\n and ` is part of the interpolated string\r\n |\r\n ˅\r\n Example: {`text ${var} ` text`}\r\n */\r\n interpolation = `${interpolation}${cursor.currentChar.value}`\r\n }\r\n break;\r\n\r\n default:\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n }\r\n\r\n return retVal;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param interpolation The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nfunction addCharacter(cursor: LexerCursor, interpolation: string): string {\r\n cursor.advance();\r\n return `${interpolation}${cursor.currentChar.value}`;\r\n}","import { A, a, CR, LF, Z, z } from '../costants/chars.constants.js';\r\n\r\n/**\r\n * Check if char code is a Line Feed (\\n) or Carriage Return (\\r)\r\n * @param char Character to control\r\n * @returns True if character is LF or CR, false otherwise\r\n */\r\nexport function isNewLine(char: number): boolean {\r\n return char === LF || char === CR;\r\n}\r\n\r\n/**\r\n * Check if char code is is a lower case letter\r\n * @param char Character to control\r\n * @returns True if character is a lowercase letter, false otherwise\r\n */\r\nexport function isLowerCase(char: number): boolean {\r\n return char >= a && char <= z;\r\n}\r\n\r\n/**\r\n * Check if char code is is a upper case letter\r\n * @param char Character to control\r\n * @returns True if character is a upper case letter, false otherwise\r\n */\r\nexport function isUpperCase(char: number): boolean {\r\n return char >= A && char <= Z;\r\n}\r\n\r\n/**\r\n * Check if the string contains at least one character different from\r\n * ' '\r\n * \\n\r\n * \\r\r\n * \\t\r\n * \\f\r\n * \\v\r\n * @param str String to check\r\n * @returns True if string is not blank, false otherwise\r\n */\r\nexport function isNotBlank(str: string): boolean {\r\n /* \r\n Differently from the approach of the other functions\r\n here we are working with string and not numbers.\r\n\r\n Number checks are usually faster when checking a character is\r\n included in a specific range.\r\n For this case we are checking if the string contains at least one char\r\n different from a list of non adiacent characters in the ASCII code, resulting\r\n in a very long condition with multiple OR\r\n\r\n This has been proven slower than using a regex\r\n */\r\n return /\\S/.test(str)\r\n}\r\n\r\n/**\r\n * Check if given ascii code is a valid First Character\r\n * for Javasript Identifiers\r\n * @param code The ascii code to valuate\r\n * @returns True if is valid, false otherwise\r\n */\r\nexport function isJSIdentifierStart(code: number): boolean {\r\n return (\r\n (code >= 65 && code <= 90) || // A-Z\r\n (code >= 97 && code <= 122) || // a-z\r\n code === 36 || // $\r\n code === 95 // _\r\n );\r\n}","import { GRAVE_ACCENT } from '../../costants/chars.constants.js';\r\nimport { isJSIdentifierStart } from '../../utils/chars.utils.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Dispatches between an expression and a literal interpolation after the opening `{`.\r\n * Advances past `{` and any leading spaces, then inspects the next character:\r\n * a backtick routes to INTERPOLATION_LITERAL, a JS identifier start routes to INTERPOLATION_EXPRESSION.\r\n *\r\n * @param cursor The lexer cursor positioned on the `{` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the appropriate interpolation sub-state.\r\n */\r\nexport function consumeInterpolation(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '{' characters\r\n cursor.advance();\r\n\r\n /*\r\n Skip all the spaces between '{' and the actual interpolation content\r\n Ex: '{ label}\r\n */\r\n cursor.skipSpaces();\r\n \r\n const nextChar = cursor.peek();\r\n\r\n if (nextChar === GRAVE_ACCENT) {\r\n retVal = { state: LexerState.INTERPOLATION_LITERAL };\r\n } else if (isJSIdentifierStart(nextChar)) {\r\n retVal = { state: LexerState.INTERPOLATION_EXPRESSION };\r\n } else {\r\n throw new Error(`Unrecognized First Character ${String.fromCharCode(nextChar)} in interpolation`);\r\n }\r\n\r\n return retVal;\r\n}","import { AT_SIGN, GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Scans the body of an open tag to determine what comes next:\r\n * an event binding (`@`), an attribute, the end of the tag (`>` or `/`), or whitespace.\r\n * Transitions to the appropriate state without emitting any tokens.\r\n *\r\n * @param cursor The lexer cursor positioned inside a tag body.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the next state and no tokens.\r\n */\r\nexport function consumeTagBody(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n const nextChar = cursor.peek();\r\n\r\n switch (nextChar) {\r\n case AT_SIGN:\r\n retVal = {\r\n state: LexerState.EVENT\r\n }\r\n read = false;\r\n break;\r\n\r\n case SPACE:\r\n cursor.skipSpaces();\r\n break;\r\n\r\n case GREATER_THEN:\r\n case SLASH:\r\n retVal = {\r\n state: LexerState.TAG_OPEN_END\r\n }\r\n read = false;\r\n break;\r\n\r\n default:\r\n retVal = {\r\n state: LexerState.ATTRIBUTE\r\n }\r\n read = false;\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { GREATER_THEN, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a closing tag `</tagName>`, skipping the `</` prefix and any surrounding\r\n * whitespace. Emits a TAG_CLOSE_NAME token with the tag name and transitions to TEXT.\r\n *\r\n * @param cursor The lexer cursor positioned at the `<` of a closing tag.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the TAG_CLOSE_NAME token and the TEXT state.\r\n */\r\nexport function consumeTagClose(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let tagName = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Skip '</'\r\n cursor.advance(2);\r\n\r\n /*\r\n Skip all the spaces between '</' and the actual tag name\r\n Ex: '</ div>\r\n */\r\n cursor.skipSpaces();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case GREATER_THEN:\r\n cursor.advance();\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_CLOSE_NAME, \r\n parts: [tagName]\r\n }]\r\n };\r\n read = false;\r\n break;\r\n\r\n case SPACE:\r\n throw new Error('Tag Close Name cannot contains spaces');\r\n\r\n default:\r\n cursor.advance();\r\n tagName = `${tagName}${cursor.currentChar.value}`;\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { GREATER_THEN } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes the closing characters of an open tag: `>` emits TAG_OPEN_END and\r\n * transitions to TEXT, while `/>` emits TAG_SELF_CLOSE and also transitions to TEXT.\r\n *\r\n * @param cursor The lexer cursor positioned at `>` or `/`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with TAG_OPEN_END or TAG_SELF_CLOSE and the TEXT state.\r\n */\r\nexport function consumeTagOpenEnd(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n // We arrive in this point by reading '>' or '/' at the end of a Open Tag \r\n if (cursor.peek() === GREATER_THEN) {\r\n cursor.advance();\r\n retVal = { \r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_OPEN_END,\r\n parts: []\r\n }] \r\n };\r\n } else {\r\n cursor.advance();\r\n const nextChar = cursor.peek();\r\n\r\n if (nextChar === GREATER_THEN) {\r\n cursor.advance();\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_SELF_CLOSE,\r\n parts: []\r\n }]\r\n };\r\n } else {\r\n throw new Error(`Unexpected character ${nextChar} for closing tag.\\nExpected />\\nRead of /${String.fromCharCode(nextChar)}\\nAt line ${cursor.position.row + 1} col ${cursor.position.column + 1}`)\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes an opening tag name after `<`, reading until a space, `/`, or `>` is found.\r\n * Emits a TAG_OPEN_NAME token with the tag name and transitions to TAG_BODY.\r\n *\r\n * @param cursor The lexer cursor positioned at the `<` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the TAG_OPEN_NAME token and the TAG_BODY state.\r\n */\r\nexport function consumeTagOpenName(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let tagName = '';\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n // Consume '<' character\r\n cursor.advance();\r\n\r\n /*\r\n Skip all the spaces between '<' and the actual tag name\r\n Ex: '< div>\r\n */\r\n cursor.skipSpaces();\r\n\r\n /*\r\n Keep read input until:\r\n - Space: <span \r\n - GT: <span>\r\n - Slash (Self Closing tag) <span / or <span/\r\n */\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{ \r\n type: TokenType.TAG_OPEN_NAME, \r\n parts: [tagName] \r\n }]\r\n }\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n tagName = `${tagName}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { AT_SIGN, CR, LEFT_BRACE, LESS_THAN, LF, RIGHT_BRACE, SLASH } from \"../../costants/chars.constants.js\";\r\nimport { isNotBlank } from \"../../utils/chars.utils.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Consumes plain text content, accumulating characters until a structural boundary\r\n * is reached: `<` (tag open/close), `{` (interpolation), `@` (flow-control or event),\r\n * or `}` (block close). Emits a TEXT token if non-blank text was accumulated.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of text content.\r\n * @param context Lexer context used to detect flow-control block boundaries.\r\n * @returns Transition result with an optional TEXT token and the next state.\r\n */\r\nexport function consumeText(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let text = '';\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case LESS_THAN:\r\n // If after '<' we read a '/', we suppose we're approaching a ClosureTag, otherwise an OpenTag\r\n const nextState = cursor.peek(1, { offset: 1 }) === SLASH ? LexerState.TAG_CLOSE : LexerState.TAG_OPEN_NAME;\r\n retVal = { state: nextState }\r\n read = false;\r\n break;\r\n\r\n case LEFT_BRACE:\r\n retVal = { \r\n state: LexerState.INTERPOLATION,\r\n pushState: true\r\n };\r\n read = false;\r\n break;\r\n \r\n case AT_SIGN:\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL,\r\n }\r\n read = false;\r\n break;\r\n\r\n case RIGHT_BRACE:\r\n if (context.history[context.history.length - 1] === LexerState.FLOW_CONTROL_BLOCK) {\r\n cursor.advance();\r\n retVal = { \r\n state: LexerState.TEXT,\r\n tokens: [{ type: TokenType.BLOCK_CLOSE }],\r\n popState: true \r\n };\r\n read = false;\r\n } else {\r\n cursor.advance();\r\n text = `${text}${cursor.currentChar.value}`;\r\n }\r\n break;\r\n\r\n case LF:\r\n case CR:\r\n cursor.advance();\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n text = `${text}${cursor.currentChar.value}`;\r\n }\r\n }\r\n\r\n\r\n /*\r\n If the first read character trigger a StateChange\r\n The cumulative `text` variable will be empty\r\n\r\n In this case we must NOT add any token\r\n\r\n Ex:\r\n Template starts with a tag:\r\n `<div ...`\r\n Or an interpolation:\r\n `{ myVariable }`\r\n */\r\n retVal.tokens ??= (isNotBlank(text)\r\n ? [{ type: TokenType.TEXT, parts: [text] }]\r\n : undefined);\r\n\r\n return retVal\r\n}","import { PositiveInteger, TupleOfLength } from '@xaendar/types';\r\nimport { CR, EOF, LF, SPACE } from '../../costants/chars.constants.js';\r\nimport { CurrentChar } from './current-char.type.js';\r\nimport { CursorPosition } from './current-position.type.js';\r\n\r\n/**\r\n * Cursor abstraction used by the Lexer to navigate the input source.\r\n *\r\n * The LexerCursor is responsible for:\r\n * - Sequential character consumption\r\n * - Lookahead (peek) operations without state mutation\r\n * - Tracking logical position (row, column)\r\n * - Handling end-of-file conditions\r\n *\r\n * This class deliberately contains **no lexer logic**:\r\n * it does not know about tokens, states, or grammar rules.\r\n * Its sole responsibility is controlled navigation of the input stream.\r\n */\r\nexport class LexerCursor {\r\n /**\r\n * Representation of the current character.\r\n *\r\n * - `index`: absolute index within the input string\r\n * - `code`: Unicode code point of the character\r\n * - `value`: actual character value\r\n *\r\n * An index of `-1` indicates that the cursor has not yet consumed\r\n * any character or has reached EOF.\r\n */\r\n private readonly _currentChar: CurrentChar = {\r\n code: 0,\r\n index: -1,\r\n value: ''\r\n };\r\n /**\r\n * Returns a read-only snapshot of the current character.\r\n */\r\n public get currentChar(): Readonly<CurrentChar> {\r\n return this._currentChar;\r\n }\r\n /**\r\n * Cache used by peek operations to avoid re-reading\r\n * the same character positions multiple times.\r\n *\r\n * Key: absolute character index\r\n * Value: Unicode code point\r\n */\r\n private readonly _peekCache = new Map<number, number>();\r\n /**\r\n * Logical position of the cursor in the input.\r\n *\r\n * - `row`: zero-based line number\r\n * - `column`: zero-based column number\r\n */\r\n private readonly _position: CursorPosition = {\r\n row: 0,\r\n column: 0\r\n };\r\n /**\r\n * Returns a read-only snapshot of the current cursor position.\r\n */\r\n public get position(): Readonly<CursorPosition> {\r\n return this._position;\r\n }\r\n\r\n /**\r\n * Creates a new cursor for the given input source.\r\n *\r\n * @param input Full source string to be tokenized.\r\n */\r\n constructor(public input: string) { }\r\n\r\n /**\r\n * Advances the cursor by the specified number of characters.\r\n *\r\n * This method:\r\n * - Updates the current character\r\n * - Updates row/column position\r\n * - Detects line breaks (LF / CR)\r\n * - Throws an EOF error when the end of the input is reached\r\n *\r\n * @param chars Number of characters to consume (must be >= 1)\r\n *\r\n * @throws Error with cause `EOF` when advancing past input length\r\n */\r\n public advance(chars = 1): void {\r\n if (chars < 1) {\r\n throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);\r\n }\r\n\r\n const newIndex = this._currentChar.index + chars;\r\n\r\n if (newIndex >= this.input.length) {\r\n this._currentChar.code = EOF;\r\n this._currentChar.index = -1;\r\n this._currentChar.value = '';\r\n this.throwEOFError();\r\n } else {\r\n /*\r\n Before updating the character, adjust logical position.\r\n Line breaks reset column and increment row.\r\n */\r\n if ([LF, CR].includes(this._currentChar.code)) {\r\n this._position.row++;\r\n this._position.column = 0;\r\n } else {\r\n this._position.column++;\r\n }\r\n\r\n this._currentChar.index = newIndex;\r\n this._currentChar.value = this.input[newIndex]!;\r\n this._currentChar.code = this.input.charCodeAt(newIndex);\r\n }\r\n }\r\n\r\n /**\r\n * Checks whether the upcoming characters in the input match the given pattern,\r\n * without advancing the cursor.\r\n *\r\n * - `string`: fast path using char code comparison (no allocation)\r\n * - `RegExp`: slices the input and tests the pattern against it.\r\n * Requires `length` to know how many characters to peek.\r\n *\r\n * @param pattern String or RegExp to match against\r\n * @param length Number of characters to peek — required when `pattern` is a RegExp\r\n * @returns `true` if the upcoming characters match, `false` otherwise\r\n */\r\n public peekMatch(pattern: string): boolean;\r\n public peekMatch(pattern: RegExp, length: number): boolean;\r\n public peekMatch(pattern: string | RegExp, length?: number): boolean {\r\n if (typeof pattern === 'string') {\r\n const peekedChars = this.peek(pattern.length);\r\n\r\n for (let i = 0; i < pattern.length; i++) {\r\n if (peekedChars[i] !== pattern.charCodeAt(i)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n // RegExp path — slice input and test\r\n const start = this._currentChar.index + 1;\r\n const slice = this.input.slice(start, start + length!);\r\n return pattern.test(slice);\r\n }\r\n\r\n /**\r\n * Peeks ahead in the input stream without advancing the cursor.\r\n *\r\n * This method supports:\r\n * - Single-character lookahead\r\n * - Multi-character lookahead\r\n * - Optional offset from the current position\r\n *\r\n * Peek operations are cached for performance reasons and do not\r\n * modify the cursor state.\r\n *\r\n * @returns\r\n * - A single Unicode code point when peeking one character\r\n * - An array of Unicode code points when peeking multiple characters\r\n *\r\n * @throws Error with cause `EOF` if the peek exceeds input length\r\n */\r\n public peek(): number;\r\n public peek<OffSet extends number>(options?: { offset?: PositiveInteger<OffSet> }): number;\r\n public peek(chars: 1): number;\r\n public peek<OffSet extends number>(chars: 1, options?: { offset?: PositiveInteger<OffSet> }): number; \r\n public peek<ReadChars extends number>(chars: PositiveInteger<ReadChars>): TupleOfLength<ReadChars>; \r\n public peek<ReadChars extends number, OffSet extends number>(chars: PositiveInteger<ReadChars>, options?: { offset?: PositiveInteger<OffSet> }): TupleOfLength<ReadChars>;\r\n public peek(charsOrOptions?: number | { offset?: number }, options?: { offset?: number }): number | number[] {\r\n const cache = this._peekCache;\r\n const chars = typeof charsOrOptions === 'number' ? charsOrOptions : 1;\r\n const offset = (typeof charsOrOptions === 'object' ? charsOrOptions : options)?.offset ?? 0;\r\n return chars === 1 ? this.peekOneChar(this._currentChar.index + offset + 1, cache) : this.peekMany(chars + offset, cache);\r\n }\r\n\r\n /**\r\n * Skips all consecutive space characters from the current position.\r\n */\r\n public skipSpaces(): void {\r\n while (this.peek() === SPACE || this.peek() === LF || this.peek() === CR) {\r\n this.advance();\r\n }\r\n }\r\n\r\n /**\r\n * Peeks multiple characters ahead.\r\n */\r\n private peekMany(chars: number, cache: Map<number, number>): number[] {\r\n const peekedChars = new Array<number>;\r\n const nextCharIndex = this._currentChar.index + 1;\r\n\r\n for (let i = nextCharIndex; i < nextCharIndex + chars; i++) {\r\n peekedChars.push(this.peekOneChar(i, cache));\r\n }\r\n\r\n return peekedChars;\r\n }\r\n\r\n /**\r\n * Peeks a single character at the given absolute index.\r\n */\r\n private peekOneChar(index: number, cache: Map<number, number>): number {\r\n if (cache.has(index)) {\r\n return cache.get(index)!;\r\n }\r\n\r\n if (index >= this.input.length) {\r\n this.throwEOFError();\r\n }\r\n\r\n const charCode = this.input.charCodeAt(index);\r\n cache.set(index, charCode);\r\n return charCode;\r\n }\r\n\r\n /**\r\n * Throws a standardized EOF error used by the lexer engine\r\n * to terminate tokenization.\r\n */\r\n private throwEOFError(): never {\r\n throw new Error('', { cause: EOF });\r\n }\r\n}\r\n","import { Stack } from '@xaendar/common';\r\nimport { Dictionary } from '@xaendar/types';\r\nimport { EOF } from '../costants/chars.constants.js';\r\nimport { consumeAttribute } from './states/attribute.state.js';\r\nimport { consumeCaseFlowControlCondition } from './states/case-flow-control-condition.state.js';\r\nimport { consumeConstDeclaration } from './states/const-declaration.js';\r\nimport { consumeEvent } from './states/event.state.js';\r\nimport { consumeFlowControlBlock } from './states/flow-control-block.state.js';\r\nimport { consumeDefaultFlowControlCondition } from './states/default-flow-control-condition.state.js';\r\nimport { consumeFlowControl } from './states/flow-control.js';\r\nimport { consumeInterpolationExpression } from './states/interpolation-expression.state.js';\r\nimport { consumeInterpolationliteral } from './states/interpolation-literal.state.js';\r\nimport { consumeInterpolation } from './states/interpolation.state.js';\r\nimport { consumeTagBody } from './states/tag-body.state.js';\r\nimport { consumeTagClose } from './states/tag-close.state.js';\r\nimport { consumeTagOpenEnd } from './states/tag-open-end.state.js';\r\nimport { consumeTagOpenName } from './states/tag-open-name.state.js';\r\nimport { consumeText } from './states/text.state.js';\r\nimport { LexerCursor } from './types/lexer-cursor.model.js';\r\nimport { LexerState } from './types/lexer-state.enum.js';\r\nimport { Token } from './types/token.type.js';\r\nimport { LexerTransitionFunction } from './types/transition-function/transition-function.type.js';\r\n\r\n/**\r\n * Utility class that emulates a cursor navigating through a template string.\r\n *\r\n * The cursor keeps track of the current character, its absolute position\r\n * within the text, and its logical position expressed as row and column.\r\n * This is useful when parsing or analyzing template content character by character.\r\n */\r\nexport class Lexer {\r\n /**\r\n * Cursor for navigating the input character stream.\r\n */\r\n private readonly _cursor: LexerCursor;\r\n /**\r\n * Current lexer state.\r\n */\r\n private _state = LexerState.START;\r\n /**\r\n * State stack used to support nested states (e.g. interpolations).\r\n */\r\n private _stack = new Stack<LexerState>;\r\n /**\r\n * Accumulated list of tokens emitted during tokenization.\r\n */\r\n private readonly _tokens = new Array<Token>;\r\n /**\r\n * Maps each lexer state to its corresponding transition function.\r\n */\r\n private readonly _states: Dictionary<LexerState, LexerTransitionFunction> = {\r\n [LexerState.START]: consumeText,\r\n [LexerState.TEXT]: consumeText,\r\n [LexerState.TAG_OPEN_NAME]: consumeTagOpenName,\r\n [LexerState.TAG_BODY]: consumeTagBody,\r\n [LexerState.TAG_OPEN_END]: consumeTagOpenEnd,\r\n [LexerState.TAG_CLOSE]: consumeTagClose,\r\n [LexerState.ATTRIBUTE]: consumeAttribute,\r\n [LexerState.FLOW_CONTROL]: consumeFlowControl,\r\n [LexerState.FLOW_CONTROL_CONDITION]: consumeDefaultFlowControlCondition,\r\n [LexerState.CASE_FLOW_CONTROL_CONDITION]: consumeCaseFlowControlCondition,\r\n [LexerState.FLOW_CONTROL_BLOCK]: consumeFlowControlBlock,\r\n [LexerState.EVENT]: consumeEvent,\r\n [LexerState.INTERPOLATION]: consumeInterpolation,\r\n [LexerState.INTERPOLATION_EXPRESSION]: consumeInterpolationExpression,\r\n [LexerState.INTERPOLATION_LITERAL]: consumeInterpolationliteral,\r\n [LexerState.CONST_DECLARATION]: consumeConstDeclaration\r\n }\r\n\r\n /**\r\n * Creates a new Cursor instance for the given template content.\r\n *\r\n * @param input The full template text that the cursor will navigate.\r\n */\r\n constructor(public input: string) {\r\n this._cursor = new LexerCursor(this.input);\r\n }\r\n\r\n /**\r\n * Runs the lexer over the input string and returns the full token array.\r\n * Drives the state machine until EOF is reached.\r\n *\r\n * @returns Array of all tokens produced from the input.\r\n */\r\n public tokenize(): Token[] {\r\n let eof = false;\r\n\r\n while (!eof) {\r\n try {\r\n const transitionFunction = this._states[this._state];\r\n const { state, tokens, popState, pushState } = transitionFunction!(this._cursor, { \r\n history: this._stack.values,\r\n tokens: [...this._tokens] \r\n });\r\n \r\n if (tokens?.length) {\r\n this._tokens.push(...tokens);\r\n }\r\n \r\n if (pushState) {\r\n this._stack.push(this._state);\r\n }\r\n \r\n if (popState) {\r\n this._stack.pop();\r\n } \r\n \r\n this._state = state;\r\n } catch (err) {\r\n const error = err as Error;\r\n if (error.cause === EOF) {\r\n eof = true;\r\n } else {\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n return this._tokens;\r\n }\r\n}","import { PositiveInteger, TupleOfLength } from '@xaendar/types';\r\nimport { EOF } from '../../costants/chars.constants.js';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { Token } from '../../lexer/types/token.type.js';\r\nimport { CurrentToken } from '../types/current-token.type.js';\r\n\r\n/**\r\n * Cursor abstraction used by the Parser to navigate\r\n * through a sequence of tokens produced by the Lexer.\r\n *\r\n * Responsibilities:\r\n * - Sequential token consumption\r\n * - Lookahead (peek) operations without mutating state\r\n * - Handling end-of-file conditions\r\n *\r\n * This class does not perform parsing itself: it only\r\n * manages position and access to the token stream.\r\n */\r\nexport class ParserCursor {\r\n\r\n /**\r\n * Representation of the current token.\r\n *\r\n * - `index`: absolute index within the token array\r\n * - `value`: current token object (or EOF token)\r\n *\r\n * An index of `-1` indicates that the cursor has not\r\n * yet consumed any token or has reached EOF.\r\n */\r\n private readonly _currentToken: CurrentToken = {\r\n value: { type: TokenType.EOF },\r\n index: -1\r\n };\r\n\r\n /**\r\n * Returns a read-only snapshot of the current token.\r\n */\r\n public get currentToken(): Readonly<CurrentToken> {\r\n return this._currentToken;\r\n }\r\n\r\n /**\r\n * Creates a new ParserCursor for the given token array.\r\n *\r\n * @param _tokens Array of tokens to navigate.\r\n */\r\n constructor(private readonly _tokens: Token[]) { }\r\n\r\n /**\r\n * Advances the cursor by the specified number of tokens.\r\n *\r\n * Updates the current token and index.\r\n *\r\n * @param chars Number of tokens to advance (must be >= 1)\r\n *\r\n * @throws Error with cause `EOF` when advancing past the end\r\n */\r\n public advance(chars = 1): void {\r\n if (chars < 1) {\r\n throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);\r\n }\r\n\r\n const newIndex = this._currentToken.index + chars;\r\n\r\n if (newIndex >= this._tokens.length) {\r\n this._currentToken.value = { type: TokenType.EOF };\r\n this._currentToken.index = -1;\r\n } else {\r\n this._currentToken.index = newIndex;\r\n this._currentToken.value = this._tokens[newIndex]!;\r\n }\r\n }\r\n\r\n /**\r\n * Peeks ahead in the token stream without advancing the cursor.\r\n *\r\n * Supports:\r\n * - Single-token lookahead\r\n * - Multi-token lookahead\r\n * - Optional offset from the current token\r\n *\r\n * @returns\r\n * - A single Token when peeking one token\r\n * - An array of Tokens when peeking multiple tokens\r\n *\r\n * @throws Error with cause `EOF` if the peek exceeds the token array\r\n */\r\n public peek<T extends Token = Token>(): T;\r\n public peek<OffSet extends number, T extends Token = Token>(options?: { offset?: PositiveInteger<OffSet> }): T;\r\n public peek<T extends Token = Token>(chars: 1): T;\r\n public peek<OffSet extends number, T extends Token = Token>(chars: 1, options?: { offset?: PositiveInteger<OffSet> }): T; \r\n public peek<ReadChars extends number, T extends Token = Token>(chars: PositiveInteger<ReadChars>): TupleOfLength<ReadChars, T>; \r\n public peek<ReadChars extends number, OffSet extends number, T extends Token = Token>(chars: PositiveInteger<ReadChars>, options?: { offset?: PositiveInteger<OffSet> }): TupleOfLength<ReadChars, T>;\r\n public peek(charsOrOptions?: number | { offset?: number }, options?: { offset?: number }): Token | Token[] {\r\n const tokens = typeof charsOrOptions === 'number' ? charsOrOptions : 1;\r\n const offset = (typeof charsOrOptions === 'object' ? charsOrOptions : options)?.offset ?? 0;\r\n return tokens === 1 ? this.peekOneToken(this._currentToken.index + offset + 1) : this.peekMany(tokens + offset);\r\n }\r\n\r\n /**\r\n * Peeks multiple tokens ahead.\r\n */\r\n private peekMany(chars: number): Token[] {\r\n const peekedTokens = new Array<Token>;\r\n const nextTokenIndex = this._currentToken.index + 1;\r\n\r\n for (let i = nextTokenIndex; i < nextTokenIndex + chars; i++) {\r\n peekedTokens.push(this.peekOneToken(i));\r\n }\r\n\r\n return peekedTokens;\r\n }\r\n\r\n /**\r\n * Peeks a single token at the given absolute index.\r\n */\r\n private peekOneToken(index: number): Token {\r\n return index < this._tokens.length ? this._tokens[index]! : { type: TokenType.EOF };\r\n }\r\n}\r\n","/**\r\n * Discriminant values that identify the type of each AST node produced by the parser.\r\n */\r\nexport enum ASTNodeType {\r\n /**\r\n * An HTML element node with a tag name, attributes, events, and children.\r\n */\r\n Element,\r\n /**\r\n * A plain text node.\r\n */\r\n Text,\r\n /**\r\n * An inline interpolation expression or literal.\r\n */\r\n Interpolation,\r\n /**\r\n * An `@if` conditional node.\r\n */\r\n If,\r\n /**\r\n * An `@else` branch node attached to an `@if`.\r\n */\r\n Else,\r\n /**\r\n * An `@else if` branch node attached to an `@if`.\r\n */\r\n ElseIf,\r\n /**\r\n * An `@for` iteration node.\r\n */\r\n For,\r\n /**\r\n * An `@switch` node containing one or more case nodes.\r\n */\r\n Switch,\r\n /**\r\n * A `@case` or `@default` branch inside a `@switch`.\r\n */\r\n Case,\r\n /**\r\n * A `@const` declaration node.\r\n */\r\n ConstDeclaration\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { ConstDeclarationToken } from '../../lexer/types/tokens/const-declaration-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ConstDeclarationNode } from '../types/nodes/const-declaration-node.type.js';\r\n\r\n/**\r\n * Parses a CONST_DECLARATION token into a `ConstDeclarationNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the CONST_DECLARATION token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The CONST_DECLARATION token containing variable name and expression.\r\n * @returns The parsed `ConstDeclarationNode`.\r\n */\r\nexport function parseConstDeclaration(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: ConstDeclarationToken): ConstDeclarationNode {\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.ConstDeclaration,\r\n varName: token.parts[0],\r\n expression: token.parts[1]\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { InterpolationExpressionToken } from '../../lexer/types/tokens/interpolation-expression-token.type.js';\r\nimport { InterpolationLiteralToken } from '../../lexer/types/tokens/interpolation-literal-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { InterpolationNode } from '../types/nodes/interpolation-node.type.js';\r\n\r\n/**\r\n * Parses an interpolation expression or literal token into an `InterpolationNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the interpolation token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The INTERPOLATION_EXPRESSION or INTERPOLATION_LITERAL token.\r\n * @returns The parsed `InterpolationNode`.\r\n */\r\nexport function parseInterpolation(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: InterpolationExpressionToken | InterpolationLiteralToken): InterpolationNode {\r\n cursor.advance();\r\n \r\n return {\r\n type: ASTNodeType.Interpolation,\r\n expression: token.parts[0]\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { AttributeToken } from '../../lexer/types/tokens/attribute-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { AttributeNode } from '../types/nodes/attribute-node.type.js';\r\nimport { parseInterpolation } from './parse-interpolation.state.js';\r\n\r\n/**\r\n * Parses an ATTRIBUTE token into an `AttributeNode`.\r\n * Handles boolean attributes (no `=`), string values, and interpolation values.\r\n *\r\n * @param cursor Parser cursor; advanced past the ATTRIBUTE token.\r\n * @param parseNode Parser node function for recursive parsing.\r\n * @param token The ATTRIBUTE token to parse.\r\n * @returns The parsed `AttributeNode`.\r\n */\r\nexport function parseAttribute(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: AttributeToken): AttributeNode {\r\n // consume ATTRIBUTE token\r\n cursor.advance();\r\n const raw = token.parts[0];\r\n\r\n if (!raw.includes('=')) {\r\n return { name: raw, value: 'true' };\r\n }\r\n\r\n const [name, value] = raw.split('=');\r\n if (!name) {\r\n throw new Error(`[Parser] Attribute name missing in: ${raw}`);\r\n }\r\n\r\n const nextToken = cursor.peek();\r\n if (nextToken.type === TokenType.INTERPOLATION_EXPRESSION || nextToken.type === TokenType.INTERPOLATION_LITERAL) {\r\n return {\r\n name,\r\n value: parseInterpolation(cursor, parseNode, nextToken)\r\n };\r\n }\r\n\r\n if (!value) {\r\n throw new Error(`[Parser] Attribute value missing for ${name} in: ${raw}`);\r\n }\r\n\r\n return {\r\n name,\r\n value: value.replace(/^['']|['']$/g, '')\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { EventToken } from '../../lexer/types/tokens/event-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { EventNode } from '../types/nodes/event-node.type.js';\r\n\r\n/**\r\n * Parses an EVENT token into an `EventNode` by splitting the raw\r\n * `eventName=handler` string.\r\n *\r\n * @param cursor Parser cursor; advanced past the EVENT token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The EVENT token to parse.\r\n * @returns The parsed `EventNode`.\r\n */\r\nexport function parseEvent(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: EventToken): EventNode {\r\n cursor.advance();\r\n const raw = token.parts[0];\r\n const [name, value] = raw.split('=');\r\n\r\n if (!name || !value) {\r\n throw new Error(`[Parser] Invalid event format: ${raw}`);\r\n }\r\n\r\n return {\r\n name,\r\n handler: value.replace(/^[\"\"]|[\"\"]$/g, '')\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { TagOpenNameToken } from '../../lexer/types/tokens/tag-open-name-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { AttributeNode } from '../types/nodes/attribute-node.type.js';\r\nimport { ElementNode } from '../types/nodes/element-node.type.js';\r\nimport { EventNode } from '../types/nodes/event-node.type.js';\r\nimport { parseAttribute } from './parse-attribute.state.js';\r\nimport { parseEvent } from './parse-event.state.js';\r\n\r\n/**\r\n * Parses a TAG_OPEN_NAME token and the subsequent attributes, events, and children\r\n * into an `ElementNode`. Handles both regular and self-closing tags.\r\n *\r\n * @param cursor Parser cursor positioned at the TAG_OPEN_NAME token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param token The TAG_OPEN_NAME token containing the tag name.\r\n * @returns The parsed `ElementNode`.\r\n */\r\nexport function parseElement(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: TagOpenNameToken): ElementNode {\r\n cursor.advance();\r\n const tagName = token.parts[0];\r\n\r\n const attributes = new Array<AttributeNode>();\r\n const events = new Array<EventNode>();\r\n\r\n let read = true;\r\n while (read) {\r\n const token = cursor.peek();\r\n switch (token.type) {\r\n case TokenType.ATTRIBUTE:\r\n attributes.push(parseAttribute(cursor, parseNode, token));\r\n break;\r\n\r\n case TokenType.EVENT:\r\n events.push(parseEvent(cursor, parseNode, token));\r\n break;\r\n\r\n default:\r\n read = false;\r\n }\r\n }\r\n\r\n // Consume TAG_OPEN_END if present: <div>\r\n if (cursor.peek().type === TokenType.TAG_OPEN_END) {\r\n cursor.advance();\r\n }\r\n\r\n // Handle self-closing tags: <div />\r\n if (cursor.peek().type === TokenType.TAG_SELF_CLOSE) {\r\n cursor.advance();\r\n return {\r\n type: ASTNodeType.Element,\r\n tagName,\r\n attributes,\r\n events,\r\n children: []\r\n };\r\n }\r\n\r\n // Parse children recursively until closing tag\r\n const children = new Array<ASTNode>;\r\n while (!isTagClose(cursor, tagName)) {\r\n const child = parseNode();\r\n if (child) {\r\n children.push(child);\r\n }\r\n }\r\n\r\n // Consume closing tag </div>\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Element,\r\n tagName,\r\n attributes,\r\n events,\r\n children\r\n };\r\n}\r\n\r\n/**\r\n * Returns `true` if the next token in the stream is a closing tag for the given tag name.\r\n *\r\n * @param cursor Parser cursor to peek from.\r\n * @param tagName The expected tag name to match.\r\n * @returns `true` if the next token is TAG_CLOSE_NAME matching `tagName`.\r\n */\r\nfunction isTagClose(cursor: ParserCursor, tagName: string): boolean {\r\n const nextToken = cursor.peek();\r\n return nextToken.type === TokenType.TAG_CLOSE_NAME && nextToken.parts[0] === tagName;\r\n}\r\n","import ts, { Diagnostic } from 'typescript';\r\nimport { ExpressionValidationResult } from '../types/expression-validation-result.type';\r\nimport { ExpressionDiagnostic } from '../types/nodes/expression-diangnostic.type';\r\n\r\n/**\r\n * Validates that a string contains a single expression belonging to the\r\n * permitted subset of JavaScript supported inside Xaendar template expressions.\r\n *\r\n * ## Permitted constructs\r\n *\r\n * - **Literals** — strings, numbers, bigints, booleans, `null`, `undefined`\r\n * - **Identifiers** — resolved at runtime against the active scope chain\r\n * - **Member access** — `user.name`, `user.address.city`, `items[0]`\r\n * - **Call expressions** — `user.getFullName()`, `user.hasRole('admin')`\r\n * - **Binary expressions** — arithmetic (`+`, `-`, `*`, `/`, `%`, `**`),\r\n * comparison (`===`, `!==`, `<`, `>`, `<=`, `>=`),\r\n * logical (`&&`, `||`, `??`),\r\n * bitwise (`&`, `|`, `^`, `<<`, `>>`, `>>>`)\r\n * - **Unary expressions** — `!`, `~`, `+`, `-`, `typeof`, `void`\r\n * - **Conditional (ternary)** — `isAdmin ? 'yes' : 'no'`\r\n * - **Parenthesised expressions** — `(user.age > 18)`\r\n * - **Template literals** — `` `Hello ${user.name}` ``\r\n * - **Array literals** — `[1, 2, 3]`, `[...items]`\r\n * - **Object literals** — `{ key: value }`, `{ ...defaults, name }`\r\n * - **Spread** — `foo(...args)`, `[...items]`, `{ ...obj }`\r\n * - **`typeof` / `instanceof`** — `typeof user.role`, `user instanceof AdminUser`\r\n *\r\n * ## Prohibited constructs\r\n *\r\n * - Assignments (`=`, `+=`, `&&=`, etc.) — use `@const` for local bindings\r\n * - `await` and `yield`\r\n * - `new` expressions\r\n * - Function and arrow function expressions\r\n * - Tagged template expressions\r\n *\r\n * ## Scope resolution\r\n *\r\n * This function performs **syntactic** validation only. Identifier resolution\r\n * (scope chain walk → `ctx.` prefix injection) is the responsibility of the\r\n * caller and must be performed on the returned `node` after this function\r\n * reports no diagnostics.\r\n *\r\n * @param source - The raw expression string extracted from the template.\r\n * @returns A {@link ExpressionValidationResult} containing the parsed AST node\r\n * (when valid) and any diagnostics produced during validation.\r\n *\r\n * @example\r\n * const result = validateExpression('user.hasRole(\"admin\") && isVerified');\r\n * if (result.diagnostics.length === 0) {\r\n * // result.node is safe to use\r\n * }\r\n *\r\n * @example\r\n * const result = validateExpression('await user.load()');\r\n * // result.diagnostics[0].message →\r\n * // \"'await' is not allowed inside template expressions.\"\r\n */\r\nexport function validateExpression(source: string): ExpressionValidationResult {\r\n const prefix = 'const x = ';\r\n const sourceFile = ts.createSourceFile('expression.ts', `${prefix}${source}`, ts.ScriptTarget.ESNext, true);\r\n\r\n const statement = sourceFile.statements[0] as ts.VariableStatement;\r\n const expression = statement.declarationList.declarations[0]!.initializer!;\r\n\r\n const diagnostics = new Array<ExpressionDiagnostic>;\r\n visitNode(expression, prefix.length, diagnostics);\r\n\r\n if (diagnostics.length) {\r\n throw new Error(diagnostics.reduce((acc, d) => `${acc}${d.message}\\n`, ''));\r\n }\r\n\r\n return {\r\n node: expression,\r\n };\r\n}\r\n\r\n/**\r\n * Recursively visits an AST node and appends a diagnostic for every node\r\n * kind that is not part of the permitted expression subset.\r\n *\r\n * Recursion stops at the first disallowed node to avoid producing a cascade\r\n * of redundant diagnostics for its children.\r\n *\r\n * @param node - The AST node to inspect.\r\n * @param offset - Number of characters to subtract from raw node positions\r\n * to obtain offsets relative to the original expression string.\r\n * @param diagnostics - Accumulator for diagnostics found during the walk.\r\n */\r\nfunction visitNode(node: ts.Node, offset: number, diagnostics: ExpressionDiagnostic[]): void {\r\n if (!isAllowedNode(node)) {\r\n throw new Error(buildDisallowedMessage(node));\r\n }\r\n\r\n ts.forEachChild(node, child => visitNode(child, offset, diagnostics));\r\n\r\n if (diagnostics.length) {\r\n throw new Error(diagnostics[0]!.message);\r\n }\r\n}\r\n\r\n/**\r\n * Returns `true` if the given AST node kind is permitted inside a\r\n * Xaendar template expression.\r\n *\r\n * Assignment operators nested inside a `BinaryExpression` are handled\r\n * separately in {@link buildDisallowedMessage} since TypeScript does not\r\n * distinguish them at the node-kind level.\r\n */\r\nfunction isAllowedNode(node: ts.Node): boolean {\r\n switch (node.kind) {\r\n // ---- Literals ----\r\n case ts.SyntaxKind.StringLiteral:\r\n case ts.SyntaxKind.NumericLiteral:\r\n case ts.SyntaxKind.BigIntLiteral:\r\n case ts.SyntaxKind.TrueKeyword:\r\n case ts.SyntaxKind.FalseKeyword:\r\n case ts.SyntaxKind.NullKeyword:\r\n case ts.SyntaxKind.UndefinedKeyword:\r\n\r\n // ---- Identifiers ----\r\n case ts.SyntaxKind.Identifier:\r\n\r\n // ---- Member access ----\r\n // user.name\r\n case ts.SyntaxKind.PropertyAccessExpression:\r\n // user['name'], items[0]\r\n case ts.SyntaxKind.ElementAccessExpression:\r\n\r\n // ---- Call expressions ----\r\n // user.getFullName(), user.hasRole('admin')\r\n case ts.SyntaxKind.CallExpression:\r\n\r\n // ---- Binary expressions ----\r\n // Covers arithmetic, comparison, logical, bitwise, nullish coalescing,\r\n // and instanceof. Assignment operators are rejected in visitNode via\r\n // buildDisallowedMessage before recursing into children.\r\n case ts.SyntaxKind.BinaryExpression:\r\n\r\n // ---- Operator tokens — visited as children of BinaryExpression ----\r\n // Comparison\r\n case ts.SyntaxKind.EqualsEqualsToken: // ==\r\n case ts.SyntaxKind.EqualsEqualsEqualsToken: // ===\r\n case ts.SyntaxKind.ExclamationEqualsToken: // !=\r\n case ts.SyntaxKind.ExclamationEqualsEqualsToken: // !==\r\n case ts.SyntaxKind.LessThanToken: // \r\n case ts.SyntaxKind.LessThanEqualsToken: // <=\r\n case ts.SyntaxKind.GreaterThanToken: // >\r\n case ts.SyntaxKind.GreaterThanEqualsToken: // >=\r\n\r\n // Arithmetic\r\n case ts.SyntaxKind.PlusToken: // +\r\n case ts.SyntaxKind.MinusToken: // -\r\n case ts.SyntaxKind.AsteriskToken: // *\r\n case ts.SyntaxKind.SlashToken: // /\r\n case ts.SyntaxKind.PercentToken: // %\r\n case ts.SyntaxKind.AsteriskAsteriskToken: // **\r\n\r\n // Logical\r\n case ts.SyntaxKind.AmpersandAmpersandToken: // &&\r\n case ts.SyntaxKind.BarBarToken: // ||\r\n case ts.SyntaxKind.QuestionQuestionToken: // ??\r\n\r\n // Bitwise\r\n case ts.SyntaxKind.AmpersandToken: // &\r\n case ts.SyntaxKind.BarToken: // |\r\n case ts.SyntaxKind.CaretToken: // ^\r\n case ts.SyntaxKind.LessThanLessThanToken: // \r\n case ts.SyntaxKind.GreaterThanGreaterThanToken: // >>\r\n case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: // >>>\r\n \r\n // instanceof / in\r\n case ts.SyntaxKind.InstanceOfKeyword: // instanceof\r\n case ts.SyntaxKind.InKeyword: // in\r\n\r\n // ---- Unary expressions ----\r\n // !isAdmin, ~flags, +n, -n, typeof x, void 0\r\n case ts.SyntaxKind.PrefixUnaryExpression:\r\n case ts.SyntaxKind.PostfixUnaryExpression:\r\n // typeof is represented as a dedicated node kind in some TS versions\r\n case ts.SyntaxKind.TypeOfExpression:\r\n case ts.SyntaxKind.VoidExpression:\r\n\r\n // ---- Conditional (ternary) ----\r\n // isAdmin ? 'yes' : 'no'\r\n case ts.SyntaxKind.ConditionalExpression:\r\n\r\n // ---- Parenthesised expressions ----\r\n case ts.SyntaxKind.ParenthesizedExpression:\r\n\r\n // ---- Template literals ----\r\n // `Hello ${user.name}`\r\n case ts.SyntaxKind.TemplateExpression:\r\n case ts.SyntaxKind.NoSubstitutionTemplateLiteral:\r\n case ts.SyntaxKind.TemplateHead:\r\n case ts.SyntaxKind.TemplateMiddle:\r\n case ts.SyntaxKind.TemplateTail:\r\n case ts.SyntaxKind.TemplateSpan:\r\n\r\n // ---- Arrays ----\r\n // [1, 2, 3], [...items]\r\n case ts.SyntaxKind.ArrayLiteralExpression:\r\n\r\n // ---- Objects ----\r\n // { key: value }, { ...defaults, name }\r\n case ts.SyntaxKind.ObjectLiteralExpression:\r\n case ts.SyntaxKind.PropertyAssignment:\r\n case ts.SyntaxKind.ShorthandPropertyAssignment:\r\n // { ...obj } inside an object literal\r\n case ts.SyntaxKind.SpreadAssignment:\r\n\r\n // ---- Spread ----\r\n // foo(...args), [...items]\r\n case ts.SyntaxKind.SpreadElement:\r\n\r\n // ---- Internal structural nodes ----\r\n // Visited during recursion but carry no semantic meaning of their own.\r\n case ts.SyntaxKind.SyntaxList:\r\n return true;\r\n\r\n // ---- Disallowed by default ----\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Builds a human-readable diagnostic message for a node that is not permitted\r\n * inside a Xaendar template expression.\r\n *\r\n * Provides specific messages for the most common mistakes (assignments, `await`,\r\n * `new`, functions) and falls back to a generic message for anything else.\r\n */\r\nfunction buildDisallowedMessage(node: ts.Node): string {\r\n switch (node.kind) {\r\n case ts.SyntaxKind.AwaitExpression:\r\n return \"'await' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.YieldExpression:\r\n return \"'yield' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.NewExpression:\r\n return \"'new' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.ArrowFunction:\r\n case ts.SyntaxKind.FunctionExpression:\r\n return 'Function expressions are not allowed inside template expressions.';\r\n\r\n case ts.SyntaxKind.TaggedTemplateExpression:\r\n return 'Tagged template expressions are not allowed inside template expressions.';\r\n\r\n case ts.SyntaxKind.BinaryExpression: {\r\n const bin = node as ts.BinaryExpression;\r\n return isAssignmentOperator(bin.operatorToken.kind)\r\n ? 'Assignments are not allowed inside template expressions. Use @const to declare local template variables instead.'\r\n : `'${ts.SyntaxKind[node.kind]}' is not allowed inside template expressions.`;\r\n }\r\n\r\n default:\r\n return `'${ts.SyntaxKind[node.kind]}' is not allowed inside template expressions.`;\r\n }\r\n}\r\n\r\n/**\r\n * Returns `true` if the given {@link ts.SyntaxKind} is an assignment operator.\r\n *\r\n * Covers simple assignment (`=`) as well as all compound assignment operators\r\n * (`+=`, `-=`, `&&=`, `||=`, `??=`, etc.) as defined by the TypeScript\r\n * `FirstAssignment`–`LastAssignment` range.\r\n */\r\nfunction isAssignmentOperator(kind: ts.SyntaxKind): boolean {\r\n return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { parse } from 'node:path';\r\n\r\n/**\r\n * Parses child AST nodes inside a flow-control block until a BLOCK_CLOSE token is reached.\r\n * Consumes the BLOCK_CLOSE token before returning.\r\n *\r\n * @param cursor Parser cursor positioned at the first token inside the block.\r\n * @param parseNode Parser function for recursive child parsing.\r\n * @returns Array of parsed child `ASTNode`s.\r\n */\r\nexport function parseBlockChildren(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>): ASTNode[] {\r\n const children = new Array<ASTNode>;\r\n\r\n while (cursor.peek().type !== TokenType.BLOCK_CLOSE) {\r\n const child = parseNode();\r\n if (child) {\r\n children.push(child);\r\n }\r\n }\r\n\r\n // consume BLOCK_CLOSE\r\n cursor.advance();\r\n return children;\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport ts from 'typescript';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { ForToken } from '../../lexer/types/tokens/for-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ForExpression } from '../types/for-expression.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ForImplicitVariables } from '../types/nodes/for-implicit-variables.js';\r\nimport { ForNode } from '../types/nodes/for-node.type.js';\r\nimport { validateExpression } from '../utils/expression-validator.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\n\r\n/**\r\n * Parses a `@for` directive, consuming the FOR token, the CONDITION token,\r\n * the BLOCK_OPEN token, and all child nodes until BLOCK_CLOSE.\r\n *\r\n * @param cursor Parser cursor positioned at the FOR token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param _token The FOR token (unused; consumed for position advancement).\r\n * @returns The parsed `ForNode`.\r\n */\r\nexport function parseForControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, _token: ForToken): ForNode {\r\n // consume FOR\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after FOR, got ${TokenType[conditionToken.type]}`);\r\n }\r\n const expression = parseForExpression(conditionToken.parts[0], 0);\r\n\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const children = parseBlockChildren(cursor, parseNode);\r\n\r\n return { type: ASTNodeType.For, ...expression, children };\r\n}\r\n\r\n/**\r\n * Parses the body of an `@for` block into a structured {@link ForExpression}.\r\n *\r\n * The expected format is:\r\n * ```\r\n * item of iterable; track expr[; $implicit = alias, ...]\r\n * ```\r\n *\r\n * @param source - The raw string content of the `@for(...)` expression.\r\n * @param baseOffset - Character offset of `source` within the original template,\r\n * used to produce accurate diagnostic positions.\r\n * @returns A {@link ForExpression} object. When unrecoverable syntax errors are\r\n * found the returned object contains only `diagnostics`.\r\n */\r\nexport function parseForExpression(source: string, baseOffset: number): ForExpression {\r\n const sections = splitForSections(source);\r\n\r\n if (sections.length < 2) {\r\n throw new Error(`[Parser] @for requires at least \"item of iterable; track expr\".`);\r\n }\r\n\r\n // ---- Section 1: \"item of items\" ----\r\n const iterSection = sections[0]!.trim();\r\n const ofIndex = iterSection.indexOf(' of ');\r\n\r\n if (ofIndex === -1) {\r\n throw new Error(`[Parser] @for expression must be in the form \"item of iterable\".`);\r\n }\r\n\r\n const itemAlias = iterSection.slice(0, ofIndex).trim();\r\n const iterableSource = iterSection.slice(ofIndex + 4).trim();\r\n\r\n if (!isValidIdentifier(itemAlias)) {\r\n throw new Error(`[Parser] '${itemAlias}' is not a valid item alias.`);\r\n }\r\n\r\n // Validate the iterable as a JS expression.\r\n const iterValidation = validateExpression(iterableSource);\r\n\r\n // ---- Section 2: \"track item.id\" ----\r\n const trackSection = sections[1]!.trim();\r\n\r\n if (!trackSection.startsWith('track ')) {\r\n throw new Error(`[Parser] Second section of @for must start with \"track\".`);\r\n }\r\n\r\n const trackSource = trackSection.slice(6).trim();\r\n const trackValidation = validateExpression(trackSource);\r\n\r\n // ---- Section 3 (optional): \"$index = i, $last = l\" ----\r\n const implicitAliases = new Map<ForImplicitVariables, string>;\r\n\r\n if (sections.length >= 3 && sections[2] !== undefined) {\r\n const aliasSection = sections[2].trim();\r\n const aliasOffset = baseOffset + source.indexOf(sections[2]);\r\n parseImplicitAliases(aliasSection, aliasOffset, implicitAliases);\r\n }\r\n\r\n return {\r\n itemAlias,\r\n iterableExpression: iterValidation.node,\r\n iterableSource,\r\n trackExpression: trackValidation.node,\r\n trackSource,\r\n implicitAliases\r\n };\r\n}\r\n\r\n/**\r\n * Parses the optional third section of an `@for` expression, which declares\r\n * aliases for implicit loop variables (e.g. `$index = i, $last = l, $even = isEven`).\r\n *\r\n * Valid entries are comma-separated pairs in the form `$implicit = alias`.\r\n * Diagnostics are pushed to `diagnostics` for any malformed or duplicate entry.\r\n *\r\n * @param source - The raw alias-declarations string (everything after the second `;`).\r\n * @param baseOffset - Character offset of `source` within the original template.\r\n * @param out - Map to populate with `alias → implicit-variable` entries.\r\n * @param diagnostics - Array to collect any parse errors.\r\n */\r\nfunction parseImplicitAliases(source: string, baseOffset: number, out: Map<ForImplicitVariables, string>): void {\r\n const entries = source.split(',');\r\n let cursor = 0;\r\n \r\n const IMPLICIT_VARIABLES = new Set(['$index', '$last', '$first', '$even', '$odd']);\r\n\r\n for (const entry of entries) {\r\n const trimmed = entry.trim();\r\n const eqIndex = trimmed.indexOf('=');\r\n\r\n if (eqIndex === -1) {\r\n throw new Error(`[Parser] Invalid alias declaration '${trimmed}'. Expected '$implicit = alias'.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n const implicit = trimmed.slice(0, eqIndex).trim();\r\n const alias = trimmed.slice(eqIndex + 1).trim();\r\n\r\n const isImplicitVariable = (value: string): value is ForImplicitVariables => IMPLICIT_VARIABLES.has(value as ForImplicitVariables);\r\n \r\n if (!isImplicitVariable(implicit)) {\r\n throw new Error(`[Parser] '${implicit}' is not a known implicit variable. Known variables: ${[...IMPLICIT_VARIABLES].join(', ')}.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n if (!isValidIdentifier(alias)) {\r\n throw new Error(`[Parser] '${alias}' is not a valid alias identifier.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n if (out.has(implicit)) {\r\n throw new Error(`[Parser] '${implicit}' is already aliased in this @for expression.`);\r\n } else {\r\n out.set(implicit, alias);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n }\r\n}\r\n\r\n/**\r\n * Splits the raw `@for(...)` body into its semicolon-delimited sections,\r\n * respecting nested brackets and string literals so that semicolons inside\r\n * them are never treated as section separators.\r\n *\r\n * Example input: `\"item of items; track item.id; $index = i\"`\r\n * Example output: `[\"item of items\", \" track item.id\", \" $index = i\"]`\r\n *\r\n * @param source - The raw content of the `@for(...)` expression.\r\n * @returns An array of section strings (without the `;` separators).\r\n */\r\nfunction splitForSections(source: string): string[] {\r\n const sections = new Array<string>;\r\n let current = '';\r\n let depth = 0;\r\n let inString: '\"' | \"'\" | '`' | null | undefined;\r\n\r\n for (let i = 0; i < source.length; i++) {\r\n const char = source[i]!;\r\n\r\n if (!current && char === ' ') {\r\n continue;\r\n }\r\n\r\n if (inString) {\r\n current += char;\r\n if (char === inString && source[i - 1] !== '\\\\') {\r\n inString = null;\r\n }\r\n continue;\r\n }\r\n\r\n if (char === '\"' || char === \"'\" || char === '`') {\r\n inString = char;\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Brackets — do not split inside nested bracket pairs.\r\n if (char === '(' || char === '[' || char === '{') {\r\n depth++;\r\n current += char;\r\n continue;\r\n }\r\n\r\n if (char === ')' || char === ']' || char === '}') {\r\n depth--;\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Section separator — only split when not inside brackets or strings.\r\n if (char === ';' && depth === 0) {\r\n sections.push(current);\r\n current = '';\r\n continue;\r\n }\r\n\r\n current += char;\r\n }\r\n\r\n // Push the last section even when it has no trailing `;`.\r\n if (current.trim().length > 0) {\r\n sections.push(current);\r\n }\r\n\r\n return sections;\r\n}\r\n\r\n/**\r\n * Checks whether `name` is a valid JavaScript identifier by delegating to\r\n * the TypeScript parser.\r\n *\r\n * A string is considered valid when the TS parser produces a single\r\n * `ExpressionStatement` whose expression is an `Identifier` with the\r\n * same text.\r\n *\r\n * @param name - The string to validate.\r\n * @returns `true` if `name` is a valid JS identifier, `false` otherwise.\r\n */\r\nfunction isValidIdentifier(name: string): boolean {\r\n if (!name.length) {\r\n return false;\r\n }\r\n\r\n const sourceFile = ts.createSourceFile('__id.ts', name, ts.ScriptTarget.ESNext, false);\r\n const statement = sourceFile.statements[0];\r\n return !!statement && ts.isExpressionStatement(statement) && ts.isIdentifier(statement.expression) && statement.expression.text === name;\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { IfToken } from '../../lexer/types/tokens/if-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ElseNode } from '../types/nodes/else-node.type.js';\r\nimport { IfNode } from '../types/nodes/if-node.type.js';\r\nimport { validateExpression } from '../utils/expression-validator.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\nimport { ElseIfToken } from '../../lexer/types/tokens/else-if-token.type.js';\r\nimport { ElseIfNode } from '../types/nodes/else-if-node.type.js';\r\nimport { ElseToken } from '../../lexer/types/tokens/else-token.type.js';\r\n\r\n/**\r\n * Parses an `@if` directive, consuming the IF token, the CONDITION token,\r\n * the BLOCK_OPEN token, all consequent children, and an optional `@else` branch.\r\n *\r\n * @param cursor Parser cursor positioned at the IF token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param token The IF token (unused; consumed for position advancement).\r\n * @returns The parsed `IfNode`.\r\n */\r\nexport function parseIfControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken): IfNode {\r\n return parseIfRecursively(cursor, parseNode, token);\r\n}\r\n\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken): IfNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: ElseIfToken | ElseToken): ElseIfNode | ElseNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: ElseToken): ElseNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken | ElseIfToken | ElseToken): IfNode | ElseIfNode | ElseNode {\r\n switch (token.type) {\r\n case TokenType.IF:\r\n case TokenType.ELSE_IF:\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after ${TokenType[token.type]}, got ${TokenType[conditionToken.type]}`);\r\n }\r\n\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const condition = conditionToken.parts[0];\r\n const validationResult = validateExpression(condition);\r\n\r\n const consequent = parseBlockChildren(cursor, parseNode);\r\n\r\n return {\r\n type: token.type === TokenType.IF ? ASTNodeType.If : ASTNodeType.ElseIf,\r\n condition,\r\n conditionNode: validationResult.node,\r\n consequent,\r\n alternate: parseIfRecursively(cursor, parseNode, cursor.peek<ElseIfToken | ElseToken>())\r\n };\r\n\r\n case TokenType.ELSE:\r\n // consume ELSE and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const elseChildren = parseBlockChildren(cursor, parseNode);\r\n \r\n return {\r\n type: ASTNodeType.Else,\r\n consequent: elseChildren\r\n };\r\n }\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { SwitchToken } from '../../lexer/types/tokens/switch-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { CaseNode } from '../types/nodes/case-node.type.js';\r\nimport { SwitchNode } from '../types/nodes/switch-node.type.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\n\r\n/**\r\n * Parses a `@switch` directive, consuming the SWITCH token, the CONDITION token,\r\n * the outer BLOCK_OPEN, all `@case` and `@default` branches, and the outer BLOCK_CLOSE.\r\n *\r\n * @param cursor Parser cursor positioned at the SWITCH token.\r\n * @param parseNode Parser function for recursive child parsing.\r\n * @param _token The SWITCH token (unused; consumed for position advancement).\r\n * @returns The parsed `SwitchNode`.\r\n */\r\nexport function parseSwitchControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, _token: SwitchToken): SwitchNode {\r\n // consume SWITCH\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after SWITCH, got ${TokenType[conditionToken.type]}`);\r\n }\r\n\r\n const expression = conditionToken.parts[0];\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const cases = new Array<CaseNode>;\r\n\r\n while (cursor.peek().type !== TokenType.BLOCK_CLOSE) {\r\n const token = cursor.peek();\r\n\r\n switch (token.type) {\r\n case TokenType.CASE:\r\n const condition = new Array<string>;\r\n \r\n /*\r\n We loop to support block case with multiple conditions, e.g.:\r\n @switch (x) {\r\n @case (1) \r\n @case (2) {\r\n // ...\r\n }\r\n }\r\n */\r\n do {\r\n // consume CASE\r\n cursor.advance();\r\n\r\n const caseCondition = cursor.peek();\r\n if (caseCondition.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after CASE`);\r\n }\r\n \r\n condition.push(caseCondition.parts[0]);\r\n // consume CONDITION\r\n cursor.advance();\r\n } while (cursor.peek().type !== TokenType.BLOCK_OPEN);\r\n\r\n // consume BLOCK_OPEN\r\n cursor.advance();\r\n \r\n cases.push({\r\n type: ASTNodeType.Case, \r\n condition, \r\n children: parseBlockChildren(cursor, parseNode) \r\n });\r\n break;\r\n\r\n case TokenType.DEFAULT:\r\n // consume DEFAULT and BLOCK_OPEN\r\n cursor.advance(2);\r\n cases.push({\r\n type: ASTNodeType.Case, \r\n condition: null, \r\n children: parseBlockChildren(cursor, parseNode) \r\n });\r\n break;\r\n\r\n }\r\n }\r\n\r\n // consume outer BLOCK_CLOSE\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Switch,\r\n expression,\r\n cases\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TextToken } from '../../lexer/types/tokens/text-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { TextNode } from '../types/nodes/text-node.type.js';\r\n\r\n/**\r\n * Parses a TEXT token into a `TextNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the TEXT token.\r\n * @param _parseNode Function to parse the next AST node.\r\n * @param token The TEXT token containing the raw text content.\r\n * @returns The parsed `TextNode`.\r\n */\r\nexport function parseText(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: TextToken): TextNode {\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Text,\r\n value: token.parts[0]\r\n };\r\n}\r\n","import { TokenType } from \"../lexer/types/token-type.enum.js\";\r\nimport { Token } from \"../lexer/types/token.type.js\";\r\nimport { ParserCursor } from \"./models/parser-cursor.model.js\";\r\nimport { parseConstDeclaration } from \"./states/parse-const-declaration.state.js\";\r\nimport { parseElement } from \"./states/parse-element.state.js\";\r\nimport { parseForControlFlow } from \"./states/parse-for.state.js\";\r\nimport { parseIfControlFlow } from \"./states/parse-if.state.js\";\r\nimport { parseInterpolation } from \"./states/parse-interpolation.state.js\";\r\nimport { parseSwitchControlFlow } from \"./states/parse-switch.state.js\";\r\nimport { parseText } from \"./states/parse-text.state.js\";\r\nimport { ASTNode } from \"./types/ast.type.js\";\r\nimport { ParserStates } from \"./types/parser-states.type.js\";\r\n\r\n/**\r\n * Parser class that transforms a stream of tokens (from the Lexer)\r\n * into an Abstract Syntax Tree (AST) representing the template structure.\r\n *\r\n * Responsibilities:\r\n * - Parse text nodes, elements, attributes, events, and interpolations\r\n * - Maintain cursor state for sequential token consumption\r\n * - Detect tag boundaries and nested structures\r\n *\r\n * The parser assumes that the token stream is syntactically valid according\r\n * to the Lexer rules. Parsing errors are thrown as exceptions.\r\n */\r\nexport class Parser {\r\n /**\r\n * Internal cursor for navigating tokens\r\n */\r\n private readonly _cursor: ParserCursor;\r\n /**\r\n * Mapping of token types to their corresponding parser transition functions, \r\n * which handle the logic for parsing each token type into AST nodes.\r\n */\r\n private readonly _states: ParserStates = {\r\n [TokenType.TEXT]: parseText,\r\n [TokenType.INTERPOLATION_EXPRESSION]: parseInterpolation,\r\n [TokenType.INTERPOLATION_LITERAL]: parseInterpolation,\r\n [TokenType.TAG_OPEN_NAME]: parseElement,\r\n [TokenType.IF]: parseIfControlFlow,\r\n [TokenType.FOR]: parseForControlFlow,\r\n [TokenType.SWITCH]: parseSwitchControlFlow,\r\n [TokenType.CONST_DECLARATION]: parseConstDeclaration\r\n }\r\n\r\n /**\r\n * Creates a new Parser instance.\r\n *\r\n * @param tokens Array of tokens produced by the Lexer\r\n */\r\n constructor(private readonly tokens: Token[]) {\r\n this._cursor = new ParserCursor(this.tokens);\r\n }\r\n\r\n /**\r\n * Entry point for parsing the token stream into AST nodes.\r\n *\r\n * @returns Array of top-level AST nodes\r\n */\r\n public parse(): ASTNode[] {\r\n const nodes = new Array<ASTNode>;\r\n \r\n while (this._cursor.peek().type !== TokenType.EOF) {\r\n const parseNode = this.parseNode();\r\n if (parseNode) {\r\n nodes.push(parseNode);\r\n }\r\n }\r\n\r\n return nodes;\r\n }\r\n\r\n /**\r\n * Parses the next AST node based on the current token.\r\n *\r\n * @returns Parsed AST node\r\n * @throws Error if an unexpected token is encountered\r\n */\r\n private parseNode(): ASTNode | undefined {\r\n const token = this._cursor.peek();\r\n if (token.type === TokenType.EOF) {\r\n return;\r\n }\r\n \r\n const state = this._states[token.type];\r\n\r\n if (!state) {\r\n throw new Error(`[Parser] No transition function for token type ${TokenType[token.type]}`);\r\n }\r\n\r\n return state(this._cursor, this.parseNode.bind(this), token as never);\r\n }\r\n}\r\n","/**\r\n * Tracks identifier scope during render code generation.\r\n * Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)\r\n * and can be chained to a parent context for outer-scope resolution.\r\n */\r\nexport class Context {\r\n /**\r\n * Creates a new scope context.\r\n *\r\n * @param _identifiers List of loop variable names declared in this scope.\r\n * @param _parent Optional parent context representing the enclosing scope.\r\n */\r\n constructor(\r\n private _identifiers = new Array<string>,\r\n private _parent?: Context\r\n ) { }\r\n\r\n public addIdentifier(name: string): void {\r\n if (this.getIdentifier(name)) {\r\n throw new Error(`Identifier \"${name}\" is already declared in this scope.`);\r\n }\r\n \r\n this._identifiers.push(name);\r\n }\r\n\r\n /**\r\n * Returns the innermost identifier in the current scope chain, or\r\n * delegates to the parent context if none is found in this scope.\r\n *\r\n * @returns The most recently declared identifier name, or `undefined` if none exists.\r\n */\r\n public getIdentifier(name: string): string | undefined {\r\n return this._identifiers.includes(name) ? name : this._parent?.getIdentifier(name);\r\n }\r\n}\r\n","import ts, { Expression } from 'typescript';\r\nimport { Context } from '../models/render-context.model';\r\nimport { ElementNode } from '../../parser/types/nodes/element-node.type';\r\n\r\n/**\r\n * Complete set of JavaScript global identifiers up to ES2026.\r\n *\r\n * These are identifiers that TypeScript's parser classifies as\r\n * `SyntaxKind.Identifier` (unlike true keywords such as `typeof`,\r\n * `instanceof`, `true`, `false`, `null` which have their own SyntaxKind)\r\n * but that must never be prefixed with `this.` inside a template expression\r\n * because they refer to well-known globals, not to component properties.\r\n *\r\n * Organised by ECMAScript category, mirroring the MDN \"Standard built-in\r\n * objects\" reference, plus the ES2026 additions (Temporal, DisposableStack,\r\n * AsyncDisposableStack, SuppressedError, Math.sumPrecise surface).\r\n *\r\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects\r\n */\r\nexport const GLOBAL_IDENTIFIERS: ReadonlySet<string> = new Set([\r\n // ---- Value properties ------------------------------------------------\r\n // true, false, null are SyntaxKind keywords — not needed here.\r\n 'undefined',\r\n 'NaN',\r\n 'Infinity',\r\n 'globalThis',\r\n \r\n // ---- Global functions ------------------------------------------------\r\n 'eval',\r\n 'isFinite',\r\n 'isNaN',\r\n 'parseFloat',\r\n 'parseInt',\r\n 'decodeURI',\r\n 'decodeURIComponent',\r\n 'encodeURI',\r\n 'encodeURIComponent',\r\n // Deprecated but still Identifiers in TS\r\n 'escape',\r\n 'unescape',\r\n \r\n // ---- Fundamental objects ---------------------------------------------\r\n 'Object',\r\n 'Function',\r\n 'Boolean',\r\n 'Symbol',\r\n \r\n // ---- Error objects ---------------------------------------------------\r\n 'Error',\r\n 'AggregateError',\r\n 'EvalError',\r\n 'RangeError',\r\n 'ReferenceError',\r\n 'SyntaxError',\r\n 'TypeError',\r\n 'URIError',\r\n 'SuppressedError', // ES2026 — explicit resource management\r\n 'InternalError', // Non-standard (Firefox) but common\r\n \r\n // ---- Numbers and dates -----------------------------------------------\r\n 'Number',\r\n 'BigInt',\r\n 'Math',\r\n 'Date',\r\n 'Temporal', // ES2026 — replaces Date\r\n \r\n // ---- Text processing -------------------------------------------------\r\n 'String',\r\n 'RegExp',\r\n \r\n // ---- Indexed collections ---------------------------------------------\r\n 'Array',\r\n 'TypedArray',\r\n 'Int8Array',\r\n 'Uint8Array',\r\n 'Uint8ClampedArray',\r\n 'Int16Array',\r\n 'Uint16Array',\r\n 'Int32Array',\r\n 'Uint32Array',\r\n 'BigInt64Array',\r\n 'BigUint64Array',\r\n 'Float16Array', // ES2025\r\n 'Float32Array',\r\n 'Float64Array',\r\n \r\n // ---- Keyed collections -----------------------------------------------\r\n 'Map',\r\n 'Set',\r\n 'WeakMap',\r\n 'WeakSet',\r\n \r\n // ---- Structured data -------------------------------------------------\r\n 'ArrayBuffer',\r\n 'SharedArrayBuffer',\r\n 'DataView',\r\n 'Atomics',\r\n 'JSON',\r\n \r\n // ---- Memory management -----------------------------------------------\r\n 'WeakRef',\r\n 'FinalizationRegistry',\r\n \r\n // ---- Control abstractions --------------------------------------------\r\n 'Iterator', // ES2025\r\n 'AsyncIterator', // ES2025\r\n 'Promise',\r\n 'GeneratorFunction',\r\n 'AsyncGeneratorFunction',\r\n 'Generator',\r\n 'AsyncGenerator',\r\n 'AsyncFunction',\r\n 'DisposableStack', // ES2026 — explicit resource management\r\n 'AsyncDisposableStack', // ES2026 — explicit resource management\r\n \r\n // ---- Reflection ------------------------------------------------------\r\n 'Reflect',\r\n 'Proxy',\r\n \r\n // ---- Internationalization --------------------------------------------\r\n 'Intl',\r\n \r\n // ---- WebAssembly -----------------------------------------------------\r\n 'WebAssembly',\r\n \r\n // ---- Browser / DOM globals -------------------------------------------\r\n // These are not part of the ECMAScript spec but are universally available\r\n // in browser environments and must not be treated as component properties.\r\n 'window',\r\n 'document',\r\n 'navigator',\r\n 'location',\r\n 'history',\r\n 'screen',\r\n 'console',\r\n 'performance',\r\n 'crypto',\r\n 'fetch',\r\n 'alert',\r\n 'confirm',\r\n 'prompt',\r\n 'setTimeout',\r\n 'setInterval',\r\n 'clearTimeout',\r\n 'clearInterval',\r\n 'requestAnimationFrame',\r\n 'cancelAnimationFrame',\r\n 'queueMicrotask',\r\n 'structuredClone',\r\n 'URL',\r\n 'URLSearchParams',\r\n 'FormData',\r\n 'Headers',\r\n 'Request',\r\n 'Response',\r\n 'AbortController',\r\n 'AbortSignal',\r\n 'CustomEvent',\r\n 'Event',\r\n 'EventTarget',\r\n 'MutationObserver',\r\n 'IntersectionObserver',\r\n 'ResizeObserver',\r\n 'PerformanceObserver',\r\n 'Worker',\r\n 'SharedWorker',\r\n 'ServiceWorker',\r\n 'Blob',\r\n 'File',\r\n 'FileReader',\r\n 'ReadableStream',\r\n 'WritableStream',\r\n 'TransformStream',\r\n 'TextEncoder',\r\n 'TextDecoder',\r\n 'ImageData',\r\n 'Canvas',\r\n 'Storage',\r\n 'localStorage',\r\n 'sessionStorage',\r\n 'indexedDB',\r\n 'WebSocket',\r\n 'XMLHttpRequest',\r\n \r\n // ---- DOM element constructors ----------------------------------------\r\n // Commonly used with instanceof in template expressions.\r\n 'HTMLElement',\r\n 'HTMLInputElement',\r\n 'HTMLButtonElement',\r\n 'HTMLFormElement',\r\n 'HTMLAnchorElement',\r\n 'HTMLImageElement',\r\n 'HTMLVideoElement',\r\n 'HTMLAudioElement',\r\n 'HTMLCanvasElement',\r\n 'HTMLSelectElement',\r\n 'HTMLTextAreaElement',\r\n 'HTMLDivElement',\r\n 'HTMLSpanElement',\r\n 'HTMLParagraphElement',\r\n 'HTMLHeadingElement',\r\n 'HTMLTableElement',\r\n 'HTMLTableRowElement',\r\n 'HTMLTableCellElement',\r\n 'HTMLUListElement',\r\n 'HTMLOListElement',\r\n 'HTMLLIElement',\r\n 'HTMLLabelElement',\r\n 'HTMLDialogElement',\r\n 'HTMLDetailsElement',\r\n 'HTMLSlotElement',\r\n 'HTMLTemplateElement',\r\n 'SVGElement',\r\n 'SVGSVGElement',\r\n 'Element',\r\n 'Node',\r\n 'NodeList',\r\n 'DocumentFragment',\r\n 'ShadowRoot',\r\n 'Document',\r\n 'Window',\r\n]);\r\n\r\nexport const ROOT_NODE = 'this._root';\r\n\r\n/**\r\n * Resolves references to component properties inside a template expression.\r\n *\r\n * Identifiers that are not found in the active scope chain and are not\r\n * well-known globals are prefixed with `this.` so they resolve against\r\n * the component instance at runtime.\r\n *\r\n * The original formatting of the expression — parentheses, spacing,\r\n * operator tokens, member access dots — is preserved verbatim by delegating\r\n * to `node.getText()` for any subtree that contains no resolvable identifiers.\r\n *\r\n * @param expression - Either a raw identifier string or a validated\r\n * `ts.Expression` node produced by `validateExpression`.\r\n * @param context - The active template scope context.\r\n * @returns The resolved expression as a JavaScript string ready for codegen.\r\n *\r\n * @example\r\n * // Simple identifier\r\n * resolveExpression('items', context) // → 'this.items'\r\n *\r\n * @example\r\n * // Complex expression — formatting preserved\r\n * resolveExpression(node, context)\r\n * // typeof id !== 'boolean' || pippo instanceof HTMLElement\r\n * // → typeof this.id !== 'boolean' || this.pippo instanceof HTMLElement\r\n */\r\nexport function resolveExpression(expression: string | Expression, context: Context): string {\r\n return typeof expression === 'string'\r\n ? context.getIdentifier(expression) ?? `this.${expression}`\r\n : emitNode(expression, expression, context);\r\n}\r\n\r\n/**\r\n * Emits the resolved text for a node.\r\n *\r\n * - If the node has no resolvable identifiers in its subtree, emits\r\n * `node.getText()` verbatim — preserving all original spacing,\r\n * parentheses, dots, and punctuation.\r\n * - If the node is a resolvable Identifier, emits the resolved name.\r\n * - Otherwise recurses into children and concatenates their output.\r\n */\r\nfunction emitNode(node: ts.Node, parent: ts.Node, context: Context): string {\r\n // Leaf Identifier that needs resolution\r\n if (ts.isIdentifier(node) && needsResolution(node, parent)) {\r\n return context.getIdentifier(node.text) ?? `this.${node.text}`;\r\n }\r\n\r\n // No resolvable identifiers in this subtree — emit verbatim\r\n if (!containsResolvableIdentifier(node, parent)) {\r\n return node.getText();\r\n }\r\n\r\n /*\r\n Has resolvable identifiers — recurse into children and concatenate.\r\n We use the original source positions to reconstruct spacing between\r\n children faithfully instead of joining with a fixed separator.\r\n */\r\n const sourceText = node.getSourceFile().text;\r\n let result = '';\r\n let lastEnd = node.getStart();\r\n\r\n ts.forEachChild(node, child => {\r\n result = `${result}${sourceText.slice(lastEnd, child.getStart())}${emitNode(child, node, context)}`;\r\n lastEnd = child.getEnd();\r\n });\r\n\r\n // Append any trailing text after the last child (e.g. closing paren)\r\n return `${result}${sourceText.slice(lastEnd, node.getEnd())}`;\r\n}\r\n\r\n/**\r\n * Returns true if the subtree rooted at `node` contains at least one\r\n * Identifier that needs context resolution.\r\n *\r\n * Short-circuits as soon as one is found to avoid visiting the whole tree.\r\n */\r\nfunction containsResolvableIdentifier(node: ts.Node, parent: ts.Node): boolean {\r\n if (ts.isIdentifier(node) && needsResolution(node, parent)) {\r\n return true;\r\n }\r\n\r\n let found = false;\r\n\r\n ts.forEachChild(node, child => {\r\n if (!found) {\r\n found = containsResolvableIdentifier(child, node);\r\n }\r\n });\r\n\r\n return found;\r\n}\r\n\r\n/**\r\n * Returns true if the identifier needs to be resolved against the context\r\n * or prefixed with `this.` — i.e. it is not a global/builtin identifier\r\n * and not the property-name side of a member access expression.\r\n */\r\nfunction needsResolution(node: ts.Identifier, parent: ts.Node): boolean {\r\n return !((ts.isPropertyAccessExpression(parent) && parent.name === node) || GLOBAL_IDENTIFIERS.has(node.text));\r\n}\r\n\r\n/**\r\n * Indents each line of a code block by two spaces.\r\n */\r\nexport function indent(...lines: string[]): string[] {\r\n return lines.map(line => ` ${line}`);\r\n} \r\n\r\n/**\r\n * Generates a unique variable name for an element based on its tag name and parent node.\r\n * If the parent node is 'this._root', the identifier will be based solely on the element's type.\r\n * Otherwise, it will be prefixed with the parent node's name to ensure uniqueness.\r\n * @param node The ElementNode for which to generate the identifier.\r\n * @param parentNode The name of the parent node to ensure uniqueness in the context of nested elements.\r\n * @returns A string representing the unique variable name for the element.\r\n */\r\nexport function getElementIdentifier(node: ElementNode, parentNode: string, index: string): string {\r\n return parentNode !== ROOT_NODE ? `${parentNode}_${node.tagName}${index}` : `${node.tagName}${index}`;\r\n}\r\n\r\nexport function getTextIdentifier(parentNode: string, index: string, prefix = 'text'): string {\r\n return parentNode !== ROOT_NODE ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`;\r\n}\r\n\r\n","import { ConstDeclarationNode } from '../../parser/types/nodes/const-declaration-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a `@const` declaration node.\r\n * Emits a `const name = expression;` JavaScript statement.\r\n *\r\n * @param node The `ConstDeclarationNode` to process.\r\n * @param _nodeName Unused node name.\r\n * @param _parentNode Unused parent node name.\r\n * @param _context Unused render context.\r\n * @returns Array containing the generated const statement string.\r\n */\r\nexport function processConstDeclaration(node: ConstDeclarationNode, _nodeName: string, _parentNode: string, context: Context): string[] {\r\n context.addIdentifier(node.varName);\r\n \r\n return [\r\n `const ${node.varName} = ${resolveExpression(node.expression, context)};`\r\n ];\r\n}\r\n","import { ElementNode } from '../../parser/types/nodes/element-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { getElementIdentifier, resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for an HTML element node: creates the DOM element, sets attributes,\r\n * attaches event listeners, appends it to the parent, and recursively processes children.\r\n *\r\n * @param node The `ElementNode` to process.\r\n * @param nodeName Variable name to use for the created DOM element.\r\n * @param parentNode Variable name of the parent DOM node to append to.\r\n * @param context Current render scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processElement(node: ElementNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const childrenContext = new Context([], context);\r\n const tagName = node.tagName;\r\n\r\n return [\r\n `const ${nodeName} = document.createElement(\"${tagName}\");`,\r\n ...(node.attributes?.map(attr => {\r\n const value = attr.value;\r\n return typeof value === \"string\" \r\n ? `${nodeName}.setAttribute('${attr.name}', ${value});`\r\n : `effect(() => ${nodeName}.setAttribute('${attr.name}', ${resolveExpression(value.expression, context)}));`\r\n }) || []),\r\n ...(node.events?.map(event => `${nodeName}.addEventListener(\"${event.name}\", ($event) => this.${event.handler});`) || []),\r\n `${parentNode}.appendChild(${nodeName});`,\r\n ...(node.children.map((child, i) => processNode(child, i.toString(), nodeName, childrenContext)).flat())\r\n ];\r\n}\r\n","import { ForImplicitVariables } from '../../parser/types/nodes/for-implicit-variables.js';\r\nimport { ForNode } from '../../parser/types/nodes/for-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { getTextIdentifier, indent } from '../utils/render-generator.utils.js';\r\n \r\n/**\r\n * Generates code for a `@for` iteration node.\r\n *\r\n * Emits a classic index-based `for` loop with all implicit variables\r\n * declared at the top of the loop body:\r\n *\r\n * ```javascript\r\n * for (let $i = 0; $i < ctx_items.length; $i++) {\r\n * const item = items[$i];\r\n * const $index = $i;\r\n * const $first = $i === 0;\r\n * const $last = $i === items.length - 1;\r\n * const $even = $i % 2 === 0;\r\n * const $odd = $i % 2 !== 0;\r\n * // ... child nodes\r\n * }\r\n * ```\r\n *\r\n * The iterable identifier is resolved through the active {@link Context}:\r\n * if found in scope it is used as-is, otherwise `this.` is prepended.\r\n *\r\n * The internal loop counter is always named `$i_<nodeName>` to avoid\r\n * collisions when `@for` blocks are nested.\r\n *\r\n * @param node - The `ForNode` to process.\r\n * @param nodeName - Base variable name prefix used for child nodes and\r\n * to produce a unique loop counter identifier.\r\n * @param parentNode - Variable name of the parent DOM node.\r\n * @param parentContext - The enclosing scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processFor(node: ForNode, nodeName: string, parentNode: string, parentContext: Context): string[] {\r\n const iterableSource = node.iterableSource;\r\n const iterableExpr = parentContext.getIdentifier(iterableSource) ?? `this.${iterableSource}`;\r\n\r\n const itemsName = getTextIdentifier(parentNode, nodeName, 'items');\r\n const counterName = getTextIdentifier(parentNode, nodeName, 'i');\r\n \r\n const indexName = resolveImplicit(node, '$index');\r\n const firstName = resolveImplicit(node, '$first');\r\n const lastName = resolveImplicit(node, '$last');\r\n const evenName = resolveImplicit(node, '$even');\r\n const oddName = resolveImplicit(node, '$odd');\r\n const forContext = new Context([node.itemAlias, indexName, firstName, lastName, evenName, oddName], parentContext);\r\n\r\n return [\r\n `const ${itemsName} = ${iterableExpr};`,\r\n `for (let ${counterName} = 0; ${counterName} < ${itemsName}.length; ${counterName}++) {`,\r\n ...indent(`const ${node.itemAlias} = ${itemsName}[${counterName}];`),\r\n ...indent(`const ${indexName} = ${counterName};`),\r\n ...indent(`const ${firstName} = ${counterName} === 0;`),\r\n ...indent(`const ${lastName} = ${counterName} === ${itemsName}.length - 1;`),\r\n ...indent(`const ${evenName} = ${counterName} % 2 === 0;`),\r\n ...indent(`const ${oddName} = ${counterName} % 2 !== 0;`),\r\n ...indent(''),\r\n ... node.children.flatMap((child, i) => indent(...processNode(child, `${nodeName}_${i}`, parentNode, forContext))),\r\n '}',\r\n ];\r\n}\r\n\r\n/**\r\n * Resolves the name that should be used in generated code for a given\r\n * implicit variable.\r\n *\r\n * If the template declared an explicit alias for the variable\r\n * (e.g. `; $index = i`) that alias is returned. Otherwise the default\r\n * implicit variable name (e.g. `$index`) is used.\r\n *\r\n * @param node - The `ForNode` whose implicit alias map is consulted.\r\n * @param implicit - The implicit variable to look up (e.g. `'$index'`).\r\n * @returns The alias string if one was declared, otherwise `implicit` itself.\r\n */\r\nfunction resolveImplicit(node: ForNode, implicit: ForImplicitVariables): string {\r\n return node.implicitAliases.get(implicit) ?? implicit;\r\n}","import { ASTNodeType } from '../../parser/types/node.enum.js';\r\nimport { ElseIfNode } from '../../parser/types/nodes/else-if-node.type.js';\r\nimport { ElseNode } from '../../parser/types/nodes/else-node.type.js';\r\nimport { IfNode } from '../../parser/types/nodes/if-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { indent, resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for an `@if` conditional node.\r\n * Emits an `if (...) { ... }` block, appending an `else { ... }` block if an alternate exists.\r\n *\r\n * @param node The `IfNode` to process.\r\n * @param nodeName Base variable name prefix for child nodes.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param context Current render scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processIf(node: IfNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const ifContext = new Context([], context);\r\n\r\n const code = [\r\n `if (${resolveExpression(node.conditionNode, context)}) {`,\r\n ...processConsequent(node, nodeName, parentNode, ifContext),\r\n '}'\r\n ];\r\n\r\n let alt = node.alternate;\r\n while (alt?.type === ASTNodeType.ElseIf) {\r\n const elseIfContext = new Context([], context);\r\n\r\n code[code.length - 1] += ` else if (${resolveExpression(alt.conditionNode, context)}) {`\r\n code.push(\r\n ...processConsequent(alt, nodeName, parentNode, elseIfContext),\r\n '}'\r\n );\r\n alt = alt.alternate;\r\n }\r\n \r\n if (alt) {\r\n const elseContext = new Context([], context);\r\n code[code.length - 1] += ' else {';\r\n code.push(\r\n ...processConsequent(alt, nodeName, parentNode, elseContext),\r\n '}'\r\n );\r\n }\r\n\r\n return code;\r\n}\r\n\r\nfunction processConsequent(node: IfNode | ElseIfNode | ElseNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n return node.consequent.map((child, i) => indent(...processNode(child, `${nodeName}_${i}`, parentNode, context))).flat();\r\n}","import { SwitchNode } from '../../parser/types/nodes/switch-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { indent, resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a `@switch` node.\r\n * Emits a `switch (expression) { case ...: { ... break; } ... }` block.\r\n *\r\n * @param node The `SwitchNode` to process.\r\n * @param nodeName Base variable name prefix for child nodes.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param context Current render scope context.\r\n * @param processNode Recursive node processor function.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processSwitch(node: SwitchNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n return [\r\n `switch (${resolveExpression(node.expression, context)}) {`,\r\n ...node.cases.map(caseNode => ([\r\n ...indent(\r\n ...(!caseNode.condition ? ['default: {'] : caseNode.condition.map((cond, i, arr) => `case ${cond}:${i === arr.length - 1 ? ' {' : ''}`)),\r\n ...caseNode.children.map((child, i) => indent(...processNode(child, `${nodeName}_${i}_${i}`, parentNode, new Context([], context)))).flat(),\r\n `${indent('break;')}`,\r\n `}`\r\n )\r\n ])).flat(),\r\n '}'\r\n ];\r\n}\r\n","import { ASTNodeType } from '../../parser/types/node.enum.js';\r\nimport { InterpolationNode } from '../../parser/types/nodes/interpolation-node.type.js';\r\nimport { TextNode } from '../../parser/types/nodes/text-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a text or interpolation node.\r\n * Creates a DOM text node with either a JSON-stringified literal or a resolved expression,\r\n * then appends it to the parent DOM node.\r\n *\r\n * @param node A `TextNode` or `InterpolationNode` to process.\r\n * @param nodeName Variable name for the created text node.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param _context Unused render context.\r\n * @returns Array of two generated code lines: the text node creation and the appendChild call.\r\n */\r\nexport function processTextAndInterpolation(node: TextNode | InterpolationNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const textValue = node.type === ASTNodeType.Text ? JSON.stringify(node.value) : resolveExpression(node.expression, context);\r\n\r\n return [\r\n `const ${nodeName} = document.createTextNode(${textValue});`,\r\n `${parentNode}.appendChild(${nodeName});`,\r\n `effect(() => ${nodeName}.textContent = ${textValue});`\r\n ];\r\n}\r\n","import { NoArgsFunction } from \"@xaendar/types\";\r\nimport { ASTNode } from \"../parser/types/ast.type.js\";\r\nimport { ASTNodeType } from \"../parser/types/node.enum.js\";\r\nimport { Context } from \"./models/render-context.model.js\";\r\nimport { processConstDeclaration } from \"./states/process-const-declaration.state.js\";\r\nimport { processElement } from \"./states/process-element.state.js\";\r\nimport { processFor } from \"./states/process-for.state.js\";\r\nimport { processIf } from \"./states/process-if.state.js\";\r\nimport { processSwitch } from \"./states/process-switch.state.js\";\r\nimport { processTextAndInterpolation } from \"./states/process-text-and-interpolation.state.js\";\r\nimport { getElementIdentifier, getTextIdentifier, indent, ROOT_NODE } from \"./utils/render-generator.utils.js\";\r\n\r\nconst nodeToProcess = new Map<string, NoArgsFunction<string[]>>;\r\n\r\n/**\r\n * Generates the TypeScript body of a render function from an AST.\r\n *\r\n * @param ast Top-level AST nodes produced by the Parser\r\n * @returns String containing the render function body\r\n */\r\nexport function generateRenderFunction(ast: ASTNode[], cssVariableName: string): string {\r\n nodeToProcess.clear();\r\n const context = new Context;\r\n\r\n const renderFunctions = [\r\n '_render() {',\r\n ...indent(\r\n `this._root.adoptedStyleSheets = [${cssVariableName}];`,\r\n ...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE, context)]).flat()\r\n ),\r\n '}',\r\n ]\r\n\r\n while (nodeToProcess.size > 0) {\r\n const [key, fn] = nodeToProcess.entries().next().value!;\r\n renderFunctions.push(\r\n `${key} {`,\r\n ...indent(...fn()),\r\n '}',\r\n );\r\n nodeToProcess.delete(key);\r\n }\r\n\r\n return renderFunctions.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Generates code that appends `nodeName` to `parentNode`.\r\n * For flow control nodes no single var is produced; instead multiple children\r\n * are appended directly inside the control flow block.\r\n */\r\nexport function processNode(node: ASTNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n switch (node.type) {\r\n case ASTNodeType.Text:\r\n case ASTNodeType.Interpolation:\r\n return processTextAndInterpolation(node, getTextIdentifier(parentNode, nodeName), parentNode, context);\r\n\r\n case ASTNodeType.Element:\r\n return processElement(node, getElementIdentifier(node, parentNode, nodeName), parentNode, context);\r\n\r\n case ASTNodeType.If:\r\n const keyIf = `control_flow_if_${nodeName}()`\r\n nodeToProcess.set(keyIf, () => processIf(node, nodeName, parentNode, context));\r\n return [`this.${keyIf};`];\r\n\r\n case ASTNodeType.For:\r\n const keyFor = `control_flow_for_${nodeName}()`\r\n nodeToProcess.set(keyFor, () => processFor(node, nodeName, parentNode, context));\r\n return [`this.${keyFor};`];\r\n\r\n case ASTNodeType.Switch:\r\n const keySwitch = `control_flow_switch_${nodeName}()`\r\n nodeToProcess.set(keySwitch, () => processSwitch(node, nodeName, parentNode, context));\r\n return [`this.${keySwitch};`];\r\n\r\n case ASTNodeType.ConstDeclaration:\r\n return processConstDeclaration(node, nodeName, parentNode, context);\r\n\r\n default:\r\n return [];\r\n }\r\n}\r\n","import { Lexer } from \"./lexer/lexer\";\r\nimport { Parser } from \"./parser/parser\";\r\nimport { generateRenderFunction } from \"./render-generator/render-generator\";\r\n\r\nexport function compile(input: string, cssVariableName: string): string {\r\n const tokens = new Lexer(input).tokenize();\r\n const ast = new Parser(tokens).parse();\r\n return generateRenderFunction(ast, cssVariableName);\r\n}"],"mappings":"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"}
1
+ {"version":3,"file":"xaendar-compiler.es.js","names":[],"sources":["../../../packages/compiler/src/lexer/types/lexer-state.enum.ts","../../../packages/compiler/src/lexer/types/token-type.enum.ts","../../../packages/compiler/src/lexer/states/attribute.state.ts","../../../packages/compiler/src/lexer/utils/consume-flow-control-condition.utils.ts","../../../packages/compiler/src/lexer/states/case-flow-control-condition.state.ts","../../../packages/compiler/src/lexer/states/const-declaration.ts","../../../packages/compiler/src/lexer/states/event.state.ts","../../../packages/compiler/src/lexer/states/flow-control-block.state.ts","../../../packages/compiler/src/lexer/states/default-flow-control-condition.state.ts","../../../packages/compiler/src/lexer/states/flow-control.ts","../../../packages/compiler/src/lexer/states/interpolation-expression.state.ts","../../../packages/compiler/src/lexer/states/interpolation-literal.state.ts","../../../packages/compiler/src/utils/chars.utils.ts","../../../packages/compiler/src/lexer/states/interpolation.state.ts","../../../packages/compiler/src/lexer/states/tag-body.state.ts","../../../packages/compiler/src/lexer/states/tag-close.state.ts","../../../packages/compiler/src/lexer/states/tag-open-end.state.ts","../../../packages/compiler/src/lexer/states/tag-open-name.state.ts","../../../packages/compiler/src/lexer/states/text.state.ts","../../../packages/compiler/src/lexer/types/lexer-cursor.model.ts","../../../packages/compiler/src/lexer/lexer.ts","../../../packages/compiler/src/parser/models/parser-cursor.model.ts","../../../packages/compiler/src/parser/types/node.enum.ts","../../../packages/compiler/src/parser/states/parse-const-declaration.state.ts","../../../packages/compiler/src/parser/states/parse-interpolation.state.ts","../../../packages/compiler/src/parser/states/parse-attribute.state.ts","../../../packages/compiler/src/parser/states/parse-event.state.ts","../../../packages/compiler/src/parser/states/parse-element.state.ts","../../../packages/compiler/src/parser/utils/expression-validator.ts","../../../packages/compiler/src/parser/states/parse-block-children.state.ts","../../../packages/compiler/src/parser/states/parse-for.state.ts","../../../packages/compiler/src/parser/states/parse-if.state.ts","../../../packages/compiler/src/parser/states/parse-switch.state.ts","../../../packages/compiler/src/parser/states/parse-text.state.ts","../../../packages/compiler/src/parser/parser.ts","../../../packages/compiler/src/render-generator/models/render-context.model.ts","../../../packages/compiler/src/render-generator/utils/render-generator.utils.ts","../../../packages/compiler/src/render-generator/states/process-const-declaration.state.ts","../../../packages/compiler/src/render-generator/states/process-element.state.ts","../../../packages/compiler/src/render-generator/states/process-for.state.ts","../../../packages/compiler/src/render-generator/states/process-if.state.ts","../../../packages/compiler/src/render-generator/states/process-switch.state.ts","../../../packages/compiler/src/render-generator/states/process-text-and-interpolation.state.ts","../../../packages/compiler/src/render-generator/render-generator.ts","../../../packages/compiler/src/compile.ts"],"sourcesContent":["/**\r\n * Represents the set of states the lexer can be in while processing template input.\r\n */\r\nexport enum LexerState {\r\n /**\r\n * Initial state before any input has been processed.\r\n */\r\n START = 'start',\r\n /**\r\n * Consuming plain text content between tags or at the top level.\r\n */\r\n TEXT = 'text',\r\n /**\r\n * Consuming the opening tag name after `<`.\r\n */\r\n TAG_OPEN_NAME = 'tag-open-name',\r\n /**\r\n * Inside an open tag body, scanning for attributes, events, or the closing `>`.\r\n */\r\n TAG_BODY = 'tag-body',\r\n /**\r\n * Processing the end of an open tag: `>` or `/>`.\r\n */\r\n TAG_OPEN_END = 'tag-open-end',\r\n /**\r\n * Consuming a closing tag `</tagName>`.\r\n */\r\n TAG_CLOSE = 'tag-close',\r\n /**\r\n * Consuming an HTML attribute name and its optional value.\r\n */\r\n ATTRIBUTE = 'attribute',\r\n /**\r\n * Consuming a DOM event binding starting with `@`.\r\n */\r\n EVENT = 'event',\r\n /**\r\n * Dispatching a flow-control keyword (@if, @for, @switch, etc.).\r\n */\r\n FLOW_CONTROL = 'flow-control',\r\n /**\r\n * Consuming the condition expression `(...)` of a flow-control directive.\r\n */\r\n FLOW_CONTROL_CONDITION = 'flow-control-condition',\r\n /**\r\n * Consuming the condition expression `(...)` of a @case directive.\r\n * This is needed to correctly handle special consecutives @case \r\n */\r\n CASE_FLOW_CONTROL_CONDITION = 'case-flow-control-condition',\r\n /**\r\n * Consuming the opening `{` of a flow-control block body.\r\n */\r\n FLOW_CONTROL_BLOCK = 'flow-control-block',\r\n /**\r\n * Dispatching between an expression or literal interpolation after `{`.\r\n */\r\n INTERPOLATION = 'interpolation',\r\n /**\r\n * Consuming a JavaScript expression inside `{ }`.\r\n */\r\n INTERPOLATION_EXPRESSION = 'interpolation-expression',\r\n /**\r\n * Consuming a template-literal string inside `` {`...`} ``.\r\n */\r\n INTERPOLATION_LITERAL = 'interpolation-literal',\r\n /**\r\n * Consuming a `@const name = expression;` declaration.\r\n */\r\n CONST_DECLARATION = 'const-declaration'\r\n}\r\n","/**\r\n * Discriminant values that identify the type of each token emitted by the lexer.\r\n */\r\nexport enum TokenType {\r\n /**\r\n * A plain text node between tags or at the top level.\r\n */\r\n TEXT,\r\n /**\r\n * The name portion of an opening tag, e.g. `div` in `<div`.\r\n */\r\n TAG_OPEN_NAME,\r\n /**\r\n * A self-closing tag marker `/>`.\r\n */\r\n TAG_SELF_CLOSE,\r\n /**\r\n * The closing `>` of an opening tag.\r\n */\r\n TAG_OPEN_END,\r\n /**\r\n * The name portion of a closing tag, e.g. `div` in `</div>`.\r\n */\r\n TAG_CLOSE_NAME,\r\n /**\r\n * An HTML attribute and its optional value.\r\n */\r\n ATTRIBUTE,\r\n /**\r\n * A DOM event binding declared with `@eventName=handler`.\r\n */\r\n EVENT,\r\n /**\r\n * A template-literal interpolation string enclosed in `` {`...`} ``.\r\n */\r\n INTERPOLATION_LITERAL,\r\n /**\r\n * A JavaScript expression interpolation enclosed in `{ }`.\r\n */\r\n INTERPOLATION_EXPRESSION,\r\n /**\r\n * A `@const name = expression;` template-level constant declaration.\r\n */\r\n CONST_DECLARATION,\r\n /**\r\n * Opening keyword of an `@if` directive.\r\n */\r\n IF,\r\n /**\r\n * Opening keyword of a `@for` directive.\r\n */\r\n FOR,\r\n /**\r\n * Opening keyword of an `@else` branch.\r\n */\r\n ELSE,\r\n /**\r\n * Opening keyword of an `@else if` branch.\r\n */\r\n ELSE_IF,\r\n /**\r\n * Opening keyword of a `@switch` directive.\r\n */\r\n SWITCH,\r\n /**\r\n * Opening keyword of a `@case` branch.\r\n */\r\n CASE,\r\n /**\r\n * Opening keyword of a `@default` branch.\r\n */\r\n DEFAULT,\r\n /**\r\n * The condition expression `(...)` associated with a flow-control directive.\r\n */\r\n CONDITION,\r\n /**\r\n * The opening `{` of a flow-control block body.\r\n */\r\n BLOCK_OPEN,\r\n /**\r\n * The closing `}` of a flow-control block body.\r\n */\r\n BLOCK_CLOSE,\r\n /**\r\n * Sentinel token emitted when the end of the input is reached.\r\n */\r\n EOF\r\n}\r\n","import { GREATER_THEN, LEFT_BRACE, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes an attribute name and optional value from the current position,\r\n * transitioning back to TAG_BODY when a space, `/`, or `>` is encountered.\r\n * If the attribute value is an interpolation, pushes the INTERPOLATION state.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of the attribute.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the ATTRIBUTE token and next state.\r\n */\r\nexport function consumeAttribute(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let attribute = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{\r\n type: TokenType.ATTRIBUTE,\r\n parts: [attribute]\r\n }] \r\n };\r\n read = false;\r\n break;\r\n\r\n case LEFT_BRACE:\r\n retVal = {\r\n state: LexerState.INTERPOLATION,\r\n tokens: [{\r\n type: TokenType.ATTRIBUTE,\r\n parts: [attribute]\r\n }],\r\n pushState: true \r\n };\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n attribute = `${attribute}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { LPAREN, RPAREN } from \"../../costants/chars.constants\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type\";\r\n\r\nexport function consumeFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): string {\r\n cursor.skipSpaces();\r\n\r\n if (cursor.peek() !== LPAREN) {\r\n throw new Error(`Expected '(' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`)\r\n }\r\n\r\n // consume '('\r\n cursor.advance();\r\n\r\n let expression = '';\r\n let depth = 1;\r\n\r\n while (depth > 0) {\r\n const code = cursor.peek();\r\n\r\n switch (code) {\r\n case LPAREN:\r\n depth++;\r\n expression = addCharacter(cursor, expression);\r\n break;\r\n\r\n case RPAREN:\r\n depth--;\r\n if (!depth) {\r\n cursor.advance();\r\n break;\r\n }\r\n\r\n expression = addCharacter(cursor, expression);\r\n break;\r\n\r\n default:\r\n expression = addCharacter(cursor, expression);\r\n }\r\n }\r\n\r\n return expression;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param expression The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nexport function addCharacter(cursor: LexerCursor, expression: string): string {\r\n cursor.advance();\r\n return `${expression}${cursor.currentChar.value}`;\r\n}","import { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\nimport { consumeFlowControlCondition } from \"../utils/consume-flow-control-condition.utils.js\";\r\n\r\n/**\r\n * Consumes the condition expression `(...)` of a flow-control directive,\r\n * handling nested parentheses correctly. Emits a CONDITION token with the\r\n * raw expression string and transitions to FLOW_CONTROL_BLOCK.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening `(`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.\r\n */\r\nexport function consumeCaseFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n const condition = consumeFlowControlCondition(cursor, _context);\r\n cursor.skipSpaces();\r\n\r\n return {\r\n state: cursor.peekMatch('@case') ? LexerState.FLOW_CONTROL : LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.CONDITION,\r\n parts: [condition]\r\n }],\r\n popState: true\r\n };\r\n}\r\n","import { EQUAL_THEN, SEMICOLON, SPACE } from \"../../costants/chars.constants\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model\";\r\nimport { LexerState } from \"../types/lexer-state.enum\";\r\nimport { TokenType } from \"../types/token-type.enum\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type\";\r\n\r\n/**\r\n * Consumes a `@const name = expression;` declaration from the current position.\r\n * Expects the cursor to be positioned after the `@const ` keyword.\r\n * Emits a CONST_DECLARATION token containing the variable name and initializer expression.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of the variable name.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONST_DECLARATION token and the TEXT state.\r\n */\r\nexport function consumeConstDeclaration(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let varName = '';\r\n let expression = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n /*\r\n Skip all possible spaces between the 'const' identifier and the '='\r\n @const varName\r\n or\r\n @const varName\r\n */\r\n cursor.skipSpaces();\r\n\r\n while(read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n read = false;\r\n break;\r\n\r\n default: \r\n cursor.advance();\r\n varName = `${varName}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n /*\r\n Skip all possible spaces between the varName and the '='\r\n varName =\r\n or\r\n varName =\r\n */\r\n cursor.skipSpaces();\r\n\r\n const nextChar = cursor.peek();\r\n if (nextChar !== EQUAL_THEN) {\r\n throw new Error(`Unexpected character ${String.fromCharCode(nextChar)}.\\nExpected '=' `);\r\n }\r\n \r\n cursor.advance();\r\n /*\r\n Skip all possible spaces between the '=' and the expression\r\n = user.name\r\n or\r\n = user.name\r\n */\r\n cursor.skipSpaces();\r\n read = true\r\n\r\n while(read) {\r\n switch (cursor.peek()) {\r\n case SEMICOLON:\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.CONST_DECLARATION,\r\n parts: [varName, expression]\r\n }]\r\n }\r\n read = false;\r\n break;\r\n\r\n default: \r\n cursor.advance();\r\n expression = `${expression}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n // Consume ';'\r\n cursor.advance();\r\n expression = `${expression};`\r\n\r\n return retVal;\r\n}","import { GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a DOM event binding starting with `@` and reads until a delimiter\r\n * (space, `/`, or `>`) is found. Emits an EVENT token containing the raw binding string.\r\n *\r\n * @param cursor The lexer cursor positioned on the `@` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the EVENT token and the TAG_BODY state.\r\n */\r\nexport function consumeEvent(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let event = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '@' character\r\n cursor.advance();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n /*\r\n Special case to handle syntax sugar for event bindings:\r\n If the desired function to be binded is the equal to the event name\r\n with the \"on\" prefix, automatically generate the binding string.\r\n Ex: @click=\"onClick\" can be written as @click, and the emitted token will have \"onClick\" as part\r\n */\r\n if (!event.includes('=')) {\r\n event = `${event}=on${event[0]!.toUpperCase()}${event.slice(1)}($event)`;\r\n }\r\n\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{ \r\n type: TokenType.EVENT, \r\n parts: [event] \r\n }]\r\n };\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n event = `${event}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { LEFT_BRACE } from \"../../costants/chars.constants.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Consumes the opening `{` of a flow control block body,\r\n * skipping any leading whitespace before it.\r\n *\r\n * Emits a BLOCK_OPEN token and transitions to TEXT,\r\n * pushing FLOW_CONTROL_BLOCK onto the state stack.\r\n * This allows consumeText to later recognise the matching `}` as a BLOCK_CLOSE\r\n * rather than as an interpolation boundary.\r\n *\r\n * Used by: @if, @for, @switch, @case, @else, @default\r\n */\r\nexport function consumeFlowControlBlock(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n cursor.skipSpaces();\r\n\r\n if (cursor.peek() !== LEFT_BRACE) {\r\n throw new Error(`Expected '{' but got '${String.fromCharCode(cursor.peek())}' at row ${cursor.position.row}, col ${cursor.position.column}`);\r\n }\r\n\r\n // consume '{'\r\n cursor.advance();\r\n\r\n return {\r\n state: LexerState.TEXT,\r\n tokens: [{ type: TokenType.BLOCK_OPEN }],\r\n pushState: true\r\n };\r\n}\r\n","import { CR, LF } from \"../../costants/chars.constants.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\nimport { consumeFlowControlCondition } from \"../utils/consume-flow-control-condition.utils.js\";\r\n\r\n/**\r\n * Consumes the condition expression `(...)` of a flow-control directive,\r\n * handling nested parentheses correctly. Emits a CONDITION token with the\r\n * raw expression string and transitions to FLOW_CONTROL_BLOCK.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening `(`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the CONDITION token and the FLOW_CONTROL_BLOCK state.\r\n */\r\nexport function consumeDefaultFlowControlCondition(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n return {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.CONDITION,\r\n parts: [consumeFlowControlCondition(cursor, _context)]\r\n }],\r\n popState: true\r\n };\r\n}\r\n","import { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Dispatches on a `@keyword` to determine which flow-control directive begins here.\r\n * Recognises `@if`, `@for`, `@else`, `@switch`, `@case`, `@default`, and `@const`.\r\n * Advances the cursor past the keyword and transitions to the appropriate next state.\r\n *\r\n * @param cursor The lexer cursor positioned on the `@` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the matching flow-control token and next state.\r\n */\r\nexport function consumeFlowControl(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '@' character\r\n cursor.advance();\r\n\r\n if (cursor.peekMatch('for ')) {\r\n cursor.advance(4);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.FOR\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('if ')) {\r\n cursor.advance(2);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.IF\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('else if ')) {\r\n cursor.advance(8);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.ELSE_IF\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('else ')) {\r\n cursor.advance(5);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.ELSE\r\n }]\r\n }\r\n } else if (cursor.peekMatch('switch ')) {\r\n cursor.advance(7);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.SWITCH\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('case ')) {\r\n cursor.advance(5);\r\n retVal = {\r\n state: LexerState.CASE_FLOW_CONTROL_CONDITION,\r\n tokens: [{\r\n type: TokenType.CASE\r\n }],\r\n pushState: true\r\n }\r\n } else if (cursor.peekMatch('default ')) {\r\n cursor.advance(8);\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL_BLOCK,\r\n tokens: [{\r\n type: TokenType.DEFAULT\r\n }]\r\n }\r\n } else if (cursor.peekMatch('const ')) {\r\n cursor.advance(6);\r\n retVal = {\r\n state: LexerState.CONST_DECLARATION\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { LEFT_BRACE, RIGHT_BRACE, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a JavaScript expression interpolation `{ expression }`, tracking nested\r\n * brace depth. Emits an INTERPOLATION_EXPRESSION token and pops the state stack to\r\n * return to the previous state (ATTRIBUTE or TEXT).\r\n *\r\n * @param cursor The lexer cursor positioned at the first character of the expression.\r\n * @param context Lexer context used to retrieve the previous state for restoration.\r\n * @returns Transition result with the INTERPOLATION_EXPRESSION token and restored state.\r\n */\r\nexport function consumeInterpolationExpression(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let interpolation = '';\r\n let deep = 1\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case LEFT_BRACE:\r\n deep++;\r\n interpolation = addCharacter(cursor, interpolation);\r\n break;\r\n\r\n case RIGHT_BRACE:\r\n deep--;\r\n \r\n if (deep === 0) {\r\n cursor.advance();\r\n /*\r\n After an interpolation we have to understanad where to transite\r\n The next state depends from the previous state\r\n */\r\n const previousState = context.history.pop();\r\n let state!: LexerState;\r\n\r\n switch (previousState) {\r\n case LexerState.ATTRIBUTE:\r\n /*\r\n This is a special case to handle syntax sugar for attribute interpolations:\r\n If the attribute name and the variable binded have the same indentifier it can be written\r\n from attribute={attribute} to {attribute}\r\n \r\n In this case the attribute token emitted by the previosu state will have an empty string\r\n as part and we need to fill it with the actual interpolation content\r\n\r\n This is tricky but it allows to avoid unnecessary complication in the parser and\r\n render generator, by keeping this syntax sugar as a purely lexical feature and\r\n by redirecting to the standard flow for attribute interpolations after the lexer\r\n */\r\n const lastToken = context.tokens[context.tokens.length - 1];\r\n if (lastToken?.type === TokenType.ATTRIBUTE && !lastToken.parts[0]) {\r\n lastToken.parts[0] = `${interpolation}=`;\r\n }\r\n state = LexerState.TAG_BODY\r\n break;\r\n\r\n case LexerState.TEXT:\r\n state = LexerState.TEXT\r\n };\r\n\r\n retVal = {\r\n state,\r\n tokens: [{ \r\n type: TokenType.INTERPOLATION_EXPRESSION, \r\n parts: [interpolation] \r\n }],\r\n popState: true\r\n }\r\n read = false;\r\n } else {\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n\r\n break;\r\n\r\n default:\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n }\r\n\r\n return retVal;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param interpolation The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nfunction addCharacter(cursor: LexerCursor, interpolation: string): string {\r\n cursor.advance(1);\r\n return `${interpolation}${cursor.currentChar.value}`;\r\n}","import { GRAVE_ACCENT, RIGHT_BRACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a template-literal interpolation `` {`...`} ``, collecting characters\r\n * until the closing backtick followed by `}`. Emits an INTERPOLATION_LITERAL token\r\n * and pops the state stack to return to the previous state.\r\n *\r\n * @param cursor The lexer cursor positioned at the opening backtick.\r\n * @param context Lexer context used to retrieve the previous state for restoration.\r\n * @returns Transition result with the INTERPOLATION_LITERAL token and restored state.\r\n */\r\nexport function consumeInterpolationliteral(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let interpolation = '`';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '`' character\r\n cursor.advance();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case GRAVE_ACCENT:\r\n interpolation = addCharacter(cursor, interpolation);\r\n\r\n if (cursor.peek() === RIGHT_BRACE) {\r\n // Consume '}'\r\n cursor.advance();\r\n /*\r\n After an interpolation we have to understanad where to transite\r\n The next state depends from the previous state\r\n */\r\n const previousState = context.history.pop();\r\n let state!: LexerState;\r\n\r\n switch (previousState) {\r\n case LexerState.ATTRIBUTE:\r\n state = LexerState.TAG_BODY\r\n break;\r\n\r\n case LexerState.TEXT:\r\n state = LexerState.TEXT\r\n };\r\n\r\n retVal = {\r\n state,\r\n tokens: [{\r\n type: TokenType.INTERPOLATION_LITERAL,\r\n parts: [interpolation]\r\n }],\r\n popState: true\r\n }\r\n read = false;\r\n } else {\r\n /*\r\n If ` is not followed by }, it means the interpolation is not closed\r\n and ` is part of the interpolated string\r\n |\r\n ˅\r\n Example: {`text ${var} ` text`}\r\n */\r\n interpolation = `${interpolation}${cursor.currentChar.value}`\r\n }\r\n break;\r\n\r\n default:\r\n interpolation = addCharacter(cursor, interpolation);\r\n }\r\n }\r\n\r\n return retVal;\r\n}\r\n\r\n/**\r\n * Advances the cursor by one character and appends it to the accumulator string.\r\n *\r\n * @param cursor The lexer cursor to advance.\r\n * @param interpolation The current accumulated string.\r\n * @returns The updated string with the new character appended.\r\n */\r\nfunction addCharacter(cursor: LexerCursor, interpolation: string): string {\r\n cursor.advance();\r\n return `${interpolation}${cursor.currentChar.value}`;\r\n}","import { A, a, CR, LF, Z, z } from '../costants/chars.constants.js';\r\n\r\n/**\r\n * Check if char code is a Line Feed (\\n) or Carriage Return (\\r)\r\n * @param char Character to control\r\n * @returns True if character is LF or CR, false otherwise\r\n */\r\nexport function isNewLine(char: number): boolean {\r\n return char === LF || char === CR;\r\n}\r\n\r\n/**\r\n * Check if char code is is a lower case letter\r\n * @param char Character to control\r\n * @returns True if character is a lowercase letter, false otherwise\r\n */\r\nexport function isLowerCase(char: number): boolean {\r\n return char >= a && char <= z;\r\n}\r\n\r\n/**\r\n * Check if char code is is a upper case letter\r\n * @param char Character to control\r\n * @returns True if character is a upper case letter, false otherwise\r\n */\r\nexport function isUpperCase(char: number): boolean {\r\n return char >= A && char <= Z;\r\n}\r\n\r\n/**\r\n * Check if the string contains at least one character different from\r\n * ' '\r\n * \\n\r\n * \\r\r\n * \\t\r\n * \\f\r\n * \\v\r\n * @param str String to check\r\n * @returns True if string is not blank, false otherwise\r\n */\r\nexport function isNotBlank(str: string): boolean {\r\n /* \r\n Differently from the approach of the other functions\r\n here we are working with string and not numbers.\r\n\r\n Number checks are usually faster when checking a character is\r\n included in a specific range.\r\n For this case we are checking if the string contains at least one char\r\n different from a list of non adiacent characters in the ASCII code, resulting\r\n in a very long condition with multiple OR\r\n\r\n This has been proven slower than using a regex\r\n */\r\n return /\\S/.test(str)\r\n}\r\n\r\n/**\r\n * Check if given ascii code is a valid First Character\r\n * for Javasript Identifiers\r\n * @param code The ascii code to valuate\r\n * @returns True if is valid, false otherwise\r\n */\r\nexport function isJSIdentifierStart(code: number): boolean {\r\n return (\r\n (code >= 65 && code <= 90) || // A-Z\r\n (code >= 97 && code <= 122) || // a-z\r\n code === 36 || // $\r\n code === 95 // _\r\n );\r\n}","import { GRAVE_ACCENT } from '../../costants/chars.constants.js';\r\nimport { isJSIdentifierStart } from '../../utils/chars.utils.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Dispatches between an expression and a literal interpolation after the opening `{`.\r\n * Advances past `{` and any leading spaces, then inspects the next character:\r\n * a backtick routes to INTERPOLATION_LITERAL, a JS identifier start routes to INTERPOLATION_EXPRESSION.\r\n *\r\n * @param cursor The lexer cursor positioned on the `{` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the appropriate interpolation sub-state.\r\n */\r\nexport function consumeInterpolation(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Consume '{' characters\r\n cursor.advance();\r\n\r\n /*\r\n Skip all the spaces between '{' and the actual interpolation content\r\n Ex: '{ label}\r\n */\r\n cursor.skipSpaces();\r\n \r\n const nextChar = cursor.peek();\r\n\r\n if (nextChar === GRAVE_ACCENT) {\r\n retVal = { state: LexerState.INTERPOLATION_LITERAL };\r\n } else if (isJSIdentifierStart(nextChar)) {\r\n retVal = { state: LexerState.INTERPOLATION_EXPRESSION };\r\n } else {\r\n throw new Error(`Unrecognized First Character ${String.fromCharCode(nextChar)} in interpolation`);\r\n }\r\n\r\n return retVal;\r\n}","import { AT_SIGN, GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Scans the body of an open tag to determine what comes next:\r\n * an event binding (`@`), an attribute, the end of the tag (`>` or `/`), or whitespace.\r\n * Transitions to the appropriate state without emitting any tokens.\r\n *\r\n * @param cursor The lexer cursor positioned inside a tag body.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the next state and no tokens.\r\n */\r\nexport function consumeTagBody(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n while (read) {\r\n const nextChar = cursor.peek();\r\n\r\n switch (nextChar) {\r\n case AT_SIGN:\r\n retVal = {\r\n state: LexerState.EVENT\r\n }\r\n read = false;\r\n break;\r\n\r\n case SPACE:\r\n cursor.skipSpaces();\r\n break;\r\n\r\n case GREATER_THEN:\r\n case SLASH:\r\n retVal = {\r\n state: LexerState.TAG_OPEN_END\r\n }\r\n read = false;\r\n break;\r\n\r\n default:\r\n retVal = {\r\n state: LexerState.ATTRIBUTE\r\n }\r\n read = false;\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { GREATER_THEN, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes a closing tag `</tagName>`, skipping the `</` prefix and any surrounding\r\n * whitespace. Emits a TAG_CLOSE_NAME token with the tag name and transitions to TEXT.\r\n *\r\n * @param cursor The lexer cursor positioned at the `<` of a closing tag.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the TAG_CLOSE_NAME token and the TEXT state.\r\n */\r\nexport function consumeTagClose(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let tagName = '';\r\n let retVal!: LexerTransitionFunctionReturnType;\r\n\r\n // Skip '</'\r\n cursor.advance(2);\r\n\r\n /*\r\n Skip all the spaces between '</' and the actual tag name\r\n Ex: '</ div>\r\n */\r\n cursor.skipSpaces();\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case GREATER_THEN:\r\n cursor.advance();\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_CLOSE_NAME, \r\n parts: [tagName]\r\n }]\r\n };\r\n read = false;\r\n break;\r\n\r\n case SPACE:\r\n throw new Error('Tag Close Name cannot contains spaces');\r\n\r\n default:\r\n cursor.advance();\r\n tagName = `${tagName}${cursor.currentChar.value}`;\r\n }\r\n }\r\n\r\n return retVal;\r\n}","import { GREATER_THEN } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes the closing characters of an open tag: `>` emits TAG_OPEN_END and\r\n * transitions to TEXT, while `/>` emits TAG_SELF_CLOSE and also transitions to TEXT.\r\n *\r\n * @param cursor The lexer cursor positioned at `>` or `/`.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with TAG_OPEN_END or TAG_SELF_CLOSE and the TEXT state.\r\n */\r\nexport function consumeTagOpenEnd(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n // We arrive in this point by reading '>' or '/' at the end of a Open Tag \r\n if (cursor.peek() === GREATER_THEN) {\r\n cursor.advance();\r\n retVal = { \r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_OPEN_END,\r\n parts: []\r\n }] \r\n };\r\n } else {\r\n cursor.advance();\r\n const nextChar = cursor.peek();\r\n\r\n if (nextChar === GREATER_THEN) {\r\n cursor.advance();\r\n retVal = {\r\n state: LexerState.TEXT,\r\n tokens: [{\r\n type: TokenType.TAG_SELF_CLOSE,\r\n parts: []\r\n }]\r\n };\r\n } else {\r\n throw new Error(`Unexpected character ${nextChar} for closing tag.\\nExpected />\\nRead of /${String.fromCharCode(nextChar)}\\nAt line ${cursor.position.row + 1} col ${cursor.position.column + 1}`)\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { GREATER_THEN, SLASH, SPACE } from '../../costants/chars.constants.js';\r\nimport { LexerCursor } from '../types/lexer-cursor.model.js';\r\nimport { LexerState } from '../types/lexer-state.enum.js';\r\nimport { TokenType } from '../types/token-type.enum.js';\r\nimport { LexerTransitionFunctionContext } from '../types/transition-function/transition-function-context.type.js';\r\nimport { LexerTransitionFunctionReturnType } from '../types/transition-function/transition-function-return-type.type.js';\r\n\r\n/**\r\n * Consumes an opening tag name after `<`, reading until a space, `/`, or `>` is found.\r\n * Emits a TAG_OPEN_NAME token with the tag name and transitions to TAG_BODY.\r\n *\r\n * @param cursor The lexer cursor positioned at the `<` character.\r\n * @param _context Unused lexer context.\r\n * @returns Transition result with the TAG_OPEN_NAME token and the TAG_BODY state.\r\n */\r\nexport function consumeTagOpenName(cursor: LexerCursor, _context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let tagName = '';\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n // Consume '<' character\r\n cursor.advance();\r\n\r\n /*\r\n Skip all the spaces between '<' and the actual tag name\r\n Ex: '< div>\r\n */\r\n cursor.skipSpaces();\r\n\r\n /*\r\n Keep read input until:\r\n - Space: <span \r\n - GT: <span>\r\n - Slash (Self Closing tag) <span / or <span/\r\n */\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case SPACE:\r\n case SLASH:\r\n case GREATER_THEN:\r\n retVal = {\r\n state: LexerState.TAG_BODY,\r\n tokens: [{ \r\n type: TokenType.TAG_OPEN_NAME, \r\n parts: [tagName] \r\n }]\r\n }\r\n read = false;\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n tagName = `${tagName}${cursor.currentChar.value}`\r\n }\r\n }\r\n\r\n return retVal\r\n}","import { AT_SIGN, CR, LEFT_BRACE, LESS_THAN, LF, RIGHT_BRACE, SLASH } from \"../../costants/chars.constants.js\";\r\nimport { isNotBlank } from \"../../utils/chars.utils.js\";\r\nimport { LexerCursor } from \"../types/lexer-cursor.model.js\";\r\nimport { LexerState } from \"../types/lexer-state.enum.js\";\r\nimport { TokenType } from \"../types/token-type.enum.js\";\r\nimport { LexerTransitionFunctionContext } from \"../types/transition-function/transition-function-context.type.js\";\r\nimport { LexerTransitionFunctionReturnType } from \"../types/transition-function/transition-function-return-type.type.js\";\r\n\r\n/**\r\n * Consumes plain text content, accumulating characters until a structural boundary\r\n * is reached: `<` (tag open/close), `{` (interpolation), `@` (flow-control or event),\r\n * or `}` (block close). Emits a TEXT token if non-blank text was accumulated.\r\n *\r\n * @param cursor The lexer cursor positioned at the start of text content.\r\n * @param context Lexer context used to detect flow-control block boundaries.\r\n * @returns Transition result with an optional TEXT token and the next state.\r\n */\r\nexport function consumeText(cursor: LexerCursor, context: LexerTransitionFunctionContext): LexerTransitionFunctionReturnType {\r\n let read = true;\r\n let text = '';\r\n let retVal!: LexerTransitionFunctionReturnType\r\n\r\n while (read) {\r\n switch (cursor.peek()) {\r\n case LESS_THAN:\r\n // If after '<' we read a '/', we suppose we're approaching a ClosureTag, otherwise an OpenTag\r\n const nextState = cursor.peek(1, { offset: 1 }) === SLASH ? LexerState.TAG_CLOSE : LexerState.TAG_OPEN_NAME;\r\n retVal = { state: nextState }\r\n read = false;\r\n break;\r\n\r\n case LEFT_BRACE:\r\n retVal = { \r\n state: LexerState.INTERPOLATION,\r\n pushState: true\r\n };\r\n read = false;\r\n break;\r\n \r\n case AT_SIGN:\r\n retVal = {\r\n state: LexerState.FLOW_CONTROL,\r\n }\r\n read = false;\r\n break;\r\n\r\n case RIGHT_BRACE:\r\n if (context.history[context.history.length - 1] === LexerState.FLOW_CONTROL_BLOCK) {\r\n cursor.advance();\r\n retVal = { \r\n state: LexerState.TEXT,\r\n tokens: [{ type: TokenType.BLOCK_CLOSE }],\r\n popState: true \r\n };\r\n read = false;\r\n } else {\r\n cursor.advance();\r\n text = `${text}${cursor.currentChar.value}`;\r\n }\r\n break;\r\n\r\n case LF:\r\n case CR:\r\n cursor.advance();\r\n break;\r\n\r\n default:\r\n cursor.advance();\r\n text = `${text}${cursor.currentChar.value}`;\r\n }\r\n }\r\n\r\n\r\n /*\r\n If the first read character trigger a StateChange\r\n The cumulative `text` variable will be empty\r\n\r\n In this case we must NOT add any token\r\n\r\n Ex:\r\n Template starts with a tag:\r\n `<div ...`\r\n Or an interpolation:\r\n `{ myVariable }`\r\n */\r\n retVal.tokens ??= (isNotBlank(text)\r\n ? [{ type: TokenType.TEXT, parts: [text] }]\r\n : undefined);\r\n\r\n return retVal\r\n}","import { PositiveInteger, TupleOfLength } from '@xaendar/types';\r\nimport { CR, EOF, LF, SPACE } from '../../costants/chars.constants.js';\r\nimport { CurrentChar } from './current-char.type.js';\r\nimport { CursorPosition } from './current-position.type.js';\r\n\r\n/**\r\n * Cursor abstraction used by the Lexer to navigate the input source.\r\n *\r\n * The LexerCursor is responsible for:\r\n * - Sequential character consumption\r\n * - Lookahead (peek) operations without state mutation\r\n * - Tracking logical position (row, column)\r\n * - Handling end-of-file conditions\r\n *\r\n * This class deliberately contains **no lexer logic**:\r\n * it does not know about tokens, states, or grammar rules.\r\n * Its sole responsibility is controlled navigation of the input stream.\r\n */\r\nexport class LexerCursor {\r\n /**\r\n * Representation of the current character.\r\n *\r\n * - `index`: absolute index within the input string\r\n * - `code`: Unicode code point of the character\r\n * - `value`: actual character value\r\n *\r\n * An index of `-1` indicates that the cursor has not yet consumed\r\n * any character or has reached EOF.\r\n */\r\n private readonly _currentChar: CurrentChar = {\r\n code: 0,\r\n index: -1,\r\n value: ''\r\n };\r\n /**\r\n * Returns a read-only snapshot of the current character.\r\n */\r\n public get currentChar(): Readonly<CurrentChar> {\r\n return this._currentChar;\r\n }\r\n /**\r\n * Cache used by peek operations to avoid re-reading\r\n * the same character positions multiple times.\r\n *\r\n * Key: absolute character index\r\n * Value: Unicode code point\r\n */\r\n private readonly _peekCache = new Map<number, number>();\r\n /**\r\n * Logical position of the cursor in the input.\r\n *\r\n * - `row`: zero-based line number\r\n * - `column`: zero-based column number\r\n */\r\n private readonly _position: CursorPosition = {\r\n row: 0,\r\n column: 0\r\n };\r\n /**\r\n * Returns a read-only snapshot of the current cursor position.\r\n */\r\n public get position(): Readonly<CursorPosition> {\r\n return this._position;\r\n }\r\n\r\n /**\r\n * Creates a new cursor for the given input source.\r\n *\r\n * @param input Full source string to be tokenized.\r\n */\r\n constructor(public input: string) { }\r\n\r\n /**\r\n * Advances the cursor by the specified number of characters.\r\n *\r\n * This method:\r\n * - Updates the current character\r\n * - Updates row/column position\r\n * - Detects line breaks (LF / CR)\r\n * - Throws an EOF error when the end of the input is reached\r\n *\r\n * @param chars Number of characters to consume (must be >= 1)\r\n *\r\n * @throws Error with cause `EOF` when advancing past input length\r\n */\r\n public advance(chars = 1): void {\r\n if (chars < 1) {\r\n throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);\r\n }\r\n\r\n const newIndex = this._currentChar.index + chars;\r\n\r\n if (newIndex >= this.input.length) {\r\n this._currentChar.code = EOF;\r\n this._currentChar.index = -1;\r\n this._currentChar.value = '';\r\n this.throwEOFError();\r\n } else {\r\n /*\r\n Before updating the character, adjust logical position.\r\n Line breaks reset column and increment row.\r\n */\r\n if ([LF, CR].includes(this._currentChar.code)) {\r\n this._position.row++;\r\n this._position.column = 0;\r\n } else {\r\n this._position.column++;\r\n }\r\n\r\n this._currentChar.index = newIndex;\r\n this._currentChar.value = this.input[newIndex]!;\r\n this._currentChar.code = this.input.charCodeAt(newIndex);\r\n }\r\n }\r\n\r\n /**\r\n * Checks whether the upcoming characters in the input match the given pattern,\r\n * without advancing the cursor.\r\n *\r\n * - `string`: fast path using char code comparison (no allocation)\r\n * - `RegExp`: slices the input and tests the pattern against it.\r\n * Requires `length` to know how many characters to peek.\r\n *\r\n * @param pattern String or RegExp to match against\r\n * @param length Number of characters to peek — required when `pattern` is a RegExp\r\n * @returns `true` if the upcoming characters match, `false` otherwise\r\n */\r\n public peekMatch(pattern: string): boolean;\r\n public peekMatch(pattern: RegExp, length: number): boolean;\r\n public peekMatch(pattern: string | RegExp, length?: number): boolean {\r\n if (typeof pattern === 'string') {\r\n const peekedChars = this.peek(pattern.length);\r\n\r\n for (let i = 0; i < pattern.length; i++) {\r\n if (peekedChars[i] !== pattern.charCodeAt(i)) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n // RegExp path — slice input and test\r\n const start = this._currentChar.index + 1;\r\n const slice = this.input.slice(start, start + length!);\r\n return pattern.test(slice);\r\n }\r\n\r\n /**\r\n * Peeks ahead in the input stream without advancing the cursor.\r\n *\r\n * This method supports:\r\n * - Single-character lookahead\r\n * - Multi-character lookahead\r\n * - Optional offset from the current position\r\n *\r\n * Peek operations are cached for performance reasons and do not\r\n * modify the cursor state.\r\n *\r\n * @returns\r\n * - A single Unicode code point when peeking one character\r\n * - An array of Unicode code points when peeking multiple characters\r\n *\r\n * @throws Error with cause `EOF` if the peek exceeds input length\r\n */\r\n public peek(): number;\r\n public peek<OffSet extends number>(options?: { offset?: PositiveInteger<OffSet> }): number;\r\n public peek(chars: 1): number;\r\n public peek<OffSet extends number>(chars: 1, options?: { offset?: PositiveInteger<OffSet> }): number; \r\n public peek<ReadChars extends number>(chars: PositiveInteger<ReadChars>): TupleOfLength<ReadChars>; \r\n public peek<ReadChars extends number, OffSet extends number>(chars: PositiveInteger<ReadChars>, options?: { offset?: PositiveInteger<OffSet> }): TupleOfLength<ReadChars>;\r\n public peek(charsOrOptions?: number | { offset?: number }, options?: { offset?: number }): number | number[] {\r\n const cache = this._peekCache;\r\n const chars = typeof charsOrOptions === 'number' ? charsOrOptions : 1;\r\n const offset = (typeof charsOrOptions === 'object' ? charsOrOptions : options)?.offset ?? 0;\r\n return chars === 1 ? this.peekOneChar(this._currentChar.index + offset + 1, cache) : this.peekMany(chars + offset, cache);\r\n }\r\n\r\n /**\r\n * Skips all consecutive space characters from the current position.\r\n */\r\n public skipSpaces(): void {\r\n while (this.peek() === SPACE || this.peek() === LF || this.peek() === CR) {\r\n this.advance();\r\n }\r\n }\r\n\r\n /**\r\n * Peeks multiple characters ahead.\r\n */\r\n private peekMany(chars: number, cache: Map<number, number>): number[] {\r\n const peekedChars = new Array<number>;\r\n const nextCharIndex = this._currentChar.index + 1;\r\n\r\n for (let i = nextCharIndex; i < nextCharIndex + chars; i++) {\r\n peekedChars.push(this.peekOneChar(i, cache));\r\n }\r\n\r\n return peekedChars;\r\n }\r\n\r\n /**\r\n * Peeks a single character at the given absolute index.\r\n */\r\n private peekOneChar(index: number, cache: Map<number, number>): number {\r\n if (cache.has(index)) {\r\n return cache.get(index)!;\r\n }\r\n\r\n if (index >= this.input.length) {\r\n this.throwEOFError();\r\n }\r\n\r\n const charCode = this.input.charCodeAt(index);\r\n cache.set(index, charCode);\r\n return charCode;\r\n }\r\n\r\n /**\r\n * Throws a standardized EOF error used by the lexer engine\r\n * to terminate tokenization.\r\n */\r\n private throwEOFError(): never {\r\n throw new Error('', { cause: EOF });\r\n }\r\n}\r\n","import { Stack } from '@xaendar/common';\r\nimport { Dictionary } from '@xaendar/types';\r\nimport { EOF } from '../costants/chars.constants.js';\r\nimport { consumeAttribute } from './states/attribute.state.js';\r\nimport { consumeCaseFlowControlCondition } from './states/case-flow-control-condition.state.js';\r\nimport { consumeConstDeclaration } from './states/const-declaration.js';\r\nimport { consumeEvent } from './states/event.state.js';\r\nimport { consumeFlowControlBlock } from './states/flow-control-block.state.js';\r\nimport { consumeDefaultFlowControlCondition } from './states/default-flow-control-condition.state.js';\r\nimport { consumeFlowControl } from './states/flow-control.js';\r\nimport { consumeInterpolationExpression } from './states/interpolation-expression.state.js';\r\nimport { consumeInterpolationliteral } from './states/interpolation-literal.state.js';\r\nimport { consumeInterpolation } from './states/interpolation.state.js';\r\nimport { consumeTagBody } from './states/tag-body.state.js';\r\nimport { consumeTagClose } from './states/tag-close.state.js';\r\nimport { consumeTagOpenEnd } from './states/tag-open-end.state.js';\r\nimport { consumeTagOpenName } from './states/tag-open-name.state.js';\r\nimport { consumeText } from './states/text.state.js';\r\nimport { LexerCursor } from './types/lexer-cursor.model.js';\r\nimport { LexerState } from './types/lexer-state.enum.js';\r\nimport { Token } from './types/token.type.js';\r\nimport { LexerTransitionFunction } from './types/transition-function/transition-function.type.js';\r\n\r\n/**\r\n * Utility class that emulates a cursor navigating through a template string.\r\n *\r\n * The cursor keeps track of the current character, its absolute position\r\n * within the text, and its logical position expressed as row and column.\r\n * This is useful when parsing or analyzing template content character by character.\r\n */\r\nexport class Lexer {\r\n /**\r\n * Cursor for navigating the input character stream.\r\n */\r\n private readonly _cursor: LexerCursor;\r\n /**\r\n * Current lexer state.\r\n */\r\n private _state = LexerState.START;\r\n /**\r\n * State stack used to support nested states (e.g. interpolations).\r\n */\r\n private _stack = new Stack<LexerState>;\r\n /**\r\n * Accumulated list of tokens emitted during tokenization.\r\n */\r\n private readonly _tokens = new Array<Token>;\r\n /**\r\n * Maps each lexer state to its corresponding transition function.\r\n */\r\n private readonly _states: Dictionary<LexerState, LexerTransitionFunction> = {\r\n [LexerState.START]: consumeText,\r\n [LexerState.TEXT]: consumeText,\r\n [LexerState.TAG_OPEN_NAME]: consumeTagOpenName,\r\n [LexerState.TAG_BODY]: consumeTagBody,\r\n [LexerState.TAG_OPEN_END]: consumeTagOpenEnd,\r\n [LexerState.TAG_CLOSE]: consumeTagClose,\r\n [LexerState.ATTRIBUTE]: consumeAttribute,\r\n [LexerState.FLOW_CONTROL]: consumeFlowControl,\r\n [LexerState.FLOW_CONTROL_CONDITION]: consumeDefaultFlowControlCondition,\r\n [LexerState.CASE_FLOW_CONTROL_CONDITION]: consumeCaseFlowControlCondition,\r\n [LexerState.FLOW_CONTROL_BLOCK]: consumeFlowControlBlock,\r\n [LexerState.EVENT]: consumeEvent,\r\n [LexerState.INTERPOLATION]: consumeInterpolation,\r\n [LexerState.INTERPOLATION_EXPRESSION]: consumeInterpolationExpression,\r\n [LexerState.INTERPOLATION_LITERAL]: consumeInterpolationliteral,\r\n [LexerState.CONST_DECLARATION]: consumeConstDeclaration\r\n }\r\n\r\n /**\r\n * Creates a new Cursor instance for the given template content.\r\n *\r\n * @param input The full template text that the cursor will navigate.\r\n */\r\n constructor(public input: string) {\r\n this._cursor = new LexerCursor(this.input);\r\n }\r\n\r\n /**\r\n * Runs the lexer over the input string and returns the full token array.\r\n * Drives the state machine until EOF is reached.\r\n *\r\n * @returns Array of all tokens produced from the input.\r\n */\r\n public tokenize(): Token[] {\r\n let eof = false;\r\n\r\n while (!eof) {\r\n try {\r\n const transitionFunction = this._states[this._state];\r\n const { state, tokens, popState, pushState } = transitionFunction!(this._cursor, { \r\n history: this._stack.values,\r\n tokens: [...this._tokens] \r\n });\r\n \r\n if (tokens?.length) {\r\n this._tokens.push(...tokens);\r\n }\r\n \r\n if (pushState) {\r\n this._stack.push(this._state);\r\n }\r\n \r\n if (popState) {\r\n this._stack.pop();\r\n } \r\n \r\n this._state = state;\r\n } catch (err) {\r\n const error = err as Error;\r\n if (error.cause === EOF) {\r\n eof = true;\r\n } else {\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n return this._tokens;\r\n }\r\n}","import { PositiveInteger, TupleOfLength } from '@xaendar/types';\r\nimport { EOF } from '../../costants/chars.constants.js';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { Token } from '../../lexer/types/token.type.js';\r\nimport { CurrentToken } from '../types/current-token.type.js';\r\n\r\n/**\r\n * Cursor abstraction used by the Parser to navigate\r\n * through a sequence of tokens produced by the Lexer.\r\n *\r\n * Responsibilities:\r\n * - Sequential token consumption\r\n * - Lookahead (peek) operations without mutating state\r\n * - Handling end-of-file conditions\r\n *\r\n * This class does not perform parsing itself: it only\r\n * manages position and access to the token stream.\r\n */\r\nexport class ParserCursor {\r\n\r\n /**\r\n * Representation of the current token.\r\n *\r\n * - `index`: absolute index within the token array\r\n * - `value`: current token object (or EOF token)\r\n *\r\n * An index of `-1` indicates that the cursor has not\r\n * yet consumed any token or has reached EOF.\r\n */\r\n private readonly _currentToken: CurrentToken = {\r\n value: { type: TokenType.EOF },\r\n index: -1\r\n };\r\n\r\n /**\r\n * Returns a read-only snapshot of the current token.\r\n */\r\n public get currentToken(): Readonly<CurrentToken> {\r\n return this._currentToken;\r\n }\r\n\r\n /**\r\n * Creates a new ParserCursor for the given token array.\r\n *\r\n * @param _tokens Array of tokens to navigate.\r\n */\r\n constructor(private readonly _tokens: Token[]) { }\r\n\r\n /**\r\n * Advances the cursor by the specified number of tokens.\r\n *\r\n * Updates the current token and index.\r\n *\r\n * @param chars Number of tokens to advance (must be >= 1)\r\n *\r\n * @throws Error with cause `EOF` when advancing past the end\r\n */\r\n public advance(chars = 1): void {\r\n if (chars < 1) {\r\n throw new Error(`${chars} is not a valid value. Please enter a number equal or greater than 1`);\r\n }\r\n\r\n const newIndex = this._currentToken.index + chars;\r\n\r\n if (newIndex >= this._tokens.length) {\r\n this._currentToken.value = { type: TokenType.EOF };\r\n this._currentToken.index = -1;\r\n } else {\r\n this._currentToken.index = newIndex;\r\n this._currentToken.value = this._tokens[newIndex]!;\r\n }\r\n }\r\n\r\n /**\r\n * Peeks ahead in the token stream without advancing the cursor.\r\n *\r\n * Supports:\r\n * - Single-token lookahead\r\n * - Multi-token lookahead\r\n * - Optional offset from the current token\r\n *\r\n * @returns\r\n * - A single Token when peeking one token\r\n * - An array of Tokens when peeking multiple tokens\r\n *\r\n * @throws Error with cause `EOF` if the peek exceeds the token array\r\n */\r\n public peek<T extends Token = Token>(): T;\r\n public peek<OffSet extends number, T extends Token = Token>(options?: { offset?: PositiveInteger<OffSet> }): T;\r\n public peek<T extends Token = Token>(chars: 1): T;\r\n public peek<OffSet extends number, T extends Token = Token>(chars: 1, options?: { offset?: PositiveInteger<OffSet> }): T; \r\n public peek<ReadChars extends number, T extends Token = Token>(chars: PositiveInteger<ReadChars>): TupleOfLength<ReadChars, T>; \r\n public peek<ReadChars extends number, OffSet extends number, T extends Token = Token>(chars: PositiveInteger<ReadChars>, options?: { offset?: PositiveInteger<OffSet> }): TupleOfLength<ReadChars, T>;\r\n public peek(charsOrOptions?: number | { offset?: number }, options?: { offset?: number }): Token | Token[] {\r\n const tokens = typeof charsOrOptions === 'number' ? charsOrOptions : 1;\r\n const offset = (typeof charsOrOptions === 'object' ? charsOrOptions : options)?.offset ?? 0;\r\n return tokens === 1 ? this.peekOneToken(this._currentToken.index + offset + 1) : this.peekMany(tokens + offset);\r\n }\r\n\r\n /**\r\n * Peeks multiple tokens ahead.\r\n */\r\n private peekMany(chars: number): Token[] {\r\n const peekedTokens = new Array<Token>;\r\n const nextTokenIndex = this._currentToken.index + 1;\r\n\r\n for (let i = nextTokenIndex; i < nextTokenIndex + chars; i++) {\r\n peekedTokens.push(this.peekOneToken(i));\r\n }\r\n\r\n return peekedTokens;\r\n }\r\n\r\n /**\r\n * Peeks a single token at the given absolute index.\r\n */\r\n private peekOneToken(index: number): Token {\r\n return index < this._tokens.length ? this._tokens[index]! : { type: TokenType.EOF };\r\n }\r\n}\r\n","/**\r\n * Discriminant values that identify the type of each AST node produced by the parser.\r\n */\r\nexport enum ASTNodeType {\r\n /**\r\n * An HTML element node with a tag name, attributes, events, and children.\r\n */\r\n Element,\r\n /**\r\n * A plain text node.\r\n */\r\n Text,\r\n /**\r\n * An inline interpolation expression or literal.\r\n */\r\n Interpolation,\r\n /**\r\n * An `@if` conditional node.\r\n */\r\n If,\r\n /**\r\n * An `@else` branch node attached to an `@if`.\r\n */\r\n Else,\r\n /**\r\n * An `@else if` branch node attached to an `@if`.\r\n */\r\n ElseIf,\r\n /**\r\n * An `@for` iteration node.\r\n */\r\n For,\r\n /**\r\n * An `@switch` node containing one or more case nodes.\r\n */\r\n Switch,\r\n /**\r\n * A `@case` or `@default` branch inside a `@switch`.\r\n */\r\n Case,\r\n /**\r\n * A `@const` declaration node.\r\n */\r\n ConstDeclaration\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { ConstDeclarationToken } from '../../lexer/types/tokens/const-declaration-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ConstDeclarationNode } from '../types/nodes/const-declaration-node.type.js';\r\n\r\n/**\r\n * Parses a CONST_DECLARATION token into a `ConstDeclarationNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the CONST_DECLARATION token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The CONST_DECLARATION token containing variable name and expression.\r\n * @returns The parsed `ConstDeclarationNode`.\r\n */\r\nexport function parseConstDeclaration(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: ConstDeclarationToken): ConstDeclarationNode {\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.ConstDeclaration,\r\n varName: token.parts[0],\r\n expression: token.parts[1]\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { InterpolationExpressionToken } from '../../lexer/types/tokens/interpolation-expression-token.type.js';\r\nimport { InterpolationLiteralToken } from '../../lexer/types/tokens/interpolation-literal-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { InterpolationNode } from '../types/nodes/interpolation-node.type.js';\r\n\r\n/**\r\n * Parses an interpolation expression or literal token into an `InterpolationNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the interpolation token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The INTERPOLATION_EXPRESSION or INTERPOLATION_LITERAL token.\r\n * @returns The parsed `InterpolationNode`.\r\n */\r\nexport function parseInterpolation(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: InterpolationExpressionToken | InterpolationLiteralToken): InterpolationNode {\r\n cursor.advance();\r\n \r\n return {\r\n type: ASTNodeType.Interpolation,\r\n expression: token.parts[0]\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { AttributeToken } from '../../lexer/types/tokens/attribute-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { AttributeNode } from '../types/nodes/attribute-node.type.js';\r\nimport { parseInterpolation } from './parse-interpolation.state.js';\r\n\r\n/**\r\n * Parses an ATTRIBUTE token into an `AttributeNode`.\r\n * Handles boolean attributes (no `=`), string values, and interpolation values.\r\n *\r\n * @param cursor Parser cursor; advanced past the ATTRIBUTE token.\r\n * @param parseNode Parser node function for recursive parsing.\r\n * @param token The ATTRIBUTE token to parse.\r\n * @returns The parsed `AttributeNode`.\r\n */\r\nexport function parseAttribute(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: AttributeToken): AttributeNode {\r\n // consume ATTRIBUTE token\r\n cursor.advance();\r\n const raw = token.parts[0];\r\n\r\n if (!raw.includes('=')) {\r\n return { name: raw, value: 'true' };\r\n }\r\n\r\n const [name, value] = raw.split('=');\r\n if (!name) {\r\n throw new Error(`[Parser] Attribute name missing in: ${raw}`);\r\n }\r\n\r\n const nextToken = cursor.peek();\r\n if (nextToken.type === TokenType.INTERPOLATION_EXPRESSION || nextToken.type === TokenType.INTERPOLATION_LITERAL) {\r\n return {\r\n name,\r\n value: parseInterpolation(cursor, parseNode, nextToken)\r\n };\r\n }\r\n\r\n if (!value) {\r\n throw new Error(`[Parser] Attribute value missing for ${name} in: ${raw}`);\r\n }\r\n\r\n return {\r\n name,\r\n value: value.replace(/^['']|['']$/g, '')\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { EventToken } from '../../lexer/types/tokens/event-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { EventNode } from '../types/nodes/event-node.type.js';\r\n\r\n/**\r\n * Parses an EVENT token into an `EventNode` by splitting the raw\r\n * `eventName=handler` string.\r\n *\r\n * @param cursor Parser cursor; advanced past the EVENT token.\r\n * @param _parseNode Unused parser function.\r\n * @param token The EVENT token to parse.\r\n * @returns The parsed `EventNode`.\r\n */\r\nexport function parseEvent(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: EventToken): EventNode {\r\n cursor.advance();\r\n const raw = token.parts[0];\r\n const [name, value] = raw.split('=');\r\n\r\n if (!name || !value) {\r\n throw new Error(`[Parser] Invalid event format: ${raw}`);\r\n }\r\n\r\n return {\r\n name,\r\n handler: value.replace(/^[\"\"]|[\"\"]$/g, '')\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { TagOpenNameToken } from '../../lexer/types/tokens/tag-open-name-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { AttributeNode } from '../types/nodes/attribute-node.type.js';\r\nimport { ElementNode } from '../types/nodes/element-node.type.js';\r\nimport { EventNode } from '../types/nodes/event-node.type.js';\r\nimport { parseAttribute } from './parse-attribute.state.js';\r\nimport { parseEvent } from './parse-event.state.js';\r\n\r\n/**\r\n * Parses a TAG_OPEN_NAME token and the subsequent attributes, events, and children\r\n * into an `ElementNode`. Handles both regular and self-closing tags.\r\n *\r\n * @param cursor Parser cursor positioned at the TAG_OPEN_NAME token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param token The TAG_OPEN_NAME token containing the tag name.\r\n * @returns The parsed `ElementNode`.\r\n */\r\nexport function parseElement(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: TagOpenNameToken): ElementNode {\r\n cursor.advance();\r\n const tagName = token.parts[0];\r\n\r\n const attributes = new Array<AttributeNode>();\r\n const events = new Array<EventNode>();\r\n\r\n let read = true;\r\n while (read) {\r\n const token = cursor.peek();\r\n switch (token.type) {\r\n case TokenType.ATTRIBUTE:\r\n attributes.push(parseAttribute(cursor, parseNode, token));\r\n break;\r\n\r\n case TokenType.EVENT:\r\n events.push(parseEvent(cursor, parseNode, token));\r\n break;\r\n\r\n default:\r\n read = false;\r\n }\r\n }\r\n\r\n // Consume TAG_OPEN_END if present: <div>\r\n if (cursor.peek().type === TokenType.TAG_OPEN_END) {\r\n cursor.advance();\r\n }\r\n\r\n // Handle self-closing tags: <div />\r\n if (cursor.peek().type === TokenType.TAG_SELF_CLOSE) {\r\n cursor.advance();\r\n return {\r\n type: ASTNodeType.Element,\r\n tagName,\r\n attributes,\r\n events,\r\n children: []\r\n };\r\n }\r\n\r\n // Parse children recursively until closing tag\r\n const children = new Array<ASTNode>;\r\n while (!isTagClose(cursor, tagName)) {\r\n const child = parseNode();\r\n if (child) {\r\n children.push(child);\r\n }\r\n }\r\n\r\n // Consume closing tag </div>\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Element,\r\n tagName,\r\n attributes,\r\n events,\r\n children\r\n };\r\n}\r\n\r\n/**\r\n * Returns `true` if the next token in the stream is a closing tag for the given tag name.\r\n *\r\n * @param cursor Parser cursor to peek from.\r\n * @param tagName The expected tag name to match.\r\n * @returns `true` if the next token is TAG_CLOSE_NAME matching `tagName`.\r\n */\r\nfunction isTagClose(cursor: ParserCursor, tagName: string): boolean {\r\n const nextToken = cursor.peek();\r\n return nextToken.type === TokenType.TAG_CLOSE_NAME && nextToken.parts[0] === tagName;\r\n}\r\n","import ts, { Diagnostic } from 'typescript';\r\nimport { ExpressionValidationResult } from '../types/expression-validation-result.type';\r\nimport { ExpressionDiagnostic } from '../types/nodes/expression-diangnostic.type';\r\n\r\n/**\r\n * Validates that a string contains a single expression belonging to the\r\n * permitted subset of JavaScript supported inside Xaendar template expressions.\r\n *\r\n * ## Permitted constructs\r\n *\r\n * - **Literals** — strings, numbers, bigints, booleans, `null`, `undefined`\r\n * - **Identifiers** — resolved at runtime against the active scope chain\r\n * - **Member access** — `user.name`, `user.address.city`, `items[0]`\r\n * - **Call expressions** — `user.getFullName()`, `user.hasRole('admin')`\r\n * - **Binary expressions** — arithmetic (`+`, `-`, `*`, `/`, `%`, `**`),\r\n * comparison (`===`, `!==`, `<`, `>`, `<=`, `>=`),\r\n * logical (`&&`, `||`, `??`),\r\n * bitwise (`&`, `|`, `^`, `<<`, `>>`, `>>>`)\r\n * - **Unary expressions** — `!`, `~`, `+`, `-`, `typeof`, `void`\r\n * - **Conditional (ternary)** — `isAdmin ? 'yes' : 'no'`\r\n * - **Parenthesised expressions** — `(user.age > 18)`\r\n * - **Template literals** — `` `Hello ${user.name}` ``\r\n * - **Array literals** — `[1, 2, 3]`, `[...items]`\r\n * - **Object literals** — `{ key: value }`, `{ ...defaults, name }`\r\n * - **Spread** — `foo(...args)`, `[...items]`, `{ ...obj }`\r\n * - **`typeof` / `instanceof`** — `typeof user.role`, `user instanceof AdminUser`\r\n *\r\n * ## Prohibited constructs\r\n *\r\n * - Assignments (`=`, `+=`, `&&=`, etc.) — use `@const` for local bindings\r\n * - `await` and `yield`\r\n * - `new` expressions\r\n * - Function and arrow function expressions\r\n * - Tagged template expressions\r\n *\r\n * ## Scope resolution\r\n *\r\n * This function performs **syntactic** validation only. Identifier resolution\r\n * (scope chain walk → `ctx.` prefix injection) is the responsibility of the\r\n * caller and must be performed on the returned `node` after this function\r\n * reports no diagnostics.\r\n *\r\n * @param source - The raw expression string extracted from the template.\r\n * @returns A {@link ExpressionValidationResult} containing the parsed AST node\r\n * (when valid) and any diagnostics produced during validation.\r\n *\r\n * @example\r\n * const result = validateExpression('user.hasRole(\"admin\") && isVerified');\r\n * if (result.diagnostics.length === 0) {\r\n * // result.node is safe to use\r\n * }\r\n *\r\n * @example\r\n * const result = validateExpression('await user.load()');\r\n * // result.diagnostics[0].message →\r\n * // \"'await' is not allowed inside template expressions.\"\r\n */\r\nexport function validateExpression(source: string): ExpressionValidationResult {\r\n const prefix = 'const x = ';\r\n const sourceFile = ts.createSourceFile('expression.ts', `${prefix}${source}`, ts.ScriptTarget.ESNext, true);\r\n\r\n const statement = sourceFile.statements[0] as ts.VariableStatement;\r\n const expression = statement.declarationList.declarations[0]!.initializer!;\r\n\r\n const diagnostics = new Array<ExpressionDiagnostic>;\r\n visitNode(expression, prefix.length, diagnostics);\r\n\r\n if (diagnostics.length) {\r\n throw new Error(diagnostics.reduce((acc, d) => `${acc}${d.message}\\n`, ''));\r\n }\r\n\r\n return {\r\n node: expression,\r\n };\r\n}\r\n\r\n/**\r\n * Recursively visits an AST node and appends a diagnostic for every node\r\n * kind that is not part of the permitted expression subset.\r\n *\r\n * Recursion stops at the first disallowed node to avoid producing a cascade\r\n * of redundant diagnostics for its children.\r\n *\r\n * @param node - The AST node to inspect.\r\n * @param offset - Number of characters to subtract from raw node positions\r\n * to obtain offsets relative to the original expression string.\r\n * @param diagnostics - Accumulator for diagnostics found during the walk.\r\n */\r\nfunction visitNode(node: ts.Node, offset: number, diagnostics: ExpressionDiagnostic[]): void {\r\n if (!isAllowedNode(node)) {\r\n throw new Error(buildDisallowedMessage(node));\r\n }\r\n\r\n ts.forEachChild(node, child => visitNode(child, offset, diagnostics));\r\n\r\n if (diagnostics.length) {\r\n throw new Error(diagnostics[0]!.message);\r\n }\r\n}\r\n\r\n/**\r\n * Returns `true` if the given AST node kind is permitted inside a\r\n * Xaendar template expression.\r\n *\r\n * Assignment operators nested inside a `BinaryExpression` are handled\r\n * separately in {@link buildDisallowedMessage} since TypeScript does not\r\n * distinguish them at the node-kind level.\r\n */\r\nfunction isAllowedNode(node: ts.Node): boolean {\r\n switch (node.kind) {\r\n // ---- Literals ----\r\n case ts.SyntaxKind.StringLiteral:\r\n case ts.SyntaxKind.NumericLiteral:\r\n case ts.SyntaxKind.BigIntLiteral:\r\n case ts.SyntaxKind.TrueKeyword:\r\n case ts.SyntaxKind.FalseKeyword:\r\n case ts.SyntaxKind.NullKeyword:\r\n case ts.SyntaxKind.UndefinedKeyword:\r\n\r\n // ---- Identifiers ----\r\n case ts.SyntaxKind.Identifier:\r\n\r\n // ---- Member access ----\r\n // user.name\r\n case ts.SyntaxKind.PropertyAccessExpression:\r\n // user['name'], items[0]\r\n case ts.SyntaxKind.ElementAccessExpression:\r\n\r\n // ---- Call expressions ----\r\n // user.getFullName(), user.hasRole('admin')\r\n case ts.SyntaxKind.CallExpression:\r\n\r\n // ---- Binary expressions ----\r\n // Covers arithmetic, comparison, logical, bitwise, nullish coalescing,\r\n // and instanceof. Assignment operators are rejected in visitNode via\r\n // buildDisallowedMessage before recursing into children.\r\n case ts.SyntaxKind.BinaryExpression:\r\n\r\n // ---- Operator tokens — visited as children of BinaryExpression ----\r\n // Comparison\r\n case ts.SyntaxKind.EqualsEqualsToken: // ==\r\n case ts.SyntaxKind.EqualsEqualsEqualsToken: // ===\r\n case ts.SyntaxKind.ExclamationEqualsToken: // !=\r\n case ts.SyntaxKind.ExclamationEqualsEqualsToken: // !==\r\n case ts.SyntaxKind.LessThanToken: // \r\n case ts.SyntaxKind.LessThanEqualsToken: // <=\r\n case ts.SyntaxKind.GreaterThanToken: // >\r\n case ts.SyntaxKind.GreaterThanEqualsToken: // >=\r\n\r\n // Arithmetic\r\n case ts.SyntaxKind.PlusToken: // +\r\n case ts.SyntaxKind.MinusToken: // -\r\n case ts.SyntaxKind.AsteriskToken: // *\r\n case ts.SyntaxKind.SlashToken: // /\r\n case ts.SyntaxKind.PercentToken: // %\r\n case ts.SyntaxKind.AsteriskAsteriskToken: // **\r\n\r\n // Logical\r\n case ts.SyntaxKind.AmpersandAmpersandToken: // &&\r\n case ts.SyntaxKind.BarBarToken: // ||\r\n case ts.SyntaxKind.QuestionQuestionToken: // ??\r\n\r\n // Bitwise\r\n case ts.SyntaxKind.AmpersandToken: // &\r\n case ts.SyntaxKind.BarToken: // |\r\n case ts.SyntaxKind.CaretToken: // ^\r\n case ts.SyntaxKind.LessThanLessThanToken: // \r\n case ts.SyntaxKind.GreaterThanGreaterThanToken: // >>\r\n case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: // >>>\r\n \r\n // instanceof / in\r\n case ts.SyntaxKind.InstanceOfKeyword: // instanceof\r\n case ts.SyntaxKind.InKeyword: // in\r\n\r\n // ---- Unary expressions ----\r\n // !isAdmin, ~flags, +n, -n, typeof x, void 0\r\n case ts.SyntaxKind.PrefixUnaryExpression:\r\n case ts.SyntaxKind.PostfixUnaryExpression:\r\n // typeof is represented as a dedicated node kind in some TS versions\r\n case ts.SyntaxKind.TypeOfExpression:\r\n case ts.SyntaxKind.VoidExpression:\r\n\r\n // ---- Conditional (ternary) ----\r\n // isAdmin ? 'yes' : 'no'\r\n case ts.SyntaxKind.ConditionalExpression:\r\n\r\n // ---- Parenthesised expressions ----\r\n case ts.SyntaxKind.ParenthesizedExpression:\r\n\r\n // ---- Template literals ----\r\n // `Hello ${user.name}`\r\n case ts.SyntaxKind.TemplateExpression:\r\n case ts.SyntaxKind.NoSubstitutionTemplateLiteral:\r\n case ts.SyntaxKind.TemplateHead:\r\n case ts.SyntaxKind.TemplateMiddle:\r\n case ts.SyntaxKind.TemplateTail:\r\n case ts.SyntaxKind.TemplateSpan:\r\n\r\n // ---- Arrays ----\r\n // [1, 2, 3], [...items]\r\n case ts.SyntaxKind.ArrayLiteralExpression:\r\n\r\n // ---- Objects ----\r\n // { key: value }, { ...defaults, name }\r\n case ts.SyntaxKind.ObjectLiteralExpression:\r\n case ts.SyntaxKind.PropertyAssignment:\r\n case ts.SyntaxKind.ShorthandPropertyAssignment:\r\n // { ...obj } inside an object literal\r\n case ts.SyntaxKind.SpreadAssignment:\r\n\r\n // ---- Spread ----\r\n // foo(...args), [...items]\r\n case ts.SyntaxKind.SpreadElement:\r\n\r\n // ---- Internal structural nodes ----\r\n // Visited during recursion but carry no semantic meaning of their own.\r\n case ts.SyntaxKind.SyntaxList:\r\n return true;\r\n\r\n // ---- Disallowed by default ----\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Builds a human-readable diagnostic message for a node that is not permitted\r\n * inside a Xaendar template expression.\r\n *\r\n * Provides specific messages for the most common mistakes (assignments, `await`,\r\n * `new`, functions) and falls back to a generic message for anything else.\r\n */\r\nfunction buildDisallowedMessage(node: ts.Node): string {\r\n switch (node.kind) {\r\n case ts.SyntaxKind.AwaitExpression:\r\n return \"'await' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.YieldExpression:\r\n return \"'yield' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.NewExpression:\r\n return \"'new' is not allowed inside template expressions.\";\r\n\r\n case ts.SyntaxKind.ArrowFunction:\r\n case ts.SyntaxKind.FunctionExpression:\r\n return 'Function expressions are not allowed inside template expressions.';\r\n\r\n case ts.SyntaxKind.TaggedTemplateExpression:\r\n return 'Tagged template expressions are not allowed inside template expressions.';\r\n\r\n case ts.SyntaxKind.BinaryExpression: {\r\n const bin = node as ts.BinaryExpression;\r\n return isAssignmentOperator(bin.operatorToken.kind)\r\n ? 'Assignments are not allowed inside template expressions. Use @const to declare local template variables instead.'\r\n : `'${ts.SyntaxKind[node.kind]}' is not allowed inside template expressions.`;\r\n }\r\n\r\n default:\r\n return `'${ts.SyntaxKind[node.kind]}' is not allowed inside template expressions.`;\r\n }\r\n}\r\n\r\n/**\r\n * Returns `true` if the given {@link ts.SyntaxKind} is an assignment operator.\r\n *\r\n * Covers simple assignment (`=`) as well as all compound assignment operators\r\n * (`+=`, `-=`, `&&=`, `||=`, `??=`, etc.) as defined by the TypeScript\r\n * `FirstAssignment`–`LastAssignment` range.\r\n */\r\nfunction isAssignmentOperator(kind: ts.SyntaxKind): boolean {\r\n return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment;\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { parse } from 'node:path';\r\n\r\n/**\r\n * Parses child AST nodes inside a flow-control block until a BLOCK_CLOSE token is reached.\r\n * Consumes the BLOCK_CLOSE token before returning.\r\n *\r\n * @param cursor Parser cursor positioned at the first token inside the block.\r\n * @param parseNode Parser function for recursive child parsing.\r\n * @returns Array of parsed child `ASTNode`s.\r\n */\r\nexport function parseBlockChildren(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>): ASTNode[] {\r\n const children = new Array<ASTNode>;\r\n\r\n while (cursor.peek().type !== TokenType.BLOCK_CLOSE) {\r\n const child = parseNode();\r\n if (child) {\r\n children.push(child);\r\n }\r\n }\r\n\r\n // consume BLOCK_CLOSE\r\n cursor.advance();\r\n return children;\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport ts from 'typescript';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { ForToken } from '../../lexer/types/tokens/for-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ForExpression } from '../types/for-expression.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ForImplicitVariables } from '../types/nodes/for-implicit-variables.js';\r\nimport { ForNode } from '../types/nodes/for-node.type.js';\r\nimport { validateExpression } from '../utils/expression-validator.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\n\r\n/**\r\n * Parses a `@for` directive, consuming the FOR token, the CONDITION token,\r\n * the BLOCK_OPEN token, and all child nodes until BLOCK_CLOSE.\r\n *\r\n * @param cursor Parser cursor positioned at the FOR token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param _token The FOR token (unused; consumed for position advancement).\r\n * @returns The parsed `ForNode`.\r\n */\r\nexport function parseForControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, _token: ForToken): ForNode {\r\n // consume FOR\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after FOR, got ${TokenType[conditionToken.type]}`);\r\n }\r\n const expression = parseForExpression(conditionToken.parts[0], 0);\r\n\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const children = parseBlockChildren(cursor, parseNode);\r\n\r\n return { type: ASTNodeType.For, ...expression, children };\r\n}\r\n\r\n/**\r\n * Parses the body of an `@for` block into a structured {@link ForExpression}.\r\n *\r\n * The expected format is:\r\n * ```\r\n * item of iterable; track expr[; $implicit = alias, ...]\r\n * ```\r\n *\r\n * @param source - The raw string content of the `@for(...)` expression.\r\n * @param baseOffset - Character offset of `source` within the original template,\r\n * used to produce accurate diagnostic positions.\r\n * @returns A {@link ForExpression} object. When unrecoverable syntax errors are\r\n * found the returned object contains only `diagnostics`.\r\n */\r\nexport function parseForExpression(source: string, baseOffset: number): ForExpression {\r\n const sections = splitForSections(source);\r\n\r\n if (sections.length < 2) {\r\n throw new Error(`[Parser] @for requires at least \"item of iterable; track expr\".`);\r\n }\r\n\r\n // ---- Section 1: \"item of items\" ----\r\n const iterSection = sections[0]!.trim();\r\n const ofIndex = iterSection.indexOf(' of ');\r\n\r\n if (ofIndex === -1) {\r\n throw new Error(`[Parser] @for expression must be in the form \"item of iterable\".`);\r\n }\r\n\r\n const itemAlias = iterSection.slice(0, ofIndex).trim();\r\n const iterableSource = iterSection.slice(ofIndex + 4).trim();\r\n\r\n if (!isValidIdentifier(itemAlias)) {\r\n throw new Error(`[Parser] '${itemAlias}' is not a valid item alias.`);\r\n }\r\n\r\n // Validate the iterable as a JS expression.\r\n const iterValidation = validateExpression(iterableSource);\r\n\r\n // ---- Section 2: \"track item.id\" ----\r\n const trackSection = sections[1]!.trim();\r\n\r\n if (!trackSection.startsWith('track ')) {\r\n throw new Error(`[Parser] Second section of @for must start with \"track\".`);\r\n }\r\n\r\n const trackSource = trackSection.slice(6).trim();\r\n const trackValidation = validateExpression(trackSource);\r\n\r\n // ---- Section 3 (optional): \"$index = i, $last = l\" ----\r\n const implicitAliases = new Map<ForImplicitVariables, string>;\r\n\r\n if (sections.length >= 3 && sections[2] !== undefined) {\r\n const aliasSection = sections[2].trim();\r\n const aliasOffset = baseOffset + source.indexOf(sections[2]);\r\n parseImplicitAliases(aliasSection, aliasOffset, implicitAliases);\r\n }\r\n\r\n return {\r\n itemAlias,\r\n iterableExpression: iterValidation.node,\r\n iterableSource,\r\n trackExpression: trackValidation.node,\r\n trackSource,\r\n implicitAliases\r\n };\r\n}\r\n\r\n/**\r\n * Parses the optional third section of an `@for` expression, which declares\r\n * aliases for implicit loop variables (e.g. `$index = i, $last = l, $even = isEven`).\r\n *\r\n * Valid entries are comma-separated pairs in the form `$implicit = alias`.\r\n * Diagnostics are pushed to `diagnostics` for any malformed or duplicate entry.\r\n *\r\n * @param source - The raw alias-declarations string (everything after the second `;`).\r\n * @param baseOffset - Character offset of `source` within the original template.\r\n * @param out - Map to populate with `alias → implicit-variable` entries.\r\n * @param diagnostics - Array to collect any parse errors.\r\n */\r\nfunction parseImplicitAliases(source: string, baseOffset: number, out: Map<ForImplicitVariables, string>): void {\r\n const entries = source.split(',');\r\n let cursor = 0;\r\n \r\n const IMPLICIT_VARIABLES = new Set(['$index', '$last', '$first', '$even', '$odd']);\r\n\r\n for (const entry of entries) {\r\n const trimmed = entry.trim();\r\n const eqIndex = trimmed.indexOf('=');\r\n\r\n if (eqIndex === -1) {\r\n throw new Error(`[Parser] Invalid alias declaration '${trimmed}'. Expected '$implicit = alias'.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n const implicit = trimmed.slice(0, eqIndex).trim();\r\n const alias = trimmed.slice(eqIndex + 1).trim();\r\n\r\n const isImplicitVariable = (value: string): value is ForImplicitVariables => IMPLICIT_VARIABLES.has(value as ForImplicitVariables);\r\n \r\n if (!isImplicitVariable(implicit)) {\r\n throw new Error(`[Parser] '${implicit}' is not a known implicit variable. Known variables: ${[...IMPLICIT_VARIABLES].join(', ')}.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n if (!isValidIdentifier(alias)) {\r\n throw new Error(`[Parser] '${alias}' is not a valid alias identifier.`);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n if (out.has(implicit)) {\r\n throw new Error(`[Parser] '${implicit}' is already aliased in this @for expression.`);\r\n } else {\r\n out.set(implicit, alias);\r\n }\r\n\r\n cursor += entry.length + 1;\r\n }\r\n}\r\n\r\n/**\r\n * Splits the raw `@for(...)` body into its semicolon-delimited sections,\r\n * respecting nested brackets and string literals so that semicolons inside\r\n * them are never treated as section separators.\r\n *\r\n * Example input: `\"item of items; track item.id; $index = i\"`\r\n * Example output: `[\"item of items\", \" track item.id\", \" $index = i\"]`\r\n *\r\n * @param source - The raw content of the `@for(...)` expression.\r\n * @returns An array of section strings (without the `;` separators).\r\n */\r\nfunction splitForSections(source: string): string[] {\r\n const sections = new Array<string>;\r\n let current = '';\r\n let depth = 0;\r\n let inString: '\"' | \"'\" | '`' | null | undefined;\r\n\r\n for (let i = 0; i < source.length; i++) {\r\n const char = source[i]!;\r\n\r\n if (!current && char === ' ') {\r\n continue;\r\n }\r\n\r\n if (inString) {\r\n current += char;\r\n if (char === inString && source[i - 1] !== '\\\\') {\r\n inString = null;\r\n }\r\n continue;\r\n }\r\n\r\n if (char === '\"' || char === \"'\" || char === '`') {\r\n inString = char;\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Brackets — do not split inside nested bracket pairs.\r\n if (char === '(' || char === '[' || char === '{') {\r\n depth++;\r\n current += char;\r\n continue;\r\n }\r\n\r\n if (char === ')' || char === ']' || char === '}') {\r\n depth--;\r\n current += char;\r\n continue;\r\n }\r\n\r\n // Section separator — only split when not inside brackets or strings.\r\n if (char === ';' && depth === 0) {\r\n sections.push(current);\r\n current = '';\r\n continue;\r\n }\r\n\r\n current += char;\r\n }\r\n\r\n // Push the last section even when it has no trailing `;`.\r\n if (current.trim().length > 0) {\r\n sections.push(current);\r\n }\r\n\r\n return sections;\r\n}\r\n\r\n/**\r\n * Checks whether `name` is a valid JavaScript identifier by delegating to\r\n * the TypeScript parser.\r\n *\r\n * A string is considered valid when the TS parser produces a single\r\n * `ExpressionStatement` whose expression is an `Identifier` with the\r\n * same text.\r\n *\r\n * @param name - The string to validate.\r\n * @returns `true` if `name` is a valid JS identifier, `false` otherwise.\r\n */\r\nfunction isValidIdentifier(name: string): boolean {\r\n if (!name.length) {\r\n return false;\r\n }\r\n\r\n const sourceFile = ts.createSourceFile('__id.ts', name, ts.ScriptTarget.ESNext, false);\r\n const statement = sourceFile.statements[0];\r\n return !!statement && ts.isExpressionStatement(statement) && ts.isIdentifier(statement.expression) && statement.expression.text === name;\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { IfToken } from '../../lexer/types/tokens/if-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { ElseNode } from '../types/nodes/else-node.type.js';\r\nimport { IfNode } from '../types/nodes/if-node.type.js';\r\nimport { validateExpression } from '../utils/expression-validator.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\nimport { ElseIfToken } from '../../lexer/types/tokens/else-if-token.type.js';\r\nimport { ElseIfNode } from '../types/nodes/else-if-node.type.js';\r\nimport { ElseToken } from '../../lexer/types/tokens/else-token.type.js';\r\n\r\n/**\r\n * Parses an `@if` directive, consuming the IF token, the CONDITION token,\r\n * the BLOCK_OPEN token, all consequent children, and an optional `@else` branch.\r\n *\r\n * @param cursor Parser cursor positioned at the IF token.\r\n * @param context Parser context for recursive child parsing.\r\n * @param token The IF token (unused; consumed for position advancement).\r\n * @returns The parsed `IfNode`.\r\n */\r\nexport function parseIfControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken): IfNode {\r\n return parseIfRecursively(cursor, parseNode, token);\r\n}\r\n\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken): IfNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: ElseIfToken | ElseToken): ElseIfNode | ElseNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: ElseToken): ElseNode;\r\nfunction parseIfRecursively(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, token: IfToken | ElseIfToken | ElseToken): IfNode | ElseIfNode | ElseNode {\r\n switch (token.type) {\r\n case TokenType.IF:\r\n case TokenType.ELSE_IF:\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after ${TokenType[token.type]}, got ${TokenType[conditionToken.type]}`);\r\n }\r\n\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const condition = conditionToken.parts[0];\r\n const validationResult = validateExpression(condition);\r\n\r\n const consequent = parseBlockChildren(cursor, parseNode);\r\n\r\n return {\r\n type: token.type === TokenType.IF ? ASTNodeType.If : ASTNodeType.ElseIf,\r\n condition,\r\n conditionNode: validationResult.node,\r\n consequent,\r\n alternate: parseIfRecursively(cursor, parseNode, cursor.peek<ElseIfToken | ElseToken>())\r\n };\r\n\r\n case TokenType.ELSE:\r\n // consume ELSE and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const elseChildren = parseBlockChildren(cursor, parseNode);\r\n \r\n return {\r\n type: ASTNodeType.Else,\r\n consequent: elseChildren\r\n };\r\n }\r\n}","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TokenType } from '../../lexer/types/token-type.enum.js';\r\nimport { SwitchToken } from '../../lexer/types/tokens/switch-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { CaseNode } from '../types/nodes/case-node.type.js';\r\nimport { SwitchNode } from '../types/nodes/switch-node.type.js';\r\nimport { parseBlockChildren } from './parse-block-children.state.js';\r\n\r\n/**\r\n * Parses a `@switch` directive, consuming the SWITCH token, the CONDITION token,\r\n * the outer BLOCK_OPEN, all `@case` and `@default` branches, and the outer BLOCK_CLOSE.\r\n *\r\n * @param cursor Parser cursor positioned at the SWITCH token.\r\n * @param parseNode Parser function for recursive child parsing.\r\n * @param _token The SWITCH token (unused; consumed for position advancement).\r\n * @returns The parsed `SwitchNode`.\r\n */\r\nexport function parseSwitchControlFlow(cursor: ParserCursor, parseNode: NoArgsFunction<ASTNode | undefined>, _token: SwitchToken): SwitchNode {\r\n // consume SWITCH\r\n cursor.advance();\r\n\r\n const conditionToken = cursor.peek();\r\n if (conditionToken.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after SWITCH, got ${TokenType[conditionToken.type]}`);\r\n }\r\n\r\n const expression = conditionToken.parts[0];\r\n // consume CONDITION and BLOCK_OPEN\r\n cursor.advance(2);\r\n\r\n const cases = new Array<CaseNode>;\r\n\r\n while (cursor.peek().type !== TokenType.BLOCK_CLOSE) {\r\n const token = cursor.peek();\r\n\r\n switch (token.type) {\r\n case TokenType.CASE:\r\n const condition = new Array<string>;\r\n \r\n /*\r\n We loop to support block case with multiple conditions, e.g.:\r\n @switch (x) {\r\n @case (1) \r\n @case (2) {\r\n // ...\r\n }\r\n }\r\n */\r\n do {\r\n // consume CASE\r\n cursor.advance();\r\n\r\n const caseCondition = cursor.peek();\r\n if (caseCondition.type !== TokenType.CONDITION) {\r\n throw new Error(`[Parser] Expected CONDITION after CASE`);\r\n }\r\n \r\n condition.push(caseCondition.parts[0]);\r\n // consume CONDITION\r\n cursor.advance();\r\n } while (cursor.peek().type !== TokenType.BLOCK_OPEN);\r\n\r\n // consume BLOCK_OPEN\r\n cursor.advance();\r\n \r\n cases.push({\r\n type: ASTNodeType.Case, \r\n condition, \r\n children: parseBlockChildren(cursor, parseNode) \r\n });\r\n break;\r\n\r\n case TokenType.DEFAULT:\r\n // consume DEFAULT and BLOCK_OPEN\r\n cursor.advance(2);\r\n cases.push({\r\n type: ASTNodeType.Case, \r\n condition: null, \r\n children: parseBlockChildren(cursor, parseNode) \r\n });\r\n break;\r\n\r\n }\r\n }\r\n\r\n // consume outer BLOCK_CLOSE\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Switch,\r\n expression,\r\n cases\r\n };\r\n}\r\n","import { NoArgsFunction } from '@xaendar/types';\r\nimport { TextToken } from '../../lexer/types/tokens/text-token.type.js';\r\nimport { ParserCursor } from '../models/parser-cursor.model.js';\r\nimport { ASTNode } from '../types/ast.type.js';\r\nimport { ASTNodeType } from '../types/node.enum.js';\r\nimport { TextNode } from '../types/nodes/text-node.type.js';\r\n\r\n/**\r\n * Parses a TEXT token into a `TextNode`.\r\n *\r\n * @param cursor Parser cursor; advanced past the TEXT token.\r\n * @param _parseNode Function to parse the next AST node.\r\n * @param token The TEXT token containing the raw text content.\r\n * @returns The parsed `TextNode`.\r\n */\r\nexport function parseText(cursor: ParserCursor, _parseNode: NoArgsFunction<ASTNode | undefined>, token: TextToken): TextNode {\r\n cursor.advance();\r\n\r\n return {\r\n type: ASTNodeType.Text,\r\n value: token.parts[0]\r\n };\r\n}\r\n","import { TokenType } from \"../lexer/types/token-type.enum.js\";\r\nimport { Token } from \"../lexer/types/token.type.js\";\r\nimport { ParserCursor } from \"./models/parser-cursor.model.js\";\r\nimport { parseConstDeclaration } from \"./states/parse-const-declaration.state.js\";\r\nimport { parseElement } from \"./states/parse-element.state.js\";\r\nimport { parseForControlFlow } from \"./states/parse-for.state.js\";\r\nimport { parseIfControlFlow } from \"./states/parse-if.state.js\";\r\nimport { parseInterpolation } from \"./states/parse-interpolation.state.js\";\r\nimport { parseSwitchControlFlow } from \"./states/parse-switch.state.js\";\r\nimport { parseText } from \"./states/parse-text.state.js\";\r\nimport { ASTNode } from \"./types/ast.type.js\";\r\nimport { ParserStates } from \"./types/parser-states.type.js\";\r\n\r\n/**\r\n * Parser class that transforms a stream of tokens (from the Lexer)\r\n * into an Abstract Syntax Tree (AST) representing the template structure.\r\n *\r\n * Responsibilities:\r\n * - Parse text nodes, elements, attributes, events, and interpolations\r\n * - Maintain cursor state for sequential token consumption\r\n * - Detect tag boundaries and nested structures\r\n *\r\n * The parser assumes that the token stream is syntactically valid according\r\n * to the Lexer rules. Parsing errors are thrown as exceptions.\r\n */\r\nexport class Parser {\r\n /**\r\n * Internal cursor for navigating tokens\r\n */\r\n private readonly _cursor: ParserCursor;\r\n /**\r\n * Mapping of token types to their corresponding parser transition functions, \r\n * which handle the logic for parsing each token type into AST nodes.\r\n */\r\n private readonly _states: ParserStates = {\r\n [TokenType.TEXT]: parseText,\r\n [TokenType.INTERPOLATION_EXPRESSION]: parseInterpolation,\r\n [TokenType.INTERPOLATION_LITERAL]: parseInterpolation,\r\n [TokenType.TAG_OPEN_NAME]: parseElement,\r\n [TokenType.IF]: parseIfControlFlow,\r\n [TokenType.FOR]: parseForControlFlow,\r\n [TokenType.SWITCH]: parseSwitchControlFlow,\r\n [TokenType.CONST_DECLARATION]: parseConstDeclaration\r\n }\r\n\r\n /**\r\n * Creates a new Parser instance.\r\n *\r\n * @param tokens Array of tokens produced by the Lexer\r\n */\r\n constructor(private readonly tokens: Token[]) {\r\n this._cursor = new ParserCursor(this.tokens);\r\n }\r\n\r\n /**\r\n * Entry point for parsing the token stream into AST nodes.\r\n *\r\n * @returns Array of top-level AST nodes\r\n */\r\n public parse(): ASTNode[] {\r\n const nodes = new Array<ASTNode>;\r\n \r\n while (this._cursor.peek().type !== TokenType.EOF) {\r\n const parseNode = this.parseNode();\r\n if (parseNode) {\r\n nodes.push(parseNode);\r\n }\r\n }\r\n\r\n return nodes;\r\n }\r\n\r\n /**\r\n * Parses the next AST node based on the current token.\r\n *\r\n * @returns Parsed AST node\r\n * @throws Error if an unexpected token is encountered\r\n */\r\n private parseNode(): ASTNode | undefined {\r\n const token = this._cursor.peek();\r\n if (token.type === TokenType.EOF) {\r\n return;\r\n }\r\n \r\n const state = this._states[token.type];\r\n\r\n if (!state) {\r\n throw new Error(`[Parser] No transition function for token type ${TokenType[token.type]}`);\r\n }\r\n\r\n return state(this._cursor, this.parseNode.bind(this), token as never);\r\n }\r\n}\r\n","/**\r\n * Tracks identifier scope during render code generation.\r\n * Each `Context` instance represents one lexical scope (e.g. a `@for` loop body)\r\n * and can be chained to a parent context for outer-scope resolution.\r\n */\r\nexport class Context {\r\n /**\r\n * Creates a new scope context.\r\n *\r\n * @param _identifiers List of loop variable names declared in this scope.\r\n * @param _parent Optional parent context representing the enclosing scope.\r\n */\r\n constructor(\r\n private _identifiers = new Array<string>,\r\n private _parent?: Context\r\n ) { }\r\n\r\n public addIdentifier(name: string): void {\r\n if (this.getIdentifier(name)) {\r\n throw new Error(`Identifier \"${name}\" is already declared in this scope.`);\r\n }\r\n \r\n this._identifiers.push(name);\r\n }\r\n\r\n /**\r\n * Returns the innermost identifier in the current scope chain, or\r\n * delegates to the parent context if none is found in this scope.\r\n *\r\n * @returns The most recently declared identifier name, or `undefined` if none exists.\r\n */\r\n public getIdentifier(name: string): string | undefined {\r\n return this._identifiers.includes(name) ? name : this._parent?.getIdentifier(name);\r\n }\r\n}\r\n","import ts, { Expression } from 'typescript';\r\nimport { Context } from '../models/render-context.model';\r\nimport { ElementNode } from '../../parser/types/nodes/element-node.type';\r\n\r\n/**\r\n * Complete set of JavaScript global identifiers up to ES2026.\r\n *\r\n * These are identifiers that TypeScript's parser classifies as\r\n * `SyntaxKind.Identifier` (unlike true keywords such as `typeof`,\r\n * `instanceof`, `true`, `false`, `null` which have their own SyntaxKind)\r\n * but that must never be prefixed with `this.` inside a template expression\r\n * because they refer to well-known globals, not to component properties.\r\n *\r\n * Organised by ECMAScript category, mirroring the MDN \"Standard built-in\r\n * objects\" reference, plus the ES2026 additions (Temporal, DisposableStack,\r\n * AsyncDisposableStack, SuppressedError, Math.sumPrecise surface).\r\n *\r\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects\r\n */\r\nexport const GLOBAL_IDENTIFIERS: ReadonlySet<string> = new Set([\r\n // ---- Value properties ------------------------------------------------\r\n // true, false, null are SyntaxKind keywords — not needed here.\r\n 'undefined',\r\n 'NaN',\r\n 'Infinity',\r\n 'globalThis',\r\n \r\n // ---- Global functions ------------------------------------------------\r\n 'eval',\r\n 'isFinite',\r\n 'isNaN',\r\n 'parseFloat',\r\n 'parseInt',\r\n 'decodeURI',\r\n 'decodeURIComponent',\r\n 'encodeURI',\r\n 'encodeURIComponent',\r\n // Deprecated but still Identifiers in TS\r\n 'escape',\r\n 'unescape',\r\n \r\n // ---- Fundamental objects ---------------------------------------------\r\n 'Object',\r\n 'Function',\r\n 'Boolean',\r\n 'Symbol',\r\n \r\n // ---- Error objects ---------------------------------------------------\r\n 'Error',\r\n 'AggregateError',\r\n 'EvalError',\r\n 'RangeError',\r\n 'ReferenceError',\r\n 'SyntaxError',\r\n 'TypeError',\r\n 'URIError',\r\n 'SuppressedError', // ES2026 — explicit resource management\r\n 'InternalError', // Non-standard (Firefox) but common\r\n \r\n // ---- Numbers and dates -----------------------------------------------\r\n 'Number',\r\n 'BigInt',\r\n 'Math',\r\n 'Date',\r\n 'Temporal', // ES2026 — replaces Date\r\n \r\n // ---- Text processing -------------------------------------------------\r\n 'String',\r\n 'RegExp',\r\n \r\n // ---- Indexed collections ---------------------------------------------\r\n 'Array',\r\n 'TypedArray',\r\n 'Int8Array',\r\n 'Uint8Array',\r\n 'Uint8ClampedArray',\r\n 'Int16Array',\r\n 'Uint16Array',\r\n 'Int32Array',\r\n 'Uint32Array',\r\n 'BigInt64Array',\r\n 'BigUint64Array',\r\n 'Float16Array', // ES2025\r\n 'Float32Array',\r\n 'Float64Array',\r\n \r\n // ---- Keyed collections -----------------------------------------------\r\n 'Map',\r\n 'Set',\r\n 'WeakMap',\r\n 'WeakSet',\r\n \r\n // ---- Structured data -------------------------------------------------\r\n 'ArrayBuffer',\r\n 'SharedArrayBuffer',\r\n 'DataView',\r\n 'Atomics',\r\n 'JSON',\r\n \r\n // ---- Memory management -----------------------------------------------\r\n 'WeakRef',\r\n 'FinalizationRegistry',\r\n \r\n // ---- Control abstractions --------------------------------------------\r\n 'Iterator', // ES2025\r\n 'AsyncIterator', // ES2025\r\n 'Promise',\r\n 'GeneratorFunction',\r\n 'AsyncGeneratorFunction',\r\n 'Generator',\r\n 'AsyncGenerator',\r\n 'AsyncFunction',\r\n 'DisposableStack', // ES2026 — explicit resource management\r\n 'AsyncDisposableStack', // ES2026 — explicit resource management\r\n \r\n // ---- Reflection ------------------------------------------------------\r\n 'Reflect',\r\n 'Proxy',\r\n \r\n // ---- Internationalization --------------------------------------------\r\n 'Intl',\r\n \r\n // ---- WebAssembly -----------------------------------------------------\r\n 'WebAssembly',\r\n \r\n // ---- Browser / DOM globals -------------------------------------------\r\n // These are not part of the ECMAScript spec but are universally available\r\n // in browser environments and must not be treated as component properties.\r\n 'window',\r\n 'document',\r\n 'navigator',\r\n 'location',\r\n 'history',\r\n 'screen',\r\n 'console',\r\n 'performance',\r\n 'crypto',\r\n 'fetch',\r\n 'alert',\r\n 'confirm',\r\n 'prompt',\r\n 'setTimeout',\r\n 'setInterval',\r\n 'clearTimeout',\r\n 'clearInterval',\r\n 'requestAnimationFrame',\r\n 'cancelAnimationFrame',\r\n 'queueMicrotask',\r\n 'structuredClone',\r\n 'URL',\r\n 'URLSearchParams',\r\n 'FormData',\r\n 'Headers',\r\n 'Request',\r\n 'Response',\r\n 'AbortController',\r\n 'AbortSignal',\r\n 'CustomEvent',\r\n 'Event',\r\n 'EventTarget',\r\n 'MutationObserver',\r\n 'IntersectionObserver',\r\n 'ResizeObserver',\r\n 'PerformanceObserver',\r\n 'Worker',\r\n 'SharedWorker',\r\n 'ServiceWorker',\r\n 'Blob',\r\n 'File',\r\n 'FileReader',\r\n 'ReadableStream',\r\n 'WritableStream',\r\n 'TransformStream',\r\n 'TextEncoder',\r\n 'TextDecoder',\r\n 'ImageData',\r\n 'Canvas',\r\n 'Storage',\r\n 'localStorage',\r\n 'sessionStorage',\r\n 'indexedDB',\r\n 'WebSocket',\r\n 'XMLHttpRequest',\r\n \r\n // ---- DOM element constructors ----------------------------------------\r\n // Commonly used with instanceof in template expressions.\r\n 'HTMLElement',\r\n 'HTMLInputElement',\r\n 'HTMLButtonElement',\r\n 'HTMLFormElement',\r\n 'HTMLAnchorElement',\r\n 'HTMLImageElement',\r\n 'HTMLVideoElement',\r\n 'HTMLAudioElement',\r\n 'HTMLCanvasElement',\r\n 'HTMLSelectElement',\r\n 'HTMLTextAreaElement',\r\n 'HTMLDivElement',\r\n 'HTMLSpanElement',\r\n 'HTMLParagraphElement',\r\n 'HTMLHeadingElement',\r\n 'HTMLTableElement',\r\n 'HTMLTableRowElement',\r\n 'HTMLTableCellElement',\r\n 'HTMLUListElement',\r\n 'HTMLOListElement',\r\n 'HTMLLIElement',\r\n 'HTMLLabelElement',\r\n 'HTMLDialogElement',\r\n 'HTMLDetailsElement',\r\n 'HTMLSlotElement',\r\n 'HTMLTemplateElement',\r\n 'SVGElement',\r\n 'SVGSVGElement',\r\n 'Element',\r\n 'Node',\r\n 'NodeList',\r\n 'DocumentFragment',\r\n 'ShadowRoot',\r\n 'Document',\r\n 'Window',\r\n]);\r\n\r\nexport const ROOT_NODE = 'this._root';\r\n\r\n/**\r\n * Resolves references to component properties inside a template expression.\r\n *\r\n * Identifiers that are not found in the active scope chain and are not\r\n * well-known globals are prefixed with `this.` so they resolve against\r\n * the component instance at runtime.\r\n *\r\n * The original formatting of the expression — parentheses, spacing,\r\n * operator tokens, member access dots — is preserved verbatim by delegating\r\n * to `node.getText()` for any subtree that contains no resolvable identifiers.\r\n *\r\n * @param expression - Either a raw identifier string or a validated\r\n * `ts.Expression` node produced by `validateExpression`.\r\n * @param context - The active template scope context.\r\n * @returns The resolved expression as a JavaScript string ready for codegen.\r\n *\r\n * @example\r\n * // Simple identifier\r\n * resolveExpression('items', context) // → 'this.items'\r\n *\r\n * @example\r\n * // Complex expression — formatting preserved\r\n * resolveExpression(node, context)\r\n * // typeof id !== 'boolean' || pippo instanceof HTMLElement\r\n * // → typeof this.id !== 'boolean' || this.pippo instanceof HTMLElement\r\n */\r\nexport function resolveExpression(expression: string | Expression, context: Context): string {\r\n return typeof expression === 'string'\r\n ? context.getIdentifier(expression) ?? `this.${expression}`\r\n : emitNode(expression, expression, context);\r\n}\r\n\r\n/**\r\n * Emits the resolved text for a node.\r\n *\r\n * - If the node has no resolvable identifiers in its subtree, emits\r\n * `node.getText()` verbatim — preserving all original spacing,\r\n * parentheses, dots, and punctuation.\r\n * - If the node is a resolvable Identifier, emits the resolved name.\r\n * - Otherwise recurses into children and concatenates their output.\r\n */\r\nfunction emitNode(node: ts.Node, parent: ts.Node, context: Context): string {\r\n // Leaf Identifier that needs resolution\r\n if (ts.isIdentifier(node) && needsResolution(node, parent)) {\r\n return context.getIdentifier(node.text) ?? `this.${node.text}`;\r\n }\r\n\r\n // No resolvable identifiers in this subtree — emit verbatim\r\n if (!containsResolvableIdentifier(node, parent)) {\r\n return node.getText();\r\n }\r\n\r\n /*\r\n Has resolvable identifiers — recurse into children and concatenate.\r\n We use the original source positions to reconstruct spacing between\r\n children faithfully instead of joining with a fixed separator.\r\n */\r\n const sourceText = node.getSourceFile().text;\r\n let result = '';\r\n let lastEnd = node.getStart();\r\n\r\n ts.forEachChild(node, child => {\r\n result = `${result}${sourceText.slice(lastEnd, child.getStart())}${emitNode(child, node, context)}`;\r\n lastEnd = child.getEnd();\r\n });\r\n\r\n // Append any trailing text after the last child (e.g. closing paren)\r\n return `${result}${sourceText.slice(lastEnd, node.getEnd())}`;\r\n}\r\n\r\n/**\r\n * Returns true if the subtree rooted at `node` contains at least one\r\n * Identifier that needs context resolution.\r\n *\r\n * Short-circuits as soon as one is found to avoid visiting the whole tree.\r\n */\r\nfunction containsResolvableIdentifier(node: ts.Node, parent: ts.Node): boolean {\r\n if (ts.isIdentifier(node) && needsResolution(node, parent)) {\r\n return true;\r\n }\r\n\r\n let found = false;\r\n\r\n ts.forEachChild(node, child => {\r\n if (!found) {\r\n found = containsResolvableIdentifier(child, node);\r\n }\r\n });\r\n\r\n return found;\r\n}\r\n\r\n/**\r\n * Returns true if the identifier needs to be resolved against the context\r\n * or prefixed with `this.` — i.e. it is not a global/builtin identifier\r\n * and not the property-name side of a member access expression.\r\n */\r\nfunction needsResolution(node: ts.Identifier, parent: ts.Node): boolean {\r\n return !((ts.isPropertyAccessExpression(parent) && parent.name === node) || GLOBAL_IDENTIFIERS.has(node.text));\r\n}\r\n\r\n/**\r\n * Generates a unique variable name for an element based on its tag name and parent node.\r\n * If the parent node is 'this._root', the identifier will be based solely on the element's type.\r\n * Otherwise, it will be prefixed with the parent node's name to ensure uniqueness.\r\n * @param node The ElementNode for which to generate the identifier.\r\n * @param parentNode The name of the parent node to ensure uniqueness in the context of nested elements.\r\n * @returns A string representing the unique variable name for the element.\r\n */\r\nexport function getElementIdentifier(node: ElementNode, parentNode: string, index: string): string {\r\n return parentNode !== ROOT_NODE ? `${parentNode}_${node.tagName}${index}` : `${node.tagName}${index}`;\r\n}\r\n\r\nexport function getTextIdentifier(parentNode: string, index: string, prefix = 'text'): string {\r\n return parentNode !== ROOT_NODE ? `${parentNode}_${prefix}${index}` : `${prefix}${index}`;\r\n}\r\n\r\n","import { ConstDeclarationNode } from '../../parser/types/nodes/const-declaration-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a `@const` declaration node.\r\n * Emits a `const name = expression;` JavaScript statement.\r\n *\r\n * @param node The `ConstDeclarationNode` to process.\r\n * @param _nodeName Unused node name.\r\n * @param _parentNode Unused parent node name.\r\n * @param _context Unused render context.\r\n * @returns Array containing the generated const statement string.\r\n */\r\nexport function processConstDeclaration(node: ConstDeclarationNode, _nodeName: string, _parentNode: string, context: Context): string[] {\r\n context.addIdentifier(node.varName);\r\n \r\n return [\r\n `const ${node.varName} = ${resolveExpression(node.expression, context)};`\r\n ];\r\n}\r\n","import { ElementNode } from '../../parser/types/nodes/element-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { getElementIdentifier, resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for an HTML element node: creates the DOM element, sets attributes,\r\n * attaches event listeners, appends it to the parent, and recursively processes children.\r\n *\r\n * @param node The `ElementNode` to process.\r\n * @param nodeName Variable name to use for the created DOM element.\r\n * @param parentNode Variable name of the parent DOM node to append to.\r\n * @param context Current render scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processElement(node: ElementNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const childrenContext = new Context([], context);\r\n const tagName = node.tagName;\r\n\r\n return [\r\n `const ${nodeName} = document.createElement(\"${tagName}\");`,\r\n ...(node.attributes?.map(attr => {\r\n const value = attr.value;\r\n return typeof value === \"string\" \r\n ? `${nodeName}.setAttribute('${attr.name}', ${value});`\r\n : `effect(() => ${nodeName}.setAttribute('${attr.name}', ${resolveExpression(value.expression, context)}));`\r\n }) || []),\r\n ...(node.events?.map(event => `${nodeName}.addEventListener(\"${event.name}\", ($event) => this.${event.handler});`) || []),\r\n `${parentNode}.appendChild(${nodeName});`,\r\n ...(node.children.map((child, i) => processNode(child, i.toString(), nodeName, childrenContext)).flat())\r\n ];\r\n}\r\n","import { indent } from '@xaendar/common';\r\nimport { ForImplicitVariables } from '../../parser/types/nodes/for-implicit-variables.js';\r\nimport { ForNode } from '../../parser/types/nodes/for-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { getTextIdentifier } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a `@for` iteration node.\r\n *\r\n * Emits a classic index-based `for` loop with all implicit variables\r\n * declared at the top of the loop body:\r\n *\r\n * ```javascript\r\n * for (let $i = 0; $i < ctx_items.length; $i++) {\r\n * const item = items[$i];\r\n * const $index = $i;\r\n * const $first = $i === 0;\r\n * const $last = $i === items.length - 1;\r\n * const $even = $i % 2 === 0;\r\n * const $odd = $i % 2 !== 0;\r\n * // ... child nodes\r\n * }\r\n * ```\r\n *\r\n * The iterable identifier is resolved through the active {@link Context}:\r\n * if found in scope it is used as-is, otherwise `this.` is prepended.\r\n *\r\n * The internal loop counter is always named `$i_<nodeName>` to avoid\r\n * collisions when `@for` blocks are nested.\r\n *\r\n * @param node - The `ForNode` to process.\r\n * @param nodeName - Base variable name prefix used for child nodes and\r\n * to produce a unique loop counter identifier.\r\n * @param parentNode - Variable name of the parent DOM node.\r\n * @param parentContext - The enclosing scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processFor(node: ForNode, nodeName: string, parentNode: string, parentContext: Context): string[] {\r\n const iterableSource = node.iterableSource;\r\n const iterableExpr = parentContext.getIdentifier(iterableSource) ?? `this.${iterableSource}`;\r\n\r\n const itemsName = getTextIdentifier(parentNode, nodeName, 'items');\r\n const counterName = getTextIdentifier(parentNode, nodeName, 'i');\r\n\r\n const indexName = resolveImplicit(node, '$index');\r\n const firstName = resolveImplicit(node, '$first');\r\n const lastName = resolveImplicit(node, '$last');\r\n const evenName = resolveImplicit(node, '$even');\r\n const oddName = resolveImplicit(node, '$odd');\r\n const forContext = new Context([node.itemAlias, indexName, firstName, lastName, evenName, oddName], parentContext);\r\n\r\n return [\r\n `const ${itemsName} = ${iterableExpr};`,\r\n `for (let ${counterName} = 0; ${counterName} < ${itemsName}.length; ${counterName}++) {`,\r\n ...indent(`const ${node.itemAlias} = ${itemsName}[${counterName}];`,\r\n `const ${indexName} = ${counterName};`,\r\n `const ${firstName} = ${counterName} === 0;`,\r\n `const ${lastName} = ${counterName} === ${itemsName}.length - 1;`,\r\n `const ${evenName} = ${counterName} % 2 === 0;`,\r\n `const ${oddName} = ${counterName} % 2 !== 0;`\r\n ),\r\n ...node.children.flatMap((child, i) => indent(...processNode(child, `${nodeName}_${i}`, parentNode, forContext))),\r\n '}',\r\n ];\r\n}\r\n\r\n/**\r\n * Resolves the name that should be used in generated code for a given\r\n * implicit variable.\r\n *\r\n * If the template declared an explicit alias for the variable\r\n * (e.g. `; $index = i`) that alias is returned. Otherwise the default\r\n * implicit variable name (e.g. `$index`) is used.\r\n *\r\n * @param node - The `ForNode` whose implicit alias map is consulted.\r\n * @param implicit - The implicit variable to look up (e.g. `'$index'`).\r\n * @returns The alias string if one was declared, otherwise `implicit` itself.\r\n */\r\nfunction resolveImplicit(node: ForNode, implicit: ForImplicitVariables): string {\r\n return node.implicitAliases.get(implicit) ?? implicit;\r\n}","import { indent } from '@xaendar/common';\r\nimport { ASTNodeType } from '../../parser/types/node.enum.js';\r\nimport { ElseIfNode } from '../../parser/types/nodes/else-if-node.type.js';\r\nimport { ElseNode } from '../../parser/types/nodes/else-node.type.js';\r\nimport { IfNode } from '../../parser/types/nodes/if-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for an `@if` conditional node.\r\n * Emits an `if (...) { ... }` block, appending an `else { ... }` block if an alternate exists.\r\n *\r\n * @param node The `IfNode` to process.\r\n * @param nodeName Base variable name prefix for child nodes.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param context Current render scope context.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processIf(node: IfNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const ifContext = new Context([], context);\r\n\r\n const code = [\r\n `if (${resolveExpression(node.conditionNode, context)}) {`,\r\n ...processConsequent(node, nodeName, parentNode, ifContext),\r\n '}'\r\n ];\r\n\r\n let alt = node.alternate;\r\n while (alt?.type === ASTNodeType.ElseIf) {\r\n const elseIfContext = new Context([], context);\r\n\r\n code[code.length - 1] += ` else if (${resolveExpression(alt.conditionNode, context)}) {`\r\n code.push(\r\n ...processConsequent(alt, nodeName, parentNode, elseIfContext),\r\n '}'\r\n );\r\n alt = alt.alternate;\r\n }\r\n \r\n if (alt) {\r\n const elseContext = new Context([], context);\r\n code[code.length - 1] += ' else {';\r\n code.push(\r\n ...processConsequent(alt, nodeName, parentNode, elseContext),\r\n '}'\r\n );\r\n }\r\n\r\n return code;\r\n}\r\n\r\nfunction processConsequent(node: IfNode | ElseIfNode | ElseNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n return node.consequent.map((child, i) => indent(...processNode(child, `${nodeName}_${i}`, parentNode, context))).flat();\r\n}","import { indent } from '@xaendar/common';\r\nimport { SwitchNode } from '../../parser/types/nodes/switch-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { processNode } from '../render-generator.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a `@switch` node.\r\n * Emits a `switch (expression) { case ...: { ... break; } ... }` block.\r\n *\r\n * @param node The `SwitchNode` to process.\r\n * @param nodeName Base variable name prefix for child nodes.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param context Current render scope context.\r\n * @param processNode Recursive node processor function.\r\n * @returns Array of generated code lines.\r\n */\r\nexport function processSwitch(node: SwitchNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n return [\r\n `switch (${resolveExpression(node.expression, context)}) {`,\r\n ...node.cases.map(caseNode => ([\r\n ...indent(\r\n ...(!caseNode.condition ? ['default: {'] : caseNode.condition.map((cond, i, arr) => `case ${cond}:${i === arr.length - 1 ? ' {' : ''}`)),\r\n ...caseNode.children.map((child, i) => indent(...processNode(child, `${nodeName}_${i}_${i}`, parentNode, new Context([], context)))).flat(),\r\n `${indent('break;')}`,\r\n `}`\r\n )\r\n ])).flat(),\r\n '}'\r\n ];\r\n}\r\n","import { ASTNodeType } from '../../parser/types/node.enum.js';\r\nimport { InterpolationNode } from '../../parser/types/nodes/interpolation-node.type.js';\r\nimport { TextNode } from '../../parser/types/nodes/text-node.type.js';\r\nimport { Context } from '../models/render-context.model.js';\r\nimport { resolveExpression } from '../utils/render-generator.utils.js';\r\n\r\n/**\r\n * Generates code for a text or interpolation node.\r\n * Creates a DOM text node with either a JSON-stringified literal or a resolved expression,\r\n * then appends it to the parent DOM node.\r\n *\r\n * @param node A `TextNode` or `InterpolationNode` to process.\r\n * @param nodeName Variable name for the created text node.\r\n * @param parentNode Variable name of the parent DOM node.\r\n * @param _context Unused render context.\r\n * @returns Array of two generated code lines: the text node creation and the appendChild call.\r\n */\r\nexport function processTextAndInterpolation(node: TextNode | InterpolationNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n const textValue = node.type === ASTNodeType.Text ? JSON.stringify(node.value) : resolveExpression(node.expression, context);\r\n\r\n return [\r\n `const ${nodeName} = document.createTextNode(${textValue});`,\r\n `${parentNode}.appendChild(${nodeName});`,\r\n `effect(() => ${nodeName}.textContent = ${textValue});`\r\n ];\r\n}\r\n","import { indent } from \"@xaendar/common\";\r\nimport { NoArgsFunction } from \"@xaendar/types\";\r\nimport { ASTNode } from \"../parser/types/ast.type.js\";\r\nimport { ASTNodeType } from \"../parser/types/node.enum.js\";\r\nimport { Context } from \"./models/render-context.model.js\";\r\nimport { processConstDeclaration } from \"./states/process-const-declaration.state.js\";\r\nimport { processElement } from \"./states/process-element.state.js\";\r\nimport { processFor } from \"./states/process-for.state.js\";\r\nimport { processIf } from \"./states/process-if.state.js\";\r\nimport { processSwitch } from \"./states/process-switch.state.js\";\r\nimport { processTextAndInterpolation } from \"./states/process-text-and-interpolation.state.js\";\r\nimport { getElementIdentifier, getTextIdentifier, ROOT_NODE } from \"./utils/render-generator.utils.js\";\r\n\r\nconst nodeToProcess = new Map<string, NoArgsFunction<string[]>>;\r\n\r\n/**\r\n * Generates the TypeScript body of a render function from an AST.\r\n *\r\n * @param ast Top-level AST nodes produced by the Parser\r\n * @returns String containing the render function body\r\n */\r\nexport function generateRenderFunction(ast: ASTNode[], cssVariableName: string): string {\r\n nodeToProcess.clear();\r\n const context = new Context;\r\n\r\n const renderFunctions = [\r\n '_render() {',\r\n ...indent(\r\n `this._root.adoptedStyleSheets = [${cssVariableName}];`,\r\n ...ast.map((node, i) => [...processNode(node, i.toString(), ROOT_NODE, context)]).flat()\r\n ),\r\n '}',\r\n ]\r\n\r\n while (nodeToProcess.size > 0) {\r\n const [key, fn] = nodeToProcess.entries().next().value!;\r\n renderFunctions.push(\r\n `${key} {`,\r\n ...indent(...fn()),\r\n '}',\r\n );\r\n nodeToProcess.delete(key);\r\n }\r\n\r\n return renderFunctions.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Generates code that appends `nodeName` to `parentNode`.\r\n * For flow control nodes no single var is produced; instead multiple children\r\n * are appended directly inside the control flow block.\r\n */\r\nexport function processNode(node: ASTNode, nodeName: string, parentNode: string, context: Context): string[] {\r\n switch (node.type) {\r\n case ASTNodeType.Text:\r\n case ASTNodeType.Interpolation:\r\n return processTextAndInterpolation(node, getTextIdentifier(parentNode, nodeName), parentNode, context);\r\n\r\n case ASTNodeType.Element:\r\n return processElement(node, getElementIdentifier(node, parentNode, nodeName), parentNode, context);\r\n\r\n case ASTNodeType.If:\r\n const keyIf = `if_${nodeName}()`\r\n nodeToProcess.set(keyIf, () => processIf(node, nodeName, parentNode, context));\r\n return [`this.${keyIf};`];\r\n\r\n case ASTNodeType.For:\r\n const keyFor = `for_${nodeName}()`\r\n nodeToProcess.set(keyFor, () => processFor(node, nodeName, parentNode, context));\r\n return [`this.${keyFor};`];\r\n\r\n case ASTNodeType.Switch:\r\n const keySwitch = `switch_${nodeName}()`\r\n nodeToProcess.set(keySwitch, () => processSwitch(node, nodeName, parentNode, context));\r\n return [`this.${keySwitch};`];\r\n\r\n case ASTNodeType.ConstDeclaration:\r\n return processConstDeclaration(node, nodeName, parentNode, context);\r\n\r\n default:\r\n return [];\r\n }\r\n}\r\n","import { Lexer } from \"./lexer/lexer\";\r\nimport { Parser } from \"./parser/parser\";\r\nimport { generateRenderFunction } from \"./render-generator/render-generator\";\r\n\r\nexport function compile(input: string, cssVariableName: string): string {\r\n const tokens = new Lexer(input).tokenize();\r\n const ast = new Parser(tokens).parse();\r\n return generateRenderFunction(ast, cssVariableName);\r\n}"],"mappings":"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"}