Files
rspade_system/node_modules/@jqhtml/parser
root f6ac36c632 Enhance refactor commands with controller-aware Route() updates and fix code quality violations
Add semantic token highlighting for 'that' variable and comment file references in VS Code extension
Add Phone_Text_Input and Currency_Input components with formatting utilities
Implement client widgets, form standardization, and soft delete functionality
Add modal scroll lock and update documentation
Implement comprehensive modal system with form integration and validation
Fix modal component instantiation using jQuery plugin API
Implement modal system with responsive sizing, queuing, and validation support
Implement form submission with validation, error handling, and loading states
Implement country/state selectors with dynamic data loading and Bootstrap styling
Revert Rsx::Route() highlighting in Blade/PHP files
Target specific PHP scopes for Rsx::Route() highlighting in Blade
Expand injection selector for Rsx::Route() highlighting
Add custom syntax highlighting for Rsx::Route() and Rsx.Route() calls
Update jqhtml packages to v2.2.165
Add bundle path validation for common mistakes (development mode only)
Create Ajax_Select_Input widget and Rsx_Reference_Data controller
Create Country_Select_Input widget with default country support
Initialize Tom Select on Select_Input widgets
Add Tom Select bundle for enhanced select dropdowns
Implement ISO 3166 geographic data system for country/region selection
Implement widget-based form system with disabled state support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 06:21:56 +00:00
..

JQHTML Parser

The JQHTML parser converts template files into JavaScript functions that use the component system.

Quick Start - Common Patterns

Basic Component with innerHTML (Most Common)

<!-- Define a component with default attributes -->
<Define:Card tag="article" class="card" style="padding: 10px">
  <div class="card-body">
    <%= content() %>  <!-- Outputs whatever innerHTML was passed -->
  </div>
</Define:Card>

<!-- Usage - just pass innerHTML like regular HTML -->
<Card class="featured">
  <h3>Card Title</h3>
  <p>This is the card content.</p>
  <button>Click me</button>
</Card>

<!-- Result: <article class="card featured Card Jqhtml_Component" style="padding: 10px"> -->

This content() pattern is the primary way to compose components in JQHTML. It works like regular HTML - the innerHTML you pass gets rendered where content() is called.

Container Component Example

<!-- A container with default size that can be overridden -->
<Define:Container $size="medium" class="container">
  <div class="container-inner <%= this.args.size %>">
    <%= content() %>  <!-- Simple innerHTML output -->
  </div>
</Define:Container>

<!-- Usage - override the default size -->
<Container $size="large">
  <p>Any content here</p>
  <UserList />
  <Footer />
</Container>

Note: Slots (<#slotname>) are an advanced feature only needed when you have multiple distinct content areas. For 95% of use cases, the simple content() pattern shown above is recommended.

Define Tag Attributes (Component Configuration)

Define tags support three types of attributes for configuring components:

<Define:Contacts_DataGrid
    extends="DataGrid_Abstract"
    $ajax_endpoint=Frontend_Contacts_Controller.datagrid_fetch
    $per_page=25
    class="card DataGrid">
  <div>Content here</div>
</Define:Contacts_DataGrid>

1. extends="" - Template Inheritance Explicitly declare parent template for inheritance (without requiring a JavaScript class).

2. $property=value - Default Args Set default values for this.args that component invocations can override:

  • Quoted: $user_id="123" → String literal "123"
  • Unquoted: $handler=MyController.fetch → Raw JavaScript expression
  • These become defaults; invocations can override them

3. Regular Attributes Standard HTML attributes like class="", tag="" applied to root element.

Generated Output:

{
  name: 'Contacts_DataGrid',
  tag: 'div',
  defaultAttributes: {"class": "card DataGrid"},
  defineArgs: {"ajax_endpoint": Frontend_Contacts_Controller.datagrid_fetch, "per_page": "25"},
  extends: 'DataGrid_Abstract',
  render: function() { ... }
}

Slot-Based Template Inheritance

When a template contains ONLY slots (no HTML), it automatically inherits the parent class template:

<!-- Parent: DataGrid_Abstract.jqhtml -->
<Define:DataGrid_Abstract>
  <table>
    <thead><tr><%= content('header') %></tr></thead>
    <tbody>
      <% for (let record of this.data.records) { %>
        <tr><%= content('row', record) %></tr>
      <% } %>
    </tbody>
  </table>
</Define:DataGrid_Abstract>

<!-- Child: Users_DataGrid.jqhtml (slot-only) -->
<Define:Users_DataGrid>
  <#header>
    <th>ID</th><th>Name</th><th>Email</th>
  </#header>
  <#row>
    <td><%= row.id %></td>
    <td><%= row.name %></td>
    <td><%= row.email %></td>
  </#row>
</Define:Users_DataGrid>

The parser detects slot-only templates and generates {_slots: {...}} format. Runtime walks prototype chain to find parent templates. Data passing: content('row', record) passes data to slot parameter function(row) { ... }. Reserved words: Slot names cannot be JavaScript keywords (function, if, etc.) - parser rejects with fatal error.

Lexer (Task 1 - COMPLETE)

The lexer is the first stage of the parser. It converts raw JQHTML template text into a stream of tokens.

Features

  • No regex - Uses simple character scanning for maintainability
  • Position tracking - Every token includes line, column, and absolute positions for source maps
  • Simple token types - Clear, unambiguous token categories
  • Efficient scanning - Single pass through the input

Token Types

  • TEXT - Plain HTML/text content
  • EXPRESSION_START - <%= opening tag
  • CODE_START - <% opening tag
  • TAG_END - %> closing tag
  • IF, ELSE, ELSEIF, ENDIF - Conditional keywords
  • FOR, ENDFOR - Loop keywords
  • DEFINE_START, DEFINE_END - Component definition tags
  • COMPONENT_NAME - Component identifier
  • JAVASCRIPT - JavaScript code within tags

Usage

import { Lexer } from '@jqhtml/parser';

const template = `
<Define:MyComponent>
  <h1><%= this.data.title %></h1>
  <% if (this.data.show): %>
    <p>Content here</p>
  <% endif; %>
</Define:MyComponent>
`;

const lexer = new Lexer(template);
const tokens = lexer.tokenize();

// tokens is an array of Token objects with:
// - type: TokenType
// - value: string
// - line: number
// - column: number  
// - start: number (absolute position)
// - end: number

Testing

# Build the parser
npm run build

# Run the test suite
node test-lexer.js

# Run the demo
node demo-lexer.js

Implementation Notes

The lexer uses a simple state machine approach:

  1. Text scanning - Default mode, captures plain text
  2. Tag detection - Looks for <%, <%=, %> sequences
  3. Keyword matching - After <%, checks for control flow keywords
  4. JavaScript capture - Captures code between tags
  5. Position tracking - Updates line/column for every character

No regex patterns are used. All scanning is done with:

  • match_sequence() - Check for exact string match
  • match_keyword() - Check for keyword with word boundary
  • Character-by-character advancement

Parser/AST Builder (Task 2 - COMPLETE)

The parser takes the token stream from the lexer and builds an Abstract Syntax Tree (AST) representing the template structure.

Features

  • Recursive descent parsing - Simple, predictable parsing algorithm
  • Clear node types - Each AST node represents a specific construct
  • Position preservation - All nodes include source positions
  • Error reporting - Clear messages with line/column information

AST Node Types

  • Program - Root node containing all top-level definitions
  • ComponentDefinition - Component template definition
  • Text - Plain text/HTML content
  • Expression - JavaScript expressions (<%= ... %>)
  • IfStatement - Conditional rendering with optional else
  • ForStatement - Loop constructs
  • CodeBlock - Generic JavaScript code blocks

Usage

import { Lexer, Parser } from '@jqhtml/parser';

const template = `
<Define:Card>
  <div class="card">
    <h3><%= title %></h3>
    <% if (showContent): %>
      <p><%= content %></p>
    <% endif; %>
  </div>
</Define:Card>
`;

// Tokenize
const lexer = new Lexer(template);
const tokens = lexer.tokenize();

// Parse to AST
const parser = new Parser(tokens);
const ast = parser.parse();

// AST structure:
// {
//   type: 'Program',
//   body: [{
//     type: 'ComponentDefinition',
//     name: 'Card',
//     body: [...]
//   }]
// }

Testing

# Run the parser test suite
node test-parser.js

# Run the interactive demo
node demo-parser.js

Implementation Notes

The parser uses straightforward techniques:

  1. Token consumption - Advances through tokens one at a time
  2. Lookahead - Peeks at upcoming tokens to decide parsing path
  3. Context tracking - Knows when inside components, loops, etc.
  4. Error recovery - Provides helpful error messages

No parser generators or complex algorithms - just simple recursive functions that build nodes.

Code Generator (Task 3 - COMPLETE)

The code generator takes the AST and produces executable JavaScript functions that work with the JQHTML component system.

Features

  • jQuery-based DOM manipulation - Generates efficient jQuery code
  • Component render functions - Each template becomes a render function
  • Control flow handling - Properly handles if/else and for loops
  • Expression evaluation - Safely evaluates and renders expressions
  • Colon syntax support - Strips trailing colons from control statements

Generated Code Structure

// Each component gets a render function
jqhtml_components.set('ComponentName', {
  name: 'ComponentName',
  render: function render() {
    const $root = $('<div></div>');
    const $current = $root;
    
    // Generated DOM manipulation code here
    
    return $root.children();
  },
  dependencies: []
});

Usage

import { Lexer, Parser, CodeGenerator } from '@jqhtml/parser';

const template = `
<Define:MyComponent>
  <h1><%= this.data.title %></h1>
  <% if (this.data.items): %>
    <ul>
      <% for (const item of this.data.items): %>
        <li><%= item %></li>
      <% endfor; %>
    </ul>
  <% endif; %>
</Define:MyComponent>
`;

// Generate the code
const lexer = new Lexer(template);
const tokens = lexer.tokenize();
const parser = new Parser(tokens);
const ast = parser.parse();
const generator = new CodeGenerator();
const result = generator.generate(ast);

// Use in a component
class MyComponent extends Component {
  async on_render() {
    const template = result.components.get('MyComponent');
    const elements = template.render.call(this);
    this.$.append(elements);
  }
}

Testing

# Run the code generator test suite
node test-codegen.js

# Run the interactive demo
node demo-codegen.js

# View the integration example
# Open example-integration.html in a browser

Implementation Notes

The code generator:

  1. Traverses the AST - Visits each node and generates appropriate code
  2. Maintains context - Tracks current jQuery element for appending
  3. Handles nesting - For loops create temporary containers
  4. Strips syntax - Removes trailing colons from control flow
  5. Escapes strings - Properly escapes text content for JavaScript

v1 JavaScript Compilation Analysis

A comprehensive analysis of how JQHTML v1 compiles templates to JavaScript has been documented in JQHTML_V1_JAVASCRIPT_COMPILATION_PATTERNS.md. This analysis reveals:

  • Instruction-based output: Templates compile to arrays of rendering instructions
  • Three instruction types: {tag:...}, {comp:...}, {block:...}
  • Context preservation: The _that = this pattern for nested functions
  • Single-pass DOM construction: Efficient rendering with one $.html() call
  • Deferred component initialization: Two-phase process for component creation

These patterns inform v2 implementation decisions, particularly around maintaining the efficient instruction-based architecture while modernizing the JavaScript output.

Implementation Status (December 2024)

Completed Tasks

  1. Lexer - Full tokenization with position tracking
  2. Parser - AST generation with all v2 syntax
  3. Code Generator - Instruction array generation
  4. Component Integration - Runtime integration complete
  5. Slot System - <#name> syntax fully implemented
  6. Nested Components - <ComponentName> recognition
  7. Binding Syntax - :prop and @event support

Current Features

  • Template Syntax: HTML with embedded JavaScript
  • Control Flow: if/else/elseif and for loops (both colon and brace styles)
  • Components: <Define:Name> definitions and <ComponentName> invocations
  • Slots: <#name>content</#name> and <#name /> syntax
  • Expressions: <%= expression %> for output
  • Bindings: :text, :value, :class, :style for data binding
  • Events: @click, @change, etc. for event handlers
  • Scoped IDs: $id attribute for component-scoped IDs

Instruction Format

The parser generates v1-compatible instruction arrays:

// HTML tags
{tag: ["div", {"class": "card"}, false]}  // open tag
{tag: ["div", {}, true]}                   // close tag

// Components
{comp: ["UserCard", {name: "John"}]}

// Slots
{slot: ["header", {}, (props) => {
  const _output = [];
  _output.push("Header content");
  return [_output, this];
}]}

// Text content
"Plain text"

// Expressions
{expr: () => this.data.title}

Integration with Core

Templates compile to functions that return [instructions, context]:

function render() {
  const _output = [];
  
  // Generate instructions...
  _output.push({tag: ["h1", {}, false]});
  _output.push("Hello World");
  _output.push({tag: ["h1", {}, true]});
  
  return [_output, this];
}

The core runtime's instruction processor handles these arrays to create DOM.

Next Steps

  1. Build Tools - Webpack loader for .jqhtml imports
  2. Source Maps - Full debugging support
  3. VS Code Extension - Syntax highlighting
  4. Autoformatter - Code formatting for .jqhtml files