## Overview

Cat is a specialized compiler designed to transform custom HTML components into highly optimized vanilla JavaScript that leverages the native Custom Elements API. The compiler's primary goal is to generate efficient, runtime-free components that utilize browser native APIs to their full potential.

## Project Goals

1. **Zero Runtime Overhead**
   - Compile components directly to vanilla JavaScript
   - No external runtime dependencies
   - Pure utilization of browser native APIs

2. **Custom Elements Focus**
   - Leverage the Web Components standard
   - Generate optimized Custom Elements implementations
   - Maintain native browser performance characteristics

3. **Developer Experience**
   - Simple component authoring with HTML-first approach
   - Clear separation of concerns (HTML, JS, CSS)
   - Familiar syntax with enhanced capabilities
   - Declarative Syntax.

# Cat syntax

```
<test-comp>

    <h1>{count}</h1>
    <button onclick="">Increase</button>

</test-comp>

<script>

let count = 0;

const increment = () => count += 1; 

</script>

<style>
h1{
    color: blue;
    font-size: large;
    font-family: 'Courier New', Courier, monospace;
}
</style>
```


### cat\src\body.js

```javascript
/**
 * Body Interpreter Module
 * 
 * This module interprets the parsed HTML body, converting custom syntax to JavaScript template literals.
 * It also tracks all interpreted variables in a bindings array.
 */

/**
 * Convert custom syntax to JavaScript Template Literals and track bindings
 * @param {string} content - The content to interpret
 * @param {Set} bindingsSet - Set to store unique bindings
 * @returns {string} - The interpreted content
 */
function interpretContent(content, bindingsSet) {
    return content.replace(/\{([^}]+)\}/g, (match, p1) => {
      const trimmed = p1.trim();
      bindingsSet.add(trimmed);
      return `\${this.${trimmed}}`;
    });
  }
  
  /**
   * Recursively interpret the parsed body and collect bindings
   * @param {Array} parsedBody - The parsed HTML body
   * @param {Set} bindingsSet - Set to store unique bindings
   * @returns {Array} - The interpreted body
   */
  function interpretBody(parsedBody, bindingsSet) {
    return parsedBody.map(node => {
      if (node.type === 'tag') {
        return {
          ...node,
          children: interpretBody(node.children, bindingsSet)
        };
      } else if (node.type === 'text') {
        return {
          ...node,
          content: interpretContent(node.content, bindingsSet)
        };
      }
      return node;
    });
  }
  
  /**
   * Main function to interpret the body of a file and collect bindings
   * @param {Object} body - The parsed HTML body
   * @returns {Object} - Object containing the interpreted body and bindings array
   */
  function interpretHTML(body) {
    const bindingsSet = new Set();
    const interpretedBody = interpretBody(body, bindingsSet);
    return {
      body: interpretedBody,
      bindings: Array.from(bindingsSet)
    };
  }
  
  module.exports = { interpretHTML };
```

### cat\src\builder.js

```javascript
/**
 * Builder Module
 * 
 * Assembles the final Custom Element class without shadow DOM.
 */

const escodegen = require('escodegen');

/**
 * Generates JavaScript code from AST nodes
 * @param {Array} nodes - AST nodes
 * @returns {string} Generated code
 */
function generateCode(nodes) {
    if (!nodes) return '';
    
    const program = {
        type: 'Program',
        body: nodes,
        sourceType: 'script'
    };

    return escodegen.generate(program);
}

/**
 * Builds the Custom Element class
 * @param {Object} file - Processed file object
 * @returns {string} Class definition as string
 */
function buildClass(file) {
    const className = file.name
        .split('-')
        .map(part => part.charAt(0).toUpperCase() + part.slice(1))
        .join('');

    const bodyCode = generateCode(file.body);
    const variablesCode = generateCode(file.script.variables.declarations);
    const mountCode = generateCode(file.mount);

    return `
class ${className} extends HTMLElement {
    constructor() {
        super();
    }

    connectedCallback() {
    
        // Create DOM structure
        ${bodyCode}

        // Initialize variables
        ${variablesCode}

        // Setup dynamic bindings
        ${mountCode}

        // Single DOM operation after everything is ready
        this.appendChild(this.fragment);
    }
}

// Register the custom element
customElements.define('${file.name}', ${className});
`;
}

module.exports = { buildClass };
```

### cat\src\code.js

```javascript
/**
 * Code Generator Module
 * 
 * Converts AST nodes back to JavaScript code strings.
 * Used as the final step before the builder module.
 */

const escodegen = require('escodegen');

/**
 * Configuration for code generation
 */
const ESCODEGEN_CONFIG = {
    format: {
        indent: {
            style: '    ',
            base: 0
        },
        newline: '\n',
        space: ' ',
        quotes: 'single',
        semicolons: true
    },
    comment: true
};

/**
 * Wraps AST nodes in a Program node if needed
 * @param {Object|Array} ast - AST node or array of nodes
 * @returns {Object} - Complete Program AST node
 */
function wrapInProgram(ast) {
    if (!ast) return null;
    
    if (ast.type === 'Program') {
        return ast;
    }

    const body = Array.isArray(ast) ? ast : [ast];
    return {
        type: 'Program',
        body: body,
        sourceType: 'script'
    };
}

/**
 * Generates code from AST safely
 * @param {Object|Array} ast - AST node or array of nodes
 * @returns {string} - Generated JavaScript code
 */
function generateCode(ast) {
    if (!ast) return '';
    
    try {
        const program = wrapInProgram(ast);
        if (!program) return '';
        
        return escodegen.generate(program, ESCODEGEN_CONFIG)
            .replace(/^"use strict";\n/, ''); // Remove 'use strict' if present
    } catch (error) {
        console.error('Code generation error:', error);
        return `/* Code generation error: ${error.message} */`;
    }
}

/**
 * Generates code for script sections
 * @param {Object} script - Script object with categorized AST nodes
 * @returns {Object} - Script object with generated code strings
 */
function generateScriptCode(script) {
    if (!script) return null;

    return {
        variables: {
            declarations: generateCode(script.variables.declarations),
            usage: generateCode(script.variables.usage)
        },
        methods: generateCode(script.methods),
        events: generateCode(script.events),
        calls: generateCode(script.calls),
        iife: generateCode(script.iife)
    };
}

/**
 * Main function to convert AST to code
 * @param {Object} file - File object containing script and body ASTs
 * @returns {Object} - File object with generated code
 */
function generateFileCode(file) {
    if (!file) return null;

    return {
        ...file,
        script: generateScriptCode(file.script),
        body: generateCode(file.body),
        mount: generateCode(file.mount)
    };
}

module.exports = { generateFileCode };
```

### cat\src\collector.js

```javascript
const fs = require('fs-extra');
const path = require('path');
const glob = require('glob');
const { determineFileType } = require('./typeof');

/**
 * Collect and structure HTML files from the project
 * @param {string} projectRoot - Root directory of the project
 * @returns {Object} - Structured object of HTML files
 */
async function collectHTMLFiles(projectRoot) {
  const htmlFiles = glob.sync('**/*.{comp.html,page.html}', {
    cwd: projectRoot,
    ignore: ['node_modules/**', 'cat/**'],
  });

  const collectedFiles = [];

  for (const file of htmlFiles) {
    const filePath = path.join(projectRoot, file);
    const content = await fs.readFile(filePath, 'utf-8');
    const fileType = determineFileType(file);

    collectedFiles.push({
        file,
        type: fileType,
        name: null,
        body: content,
        script: null,
        style:null,
        bindings: null,
        mount: null
      });
  }

  return collectedFiles;
}

module.exports = { collectHTMLFiles };
```

### cat\src\index.js

```javascript
const path = require('path');
const fs = require('fs-extra');

const { collectHTMLFiles } = require('./collector');
const { sliceContent } = require('./slicer');
const { parseContent } = require('./parser');
const { interpretHTML } = require('./body');
const { interpretScript } = require('./script');
const { transformToJavaScript } = require('./transformer');
const { resolveDOM } = require('./resolver');
const { wire } = require('./wirer');
const { viewScript } = require('./sviewer');
// const { buildClass } = require('./builder');
const { validateProps } = require('./props');
const { generateFileCode } = require('./code');




async function compile(indexPath) {

    const projectRoot = path.dirname(indexPath);
    const collectedFiles = await collectHTMLFiles(projectRoot);

    // Log the collected files
    console.log('--- START ---');

    collectedFiles.forEach(file => {
        
        console.log('');
        console.log('');
        console.log('');
        console.log('');
        console.log(`====== ${ file.file } ======`);
        console.log('');
        console.log('');
        
        //Slicing
        file = sliced = { ...file, ...sliceContent(file) };

        // Parsing HTML and JS
        file = { ...file, ... parseContent(file) }

        // Interprete Body syntax
        file = { ...file, ... interpretHTML(file.body) }

        // Interprete Script syntax
        file = { ...file, ... interpretScript(file.script) }

        // Transform HTML into JavaScript
        file = { ...file, ... transformToJavaScript(file.body) }

        if(!validateProps(file.bindings, file.script.variables.declarations));

        // Transform HTML into JavaScript
        file = { ...file, ... resolveDOM(file) }

        // Add reactives bindings
        // here...

        // Wire the Script to work on the Class context
        file = { ...file, ... wire(file.script) }

        // Log `file` Object
        console.log(file);

    });

    console.log('--- ENDS ---');
}

module.exports = { compile };
```

### cat\src\parser.js

```javascript
const { parseDocument } = require('htmlparser2');
const acorn = require('acorn');

/**
 * Parser Module
 * 
 * This module parses HTML and JavaScript content into structured formats.
 */

/**
 * Parse HTML content into a tree-like structure
 * @param {string} htmlContent - Raw HTML content
 * @returns {Array} - Parsed HTML structure
 */
function parseHTML(htmlContent) {
  const rawParsed = parseDocument(htmlContent, { recognizeSelfClosing: true });
  
  function simplifyNode(node) {
    if (node.type === 'tag') {
      return {
        type: 'tag',
        name: node.name,
        attributes: node.attribs,
        children: node.children.map(simplifyNode).filter(Boolean)
      };
    } else if (node.type === 'text') {
      const content = node.data.trim();
      return content ? { type: 'text', content } : null;
    }
    return null;
  }

  return rawParsed.children.map(simplifyNode).filter(Boolean);
}

/**
 * Parse JavaScript content into an AST
 * @param {string} jsContent - Raw JavaScript content
 * @returns {Object} - JavaScript AST
 */
function parseJavaScript(jsContent) {
  return acorn.parse(jsContent, {
    ecmaVersion: 'latest',
    sourceType: 'script'
  });
}

/**
 * Parse both HTML and JavaScript content
 * @param {Object} file - Object containing body and script properties
 * @returns {Object} - Object with parsed body and script
 */
function parseContent(file) {
  const parsedBody = parseHTML(file.body);
  const parsedScript = file.script ? (parseJavaScript(file.script)).body : null;

  return {
    body: parsedBody,
    script: parsedScript
  };
}

module.exports = { parseContent };
```

### cat\src\props.js

```javascript
/**
 * Props Module
 * 
 * Validates that prop usage in templates matches their declarations structure.
 * Returns true if valid, throws descriptive errors if not.
 */

/**
 * Extracts prop path from binding
 * @param {string} binding - The binding expression (e.g., 'prop.user.name')
 * @returns {Array} - Array of path segments (['user', 'name'])
 */
function extractPropPath(binding) {
    return binding.replace('prop.', '').split('.');
}

/**
 * Checks if path exists in object structure
 * @param {Object} obj - Object to traverse
 * @param {Array} path - Path segments
 * @returns {boolean} - True if path exists in object structure
 */
function hasPath(obj, path) {
    let current = obj;
    for (const key of path) {
        if (!current || typeof current !== 'object' || !(key in current)) {
            return false;
        }
        current = current[key];
    }
    return true;
}

/**
 * Finds and validates prop declaration
 * @param {Array} declarations - Variable declarations
 * @returns {Object} - Prop initialization object
 * @throws {Error} If prop declaration is invalid
 */
function validatePropDeclaration(declarations) {
    const propDecl = declarations.find(decl => 
        decl.type === 'VariableDeclaration' &&
        decl.declarations.some(d => 
            d.id.type === 'Identifier' && 
            d.id.name === 'prop'
        )
    );

    if (!propDecl) {
        throw new Error('Template uses props but `let prop` is not declared');
    }

    const declaration = propDecl.declarations[0];
    
    if (!declaration.init || declaration.init.type !== 'ObjectExpression') {
        throw new Error('`let prop` must be initialized with an object literal');
    }

    return declaration.init;
}

/**
 * Converts AST object expression to structure object
 * @param {Object} node - AST node
 * @returns {Object} - Object representing the structure
 */
function astToStructure(node) {
    if (node.type === 'ObjectExpression') {
        const obj = {};
        node.properties.forEach(prop => {
            obj[prop.key.name] = astToStructure(prop.value);
        });
        return obj;
    }
    // Return empty object for any value node to indicate key existence
    return {};
}

/**
 * Validates that all prop bindings have declared structure
 * @param {Array} bindings - Template bindings
 * @param {Array} declarations - Variable declarations
 * @returns {boolean} - True if all validations pass
 * @throws {Error} With detailed message if validation fails
 */
function validateProps(bindings, declarations) {
    // Filter prop bindings
    const propBindings = bindings.filter(b => b.startsWith('prop.'));
    if (propBindings.length === 0) return true;

    // Validate prop declaration and get structure
    const propInit = validatePropDeclaration(declarations);
    const propStructure = astToStructure(propInit);

    // Validate each prop binding
    propBindings.forEach(binding => {
        const path = extractPropPath(binding);
        if (!hasPath(propStructure, path)) {
            throw new Error(
                `Invalid prop reference: '${binding}' is used in template but not declared in 'let prop = {...}'`
            );
        }
    });

    return true;
}

module.exports = { validateProps };

```

### cat\src\resolver.js

```javascript
/**
 * DOM Resolver Module
 * 
 * This module analyzes and resolves DOM element references between transformed HTML
 * and script AST nodes. It maps element creation and replaces DOM queries with
 * direct references to the created elements.
 */

/**
 * Analyzes element creation and attribute information from AST
 * @param {Array} bodyAST - AST nodes from transformed body
 * @returns {Map} Map of elements with their properties
 */
function analyzeElements(bodyAST) {
  const elementMap = new Map();

  // Process each AST node
  bodyAST.forEach(node => {
    // Element creation
    if (node.type === 'ExpressionStatement' &&
        node.expression.type === 'AssignmentExpression' &&
        node.expression.left.type === 'MemberExpression' &&
        node.expression.left.object.type === 'ThisExpression' &&
        node.expression.right.type === 'CallExpression' &&
        node.expression.right.callee.type === 'MemberExpression' &&
        node.expression.right.callee.property.name === 'createElement') {
      
      const varName = node.expression.left.property.name;
      const tagName = node.expression.right.arguments[0].quasis[0].value.raw;
      
      elementMap.set(varName, {
        tagName,
        attributes: {}
      });
    }

    // setAttribute calls
    if (node.type === 'ExpressionStatement' &&
        node.expression.type === 'CallExpression' &&
        node.expression.callee.type === 'MemberExpression' &&
        node.expression.callee.property.name === 'setAttribute') {
      
      const targetElement = node.expression.callee.object.property.name;
      if (elementMap.has(targetElement)) {
        const attrName = node.expression.arguments[0].quasis[0].value.raw;
        const attrValue = node.expression.arguments[1].quasis[0].value.raw;
        elementMap.get(targetElement).attributes[attrName] = attrValue;
      }
    }
  });

  return elementMap;
}

/**
 * Creates an AST node for this.elementRef
 * @param {string} elementVar - Element variable name
 * @returns {Object} AST node
 */
function createThisElementReference(elementVar) {
  return {
    type: 'MemberExpression',
    object: {
      type: 'ThisExpression'
    },
    property: {
      type: 'Identifier',
      name: elementVar
    },
    computed: false
  };
}

/**
 * Creates an AST node for array of element references
 * @param {Array} elementVars - Array of element variable names
 * @returns {Object} AST node
 */
function createElementArrayReference(elementVars) {
  return {
    type: 'ArrayExpression',
    elements: elementVars.map(createThisElementReference)
  };
}

/**
 * Resolves a DOM query node to direct element reference
 * @param {Object} node - AST node
 * @param {Map} elementMap - Map of available elements
 * @returns {Object|null} Resolved AST node or null
 */
function resolveQueryNode(node, elementMap) {
  if (node.type !== 'CallExpression' ||
      !node.callee ||
      node.callee.type !== 'MemberExpression' ||
      !node.callee.object ||
      node.callee.object.name !== 'document') return null;

  const method = node.callee.property.name;
  const [argNode] = node.arguments;
  if (!argNode || !argNode.value) return null;

  const queryValue = argNode.value;

  switch (method) {
    case 'getElementById': {
      for (const [varName, element] of elementMap) {
        if (element.attributes.id === queryValue) {
          return createThisElementReference(varName);
        }
      }
      break;
    }
    
    case 'getElementsByClassName': {
      const elements = Array.from(elementMap.entries())
        .filter(([, element]) => element.attributes.class === queryValue)
        .map(([varName]) => varName);
      
      if (elements.length > 0) {
        return createElementArrayReference(elements);
      }
      break;
    }
  }

  return null;
}

/**
 * Transforms AST nodes by resolving DOM queries
 * @param {Object} node - AST node
 * @param {Map} elementMap - Map of available elements
 * @returns {Object} Transformed AST node
 */
function transformNode(node, elementMap) {
  if (!node || typeof node !== 'object') return node;

  // Check if node is a DOM query
  const resolvedQuery = resolveQueryNode(node, elementMap);
  if (resolvedQuery) return resolvedQuery;

  // Recursively transform child nodes
  if (Array.isArray(node)) {
    return node.map(child => transformNode(child, elementMap));
  }

  const newNode = { ...node };
  for (const key in node) {
    if (typeof node[key] === 'object') {
      newNode[key] = transformNode(node[key], elementMap);
    }
  }

  return newNode;
}

/**
 * Resolves DOM references in script AST
 * @param {Object} scriptAST - Script AST object
 * @param {Map} elementMap - Map of available elements
 * @returns {Object} Resolved script AST
 */
function resolveScriptReferences(scriptAST, elementMap) {
  return {
    variables: {
      declarations: scriptAST.variables.declarations.map(node => 
        transformNode(node, elementMap)
      ),
      usage: scriptAST.variables.usage.map(node => 
        transformNode(node, elementMap)
      )
    },
    methods: scriptAST.methods.map(node => 
      transformNode(node, elementMap)
    ),
    events: scriptAST.events.map(node => 
      transformNode(node, elementMap)
    ),
    calls: scriptAST.calls.map(node => 
      transformNode(node, elementMap)
    ),
    iife: scriptAST.iife.map(node => 
      transformNode(node, elementMap)
    )
  };
}

/**
 * Main function to resolve DOM references
 * @param {Object} file - File object containing transformed body and script AST
 * @returns {Object} Resolved file object
 */
function resolveDOM(file) {
  // Build element map from transformed body AST
  const elementMap = analyzeElements(file.body);
  
  // Resolve script references
  const resolvedScript = resolveScriptReferences(file.script, elementMap);

  return {
    script: resolvedScript,
    references: Object.fromEntries(elementMap)
  };
}

module.exports = { resolveDOM };
```

### cat\src\script.js

```javascript
/**
 * Script Interpreter Module
 * 
 * This module interprets the parsed JavaScript AST, categorizing the code into
 * variables, methods, events, and function calls.
 */

/**
 * Collects identifiers from the AST
 * @param {Array} astBody - Array of AST nodes
 * @returns {Map} - Map of identifiers with their metadata
 */
function collectIdentifiers(astBody) {
  const identifiers = new Map();
  
  astBody.forEach(node => {
    if (node.type === 'VariableDeclaration') {
      node.declarations.forEach(decl => {
        if (node.kind === 'const' && 
            (!decl.init || 
             (decl.init.type !== 'ObjectExpression' && 
              decl.init.type !== 'ArrayExpression'))) {
          return;
        }
        identifiers.set(decl.id.name, {
          type: 'property',
          kind: node.kind,
          name: decl.id.name
        });
      });
    }
    if (node.type === 'FunctionDeclaration') {
      identifiers.set(node.id.name, {
        type: 'method',
        name: node.id.name
      });
    } else if (node.type === 'VariableDeclaration' && 
               node.declarations[0].init?.type === 'ArrowFunctionExpression') {
      const name = node.declarations[0].id.name;
      identifiers.set(name, {
        type: 'method',
        name: name
      });
    }
  });

  return identifiers;
}

/**
 * Check if a node is an IIFE
 * @param {Object} node - AST node
 * @returns {boolean} - True if node is an IIFE
 */
function isIIFE(node) {
  if (node.type !== 'ExpressionStatement') return false;
  
  const expr = node.expression;
  
  if (expr.type === 'CallExpression' && 
      (expr.callee.type === 'FunctionExpression' ||
       expr.callee.type === 'ArrowFunctionExpression')) {
    return true;
  }
  
  if (expr.type === 'CallExpression' && 
      expr.callee.type === 'ParenthesizedExpression' &&
      (expr.callee.expression.type === 'FunctionExpression' ||
       expr.callee.expression.type === 'ArrowFunctionExpression')) {
    return true;
  }
  
  if (expr.type === 'UnaryExpression' && 
      expr.operator === 'void' &&
      expr.argument.type === 'CallExpression' &&
      (expr.argument.callee.type === 'FunctionExpression' ||
       expr.argument.callee.type === 'ArrowFunctionExpression')) {
    return true;
  }
  
  return false;
}

/**
 * Extract IIFE declarations
 * @param {Array} astBody - Array of AST nodes
 * @returns {Array} - Array of IIFE AST nodes
 */
function extractIIFE(astBody) {
  return astBody.filter(isIIFE);
}

/**
 * Extract variable declarations and their usage
 * @param {Array} astBody - Array of AST nodes
 * @returns {Object} - Object containing declarations and usage AST nodes
 */
function extractVariablesAndUsage(astBody) {
  const declarations = [];
  const usage = [];
  
  astBody.forEach(node => {
    if (node.type === 'VariableDeclaration' &&
        node.declarations.every(
          decl =>
            !decl.init ||
            (decl.init.type !== 'FunctionExpression' &&
             decl.init.type !== 'ArrowFunctionExpression')
        )) {
      declarations.push(node);
    }
    
    if (node.type === 'ExpressionStatement' &&
        node.expression.type === 'AssignmentExpression') {
      usage.push(node);
    }
  });
  
  return { declarations, usage };
}

/**
 * Extract global function declarations and expressions
 * @param {Array} astBody - Array of AST nodes
 * @returns {Array} - Array of method AST nodes
 */
function extractMethods(astBody) {
  const methods = [];
  
  astBody.forEach(node => {
    if (isIIFE(node)) return;
    
    if (node.type === 'FunctionDeclaration') {
      methods.push(node);
    } else if (node.type === 'VariableDeclaration') {
      node.declarations.forEach(decl => {
        if (decl.init && 
            (decl.init.type === 'FunctionExpression' ||
             decl.init.type === 'ArrowFunctionExpression')) {
          const funcDeclaration = {
            type: 'FunctionDeclaration',
            id: {
              type: 'Identifier',
              name: decl.id.name
            },
            params: decl.init.params,
            body: decl.init.body,
            generator: decl.init.generator || false,
            async: decl.init.async || false,
            expression: false,
          };
          methods.push(funcDeclaration);
        }
      });
    }
  });

  return methods;
}

/**
 * Extract global event listeners
 * @param {Array} astBody - Array of AST nodes
 * @returns {Array} - Array of event AST nodes
 */
function extractEvents(astBody) {
  const events = [];

  astBody.forEach(node => {
    if (
      node.type === 'ExpressionStatement' &&
      node.expression.type === 'CallExpression'
    ) {
      const callee = node.expression.callee;

      if (
        (callee.type === 'MemberExpression' &&
          callee.property &&
          ['addEventListener', 'on'].includes(callee.property.name)) ||
        (callee.type === 'Identifier' &&
          ['addEventListener', 'on'].includes(callee.name))
      ) {
        events.push(node);
      }
    }
  });

  return events;
}

/**
 * Extract global function calls
 * @param {Array} astBody - Array of AST nodes
 * @returns {Array} - Array of call AST nodes
 */
function extractCalls(astBody) {
  const calls = [];

  astBody.forEach(node => {
    if (
      node.type === 'ExpressionStatement' &&
      node.expression.type === 'CallExpression'
    ) {
      const callee = node.expression.callee;

      const isEventListener =
        (callee.type === 'MemberExpression' &&
          callee.property &&
          ['addEventListener', 'on'].includes(callee.property.name)) ||
        (callee.type === 'Identifier' &&
          ['addEventListener', 'on'].includes(callee.name));

      if (!isEventListener && !isIIFE(node)) {
        calls.push(node);
      }
    }
  });

  return calls;
}

/**
 * Main function to interpret the script AST
 * @param {Array} scriptAST - Parsed JavaScript AST body
 * @returns {Object} - Object containing categorized script AST nodes
 */
function interpretScript(scriptAST) {
  const { declarations, usage } = extractVariablesAndUsage(scriptAST);
  const methods = extractMethods(scriptAST);
  const events = extractEvents(scriptAST);
  const calls = extractCalls(scriptAST);
  const iife = extractIIFE(scriptAST);

  return {
    script: {
      variables: { declarations, usage },
      methods,
      events,
      calls,
      iife
    }
  };
}

module.exports = { interpretScript };
```

### cat\src\slicer.js

```javascript
/**
 * Slicer Module
 * 
 * This module extracts content from HTML files, slicing it into main, script, and style sections.
 */

/**
 * Extract wrappers from content using regex
 * @param {string} content - Raw HTML content
 * @returns {Array} - Array of wrapper objects
 */
function extractWrappers(content) {
  const wrapperRegex = /<(\w+(?:-?\w+)*)>([\s\S]*?)<\/\1>/g;
  return Array.from(content.matchAll(wrapperRegex), match => ({
    tag: match[1],
    content: match[2],
  }));
}

/**
 * Identify the main wrapper (not script or style)
 * @param {Array} wrappers - Array of wrapper objects
 * @returns {Object} - The main wrapper object
 */
function identifyMainWrapper(wrappers) {
  const mainWrappers = wrappers.filter(w => !['script', 'style'].includes(w.tag.toLowerCase()));
  if (mainWrappers.length !== 1) {
    throw new Error('Invalid structure. Expected exactly one main wrapper.');
  }
  return mainWrappers[0];
}

/**
 * Slice HTML content into structured parts
 * @param {string} file - Raw HTML content to slice
 * @returns {Object} - Sliced structure with type, tagName, body, script, and style
 */
function sliceContent(file) {

  const wrappers = extractWrappers(file.body);

  if (wrappers.length > 3) 
    throw new Error(`${file.file} :: Invalid structure. Found ${wrappers.length} wrappers, maximum allowed is 3.`);
  
  const mainWrapper = identifyMainWrapper(wrappers);
  const scriptWrapper = wrappers.find(w => w.tag.toLowerCase() === 'script');
  const styleWrapper = wrappers.find(w => w.tag.toLowerCase() === 'style');

  return {
    type: file.type,
    name: mainWrapper.tag,
    body: mainWrapper.content,
    script: scriptWrapper ? scriptWrapper.content : null,
    style: styleWrapper ? styleWrapper.content : null
  };
}

module.exports = { sliceContent };
```

### cat\src\sviewer.js

```javascript
/**
 * Script Viewer Module
 * 
 * This module takes the script object containing categorized AST nodes and generates
 * human-readable JavaScript code by converting the AST back into string code. This is
 * useful for debugging and verifying the transformations applied by the compiler.
 */

const escodegen = require('escodegen');

/**
 * Configuration for escodegen to produce clean, readable code
 */
const escodegenOptions = {
    format: {
        indent: {
            style: '  ',
            base: 0
        },
        newline: '\n',
        space: ' ',
        quotes: 'single'
    }
};

/**
 * Wraps a node in a complete AST structure if needed
 * @param {Object} node - AST node
 * @returns {Object} - Complete AST node
 */
function wrapNodeIfNeeded(node) {
    // If node is already a complete program, return as is
    if (node.type === 'Program') return node;

    // If node is an array of statements, wrap in program
    if (Array.isArray(node)) {
        return {
            type: 'Program',
            body: node,
            sourceType: 'script'
        };
    }

    // If single node, wrap in program and array
    return {
        type: 'Program',
        body: [node],
        sourceType: 'script'
    };
}

/**
 * Safely generates code from AST nodes
 * @param {Array|Object} nodes - AST node or array of nodes
 * @returns {string} - Generated JavaScript code
 */
function generateCodeFromAST(nodes) {
    if (!nodes) return '';
    
    try {
        if (Array.isArray(nodes)) {
            return nodes
                .map(node => {
                    if (!node) return '';
                    const wrappedNode = wrapNodeIfNeeded(node);
                    return escodegen.generate(wrappedNode, escodegenOptions)
                        .replace(/^"use strict";\s*/, ''); // Remove 'use strict' if present
                })
                .filter(code => code.trim()) // Remove empty lines
                .join('\n');
        } else {
            const wrappedNode = wrapNodeIfNeeded(nodes);
            return escodegen.generate(wrappedNode, escodegenOptions)
                .replace(/^"use strict";\s*/, '');
        }
    } catch (error) {
        console.error('Error generating code:', error);
        return '// Error generating code for this section';
    }
}

/**
 * Generates section code with header comment
 * @param {string} header - Section header
 * @param {Array|Object} nodes - AST nodes
 * @returns {string} - Formatted section code
 */
function generateSection(header, nodes) {
    if (!nodes || (Array.isArray(nodes) && nodes.length === 0)) return '';
    
    const code = generateCodeFromAST(nodes);
    if (!code.trim()) return '';

    return `// ${header}\n${code}\n\n`;
}

/**
 * Generates the full script code from the script object
 * @param {Object} script - Script object containing categorized AST nodes
 * @returns {string} - The complete JavaScript code as a string
 */
function generateScriptCode(script) {
    if (!script) return '// Empty script object';

    let code = '';

    // Variables Declarations
    if (script.variables) {
        code += generateSection('Variables Declarations', script.variables.declarations);
        code += generateSection('Variables Usage', script.variables.usage);
    }

    // Methods
    code += generateSection('Methods', script.methods);

    // Events
    code += generateSection('Events', script.events);

    // Function Calls
    code += generateSection('Function Calls', script.calls);

    // IIFEs
    code += generateSection('Immediately Invoked Function Expressions (IIFEs)', script.iife);

    return code.trim() + '\n';
}

/**
 * Main function to view the script object as JavaScript code
 * @param {Object} script - Script object containing categorized AST nodes
 * @returns {string} - The complete JavaScript code as a string
 */
function viewScript(script) {
    try {
        return generateScriptCode(script);
    } catch (error) {
        console.error('Error in viewScript:', error);
        return '// Error generating script view\n';
    }
}

module.exports = { viewScript };
```

### cat\src\transformer.js

```javascript
/**
 * HTML to JavaScript AST Transformer Module
 * 
 * This module transforms parsed HTML structure into JavaScript AST nodes
 * representing DOM manipulation code.
 */

const acorn = require('acorn');

function transformToJavaScript(parsedHTML) {
  let creationCode = ``;
  let mountCode = ``;
  let varCounter = 0;

  function generateVarName() {
    return `el_${varCounter++}`;
  }

  function escapeString(str) {
    return str.replace(/\\/g, `\\\\`).replace(/`/g, `\\\``).replace(/\n/g, `\\n`);
  }

  function hasBindings(content) {
    return content.includes('${this.');
  }

  function transformNode(node, parentVar) {
    let nodeCode = { creation: ``, mount: `` };
    const varName = generateVarName();

    if (node.type === `tag` && ![`style`, `script`].includes(node.name)) {
      nodeCode.creation += `this.${varName} = document.createElement(\`${node.name}\`);\n`;
      
      // Handle attributes
      Object.entries(node.attributes).forEach(([attr, value]) => {
        if (hasBindings(value)) {
          // If attribute has bindings, add to mount code
          nodeCode.mount += `this.${varName}.setAttribute(\`${attr}\`, \`${escapeString(value)}\`);\n`;
        } else {
          // If attribute is static, add to creation code
          nodeCode.creation += `this.${varName}.setAttribute(\`${attr}\`, \`${escapeString(value)}\`);\n`;
        }
      });

      // Process children
      node.children.forEach(child => {
        const childCode = transformNode(child, `this.${varName}`);
        nodeCode.creation += childCode.creation;
        nodeCode.mount += childCode.mount;
      });

    } else if (node.type === `text`) {
      const trimmedContent = node.content.trim();
      if (trimmedContent) {
        nodeCode.creation += `this.${varName} = document.createTextNode(\`\`);\n`;
        
        if (hasBindings(trimmedContent)) {
          // If text has bindings, add to mount code
          nodeCode.mount += `this.${varName}.nodeValue = \`${escapeString(trimmedContent)}\`;\n`;
        } else {
          // If text is static, set it during creation
          nodeCode.creation += `this.${varName}.nodeValue = \`${escapeString(trimmedContent)}\`;\n`;
        }

        if (parentVar) {
          nodeCode.creation += `${parentVar}.appendChild(this.${varName});\n`;
        }
      }
      return nodeCode;
    } else if (node.type === `comment`) {
      nodeCode.creation += `this.${varName} = document.createComment(\`${escapeString(node.data)}\`);\n`;
    } else {
      return nodeCode;
    }

    if (parentVar) {
      nodeCode.creation += `${parentVar}.appendChild(this.${varName});\n`;
    }

    return nodeCode;
  }

  // Initialize the fragment
  creationCode += `this.fragment = document.createDocumentFragment();\n\n`;

  // Transform all nodes
  parsedHTML.forEach(node => {
    const code = transformNode(node, `this.fragment`);
    creationCode += code.creation;
    mountCode += code.mount;
  });

  // Add return statement to creation code
  creationCode += `\nthis.fragment;`;

  // Parse both codes into AST
  const bodyAST = acorn.parse(creationCode.trim(), {
    ecmaVersion: 'latest',
    sourceType: 'script'
  });

  const mountAST = mountCode.trim() ? acorn.parse(mountCode.trim(), {
    ecmaVersion: 'latest',
    sourceType: 'script'
  }) : null;

  return { 
    body: bodyAST.body,
    mount: mountAST ? mountAST.body : null
  };
}

module.exports = { transformToJavaScript };
```

### cat\src\typeof.js

```javascript
/**
 * Determine the type of HTML file based on its name
 * @param {string} fileName - Name of the HTML file
 * @returns {string} - Type of the file ('component', 'page', or 'other')
 */
function determineFileType(fileName) {
  if (fileName.endsWith('.comp.html')) {
    return 'component';
  } else if (fileName.endsWith('.page.html')) {
    return 'page';
  } else {
    return 'other';
  }
}

module.exports = { determineFileType };
```

### cat\src\wirer.js

```javascript
/**
 * Wirer Module
 * 
 * Transforms JavaScript AST nodes to work within a Custom Element class context
 * by adding appropriate 'this' references and maintaining proper scoping.
 */

/**
 * Checks if an identifier should be bound to class context
 * @param {Set} identifiers - Set of known class-level identifiers
 * @param {string} name - Identifier name to check
 * @returns {boolean}
 */
function shouldBindToThis(identifiers, name) {
  return identifiers.has(name);
}

/**
 * Transforms variable declarations to class property assignments
 * @param {Array} declarations - Array of variable declaration nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireVariableDeclarations(declarations, identifiers) {
  return declarations.map(node => {
    if (node.type === 'VariableDeclaration') {
      return {
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          operator: '=',
          left: {
            type: 'MemberExpression',
            object: { type: 'ThisExpression' },
            property: { type: 'Identifier', name: node.declarations[0].id.name },
            computed: false
          },
          right: transformNode(node.declarations[0].init, identifiers) || { type: 'Literal', value: undefined }
        }
      };
    }
    return node;
  });
}

/**
 * Recursively transforms AST nodes to use class context
 * @param {Object} node - AST node
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Object} - Transformed node
 */
function transformNode(node, identifiers) {
  if (!node || typeof node !== 'object') return node;

  // Transform identifiers to this.identifier only if they're in our scope
  if (node.type === 'Identifier' && shouldBindToThis(identifiers, node.name)) {
    return {
      type: 'MemberExpression',
      object: { type: 'ThisExpression' },
      property: { type: 'Identifier', name: node.name },
      computed: false
    };
  }

  // Recursively transform all properties
  for (const key in node) {
    if (Array.isArray(node[key])) {
      node[key] = node[key].map(item => transformNode(item, identifiers));
    } else if (typeof node[key] === 'object' && node[key] !== null) {
      node[key] = transformNode(node[key], identifiers);
    }
  }

  return node;
}

/**
 * Transforms variable usage/assignments to use class properties
 * @param {Array} usage - Array of usage/assignment nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireVariableUsage(usage, identifiers) {
  return usage.map(node => transformNode(node, identifiers));
}

/**
 * Transforms method bodies to use class context
 * @param {Array} methods - Array of method nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireMethods(methods, identifiers) {
  return methods.map(node => {
    // Preserve the method name and parameters
    const methodNode = { ...node };
    // Transform only the method body
    methodNode.body = transformNode(methodNode.body, identifiers);
    return methodNode;
  });
}

/**
 * Transforms event listeners to use class context
 * @param {Array} events - Array of event listener nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireEvents(events, identifiers) {
  return events.map(node => {
    if (node.expression?.type === 'CallExpression') {
      // Transform addEventListener to use this context
      node.expression.callee = {
        type: 'MemberExpression',
        object: { type: 'ThisExpression' },
        property: node.expression.callee.property || node.expression.callee,
        computed: false
      };

      // Transform handler and any additional arguments
      node.expression.arguments = node.expression.arguments.map(arg => 
        transformNode(arg, identifiers)
      );
    }
    return node;
  });
}

/**
 * Transforms function calls to use class context
 * @param {Array} calls - Array of call nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireCalls(calls, identifiers) {
  return calls.map(node => {
    if (node.expression?.type === 'CallExpression') {
      // Transform the entire call expression including callee and arguments
      return transformNode(node, identifiers);
    }
    return node;
  });
}

/**
 * Transforms IIFEs to use class context
 * @param {Array} iife - Array of IIFE nodes
 * @param {Set} identifiers - Set of class-level identifiers
 * @returns {Array} - Transformed nodes
 */
function wireIIFE(iife, identifiers) {
  return iife.map(node => {
    if (node.expression?.type === 'CallExpression') {
      // Transform the IIFE body
      const iifeFn = node.expression.callee;
      
      // Transform the function body regardless of how it's wrapped
      const fnNode = iifeFn.type === 'FunctionExpression' ? 
                    iifeFn : 
                    iifeFn.type === 'ParenthesizedExpression' ? 
                    iifeFn.expression : null;
      
      if (fnNode) {
        // Transform the function body
        fnNode.body = transformNode(fnNode.body, identifiers);
        
        // Transform the call itself to use .call(this)
        return {
          type: 'ExpressionStatement',
          expression: {
            type: 'CallExpression',
            callee: {
              type: 'MemberExpression',
              object: iifeFn.type === 'ParenthesizedExpression' ?
                      { type: 'ParenthesizedExpression', expression: fnNode } :
                      fnNode,
              property: {
                type: 'Identifier',
                name: 'call'
              },
              computed: false
            },
            arguments: [
              { type: 'ThisExpression' }
            ]
          }
        };
      }
    }
    return node;
  });
}

/**
 * Main function to wire all script components
 * @param {Object} script - Categorized script object
 * @returns {Object} - Transformed script object
 */
function wire(script) {
  // Collect all identifiers that need to be bound to 'this'
  const identifiers = new Set();
  
  // Add variables to identifiers set
  script.variables.declarations.forEach(node => {
    if (node.type === 'VariableDeclaration') {
      node.declarations.forEach(decl => {
        identifiers.add(decl.id.name);
      });
    }
  });

  // Add methods to identifiers set
  script.methods.forEach(node => {
    identifiers.add(node.id.name);
  });

  // Transform each category
  return {
    script: {
      variables: {
        declarations: wireVariableDeclarations(script.variables.declarations, identifiers),
        usage: wireVariableUsage(script.variables.usage, identifiers)
      },
      methods: wireMethods(script.methods, identifiers),
      events: wireEvents(script.events, identifiers),
      calls: wireCalls(script.calls, identifiers),
      iife: wireIIFE(script.iife, identifiers)
    }
  };
}

module.exports = { wire };
```



Our next step it's developing a new module `reactive.js` which it's going to be on charge of creating the `getters` and `setters` for the reactive values. 

Which are reactive values? 
Every variable, object, or nested key inside an object that starts by `$`, sample `$value`. 

What our module it's going to do?
It's going to create the `get` and `set` for each one of these declared objects, but it's going to be automatically or not based on this criteria:
- If the variable it's a bind to the DOM, our module it's going to find inside the `references` object, and look for the cached node. Then for the node where our bind exist, it's going to create a function that manipulate it, for updating the data of our bind, weather it's a text node, or a value of an attribute. 

Bind Sample
```
<test-comp>
    <h1> { $name } </h1>
</test-comp>

<script>
    let $name = 'hello world';
</script>
```

- If our reactive object it's not a bind to the DOM, then we are going to declare what it's going to happen when it's value change, but this is for later, let's focus on the first case for now. (NOT NOW)

IMPORTANT:
- Not all the bindings are reactives, and not all the reactives values are bind to the DOM.
- Right now we are focusing on the ones bind to the DOM.
- The `get` and `set` methods are going to be placed later into the Custom Element Class, so return an object that we can iterate.