<system>
You are a Senior Software Engineer.
</system>

<context>
<code>
```
// cat/src/compiler.js

const fs = require('fs-extra');
const path = require('path');
const glob = require('glob');
const {
  parseComponent,
  generateComponentClassCode,
} = require('./component');
const {
  parsePageComponent,
  generatePageClassCode,
  generateRouterClassCode,
} = require('./page');
const { parseScript } = require('./scripter');

/**
 * Detect used components in the provided HTML contents by parsing the HTML tags.
 * @param {Array<string>} htmlContents - Array of HTML file contents.
 * @param {Set<string>} availableComponents - Set of all available component tag names.
 * @returns {Set<string>} - Set of used component tag names.
 */
function detectUsedComponents(htmlContents, availableComponents) {
  const usedComponents = new Set();

  // Regex to match all tags in the HTML
  const tagRegex = /<\s*([a-zA-Z][a-zA-Z0-9-]*)\b[^>]*>/g;

  htmlContents.forEach(content => {
    let match;
    while ((match = tagRegex.exec(content)) !== null) {
      let tag = match[1];
      if (availableComponents.has(tag)) {
        usedComponents.add(tag);
      }
    }
  });

  return usedComponents;
}

/**
 * Generate the registration script for the components and pages.
 * @param {Map<string, string>} classes - Map of className or tagName to compiled class code.
 * @returns {string} - JavaScript code for registering components and pages.
 */
function generateRegistrationScript(classes) {
  let script = '';

  classes.forEach((classCode) => {
    script += `
${classCode}
    `;
  });

  return script;
}

/**
 * Compiler Function
 * @param {string} indexPath - Path to the index.html file.
 * @returns {Promise<string>} - Compiled HTML content with component registrations and page injections.
 */
async function compile(indexPath) {
  // Read the index.html content
  let indexContent = await fs.readFile(indexPath, 'utf-8');

  // Define project root
  const projectRoot = path.dirname(indexPath);

  // Initialize style accumulator
  let accumulatedStyles = '';

  // -----------------------
  // Step 1: Process Components
  // -----------------------

  // Find all .comp.html files in the project directory
  const compFiles = glob.sync('**/*.comp.html', {
    cwd: projectRoot,
    absolute: true,
    ignore: ['node_modules/**', 'cat/**'] // Ignore node_modules and cat directory to prevent recursion
  });

  const componentMap = new Map(); // Map of tagName to compiled class code
  const parsedComponents = new Set(); // To track parsed components

  // Parse and compile each component file
  for (const file of compFiles) {
    try {
      const { tagName, html, script, style } = await parseComponent(file);

      if (!parsedComponents.has(tagName)) {
        // Parse script to extract properties and methods
        const { properties, methods } = parseScript(script);

        // Generate class code
        const classCode = generateComponentClassCode({
          tagName,
          html,
          style,
          properties,
          methods,
        });

        componentMap.set(tagName, classCode);
        parsedComponents.add(tagName);

        // Accumulate styles
        if (style && style.trim()) {
          accumulatedStyles += `\n/* Styles for component: ${tagName} */\n${style}`;
        }

        console.log(`🔍 Parsed and compiled component: <${tagName}> from ${path.relative(projectRoot, file)}`);
      } else {
        console.log(`ℹ️  Component <${tagName}> from ${path.relative(projectRoot, file)} has already been parsed.`);
      }
    } catch (error) {
      console.error(`❌ Failed to parse ${file}: ${error.message}`);
    }
  }

  if (componentMap.size === 0) {
    console.warn('⚠️  No components found to compile.');
  }

  // -----------------------
  // Step 2: Process Pages
  // -----------------------

  // Find all .page.html files in the project directory
  const pageFiles = glob.sync('**/*.page.html', {
    cwd: projectRoot,
    absolute: true,
    ignore: ['node_modules/**', 'cat/**']
  });

  const pageClassMap = new Map(); // Map of page class name to compiled class code
  const pageRouteMap = new Map(); // Map of route to page class name
  let pageCounter = 0;

  for (const file of pageFiles) {
    try {
      // Parse the page component
      const { route, html, script, style } = await parsePageComponent(file);

      // Generate a unique class name using the convention _page{number}
      pageCounter++;
      const className = `_page${pageCounter}`;

      // Parse script to extract properties and methods
      const { properties, methods } = parseScript(script);

      // Generate class code
      const classCode = generatePageClassCode({
        className,
        html,
        style,
        properties,
        methods,
      });

      pageClassMap.set(className, classCode);
      pageRouteMap.set(route, className);

      // Accumulate styles
      if (style && style.trim()) {
        accumulatedStyles += `\n/* Styles for page: ${route} */\n${style}`;
      }

      console.log(`📄 Parsed and compiled page: ${className} for route "${route}" from ${path.relative(projectRoot, file)}`);
    } catch (error) {
      console.error(`❌ Failed to parse page ${file}: ${error.message}`);
    }
  }

  if (pageClassMap.size === 0) {
    console.warn('⚠️  No pages found to compile.');
  }

  // -----------------------
  // Step 3: Detect Used Components
  // -----------------------

  // Find all .html files in the project directory for usage detection
  const htmlFiles = glob.sync('**/*.html', {
    cwd: projectRoot,
    absolute: true,
    ignore: ['node_modules/**', 'cat/**']
  });

  const htmlContents = [];
  for (const file of htmlFiles) {
    try {
      const content = await fs.readFile(file, 'utf-8');
      htmlContents.push(content);
    } catch (error) {
      console.error(`❌ Failed to read HTML file ${file}: ${error.message}`);
    }
  }

  // Detect which components are used across all HTML files
  const availableComponents = new Set(componentMap.keys());
  const usedComponents = detectUsedComponents(htmlContents, availableComponents);

  if (usedComponents.size === 0) {
    console.warn('⚠️  No used components found in HTML files.');
  } else {
    console.log(`📦 Used components: ${[...usedComponents].join(', ')}`);
  }

  // -----------------------
  // Step 4: Verify <load> Routes
  // -----------------------

  // Detect all <load> routes in indexContent
  const loadTagRegex = /<load\s+[^>]*route=["']([^"']+)["'][^>]*>/gi;
  let loadRoutes = [];
  let match;
  while ((match = loadTagRegex.exec(indexContent)) !== null) {
    const route = match[1];
    loadRoutes.push(route);
  }

  // Verify that each load route exists in the pageRouteMap
  loadRoutes.forEach(route => {
    if (!pageRouteMap.has(route)) {
      console.error(`❌ No page found for route "${route}". Please ensure a .page.html file exists with route="${route}".`);
    }
  });

  // -----------------------
  // Step 5: Generate Registration Script
  // -----------------------

  // Combine components and pages into one map
  const combinedClasses = new Map();

  // Add component classes
  usedComponents.forEach(tag => {
    combinedClasses.set(tag, componentMap.get(tag));
  });

  // Add page classes
  pageClassMap.forEach((classCode, className) => {
    combinedClasses.set(className, classCode);
  });

  // Generate the Router class code
  const routeClassNames = [];
  pageRouteMap.forEach((className, route) => {
    routeClassNames.push({ route, className });
  });
  const routerClassCode = generateRouterClassCode(routeClassNames);

  // Generate the registration script
  const registrationScript = generateRegistrationScript(combinedClasses);
  const fullScript = `
${registrationScript}
${routerClassCode}
`;

  // -----------------------
  // Step 6: Inject Styles and Registration Script
  // -----------------------

  // Inject the accumulated styles into the <head> tag
  if (accumulatedStyles.trim()) {
    const styleTag = `<style>
${accumulatedStyles}
</style>
`;

    // Check if <head> exists
    if (indexContent.includes('</head>')) {
      indexContent = indexContent.replace('</head>', `${styleTag}</head>`);
    } else {
      // If no </head>, check for <html> tag to insert after
      if (indexContent.includes('<html')) {
        indexContent = indexContent.replace(/<html[^>]*>/, `$&\n<head>\n${styleTag}\n</head>`);
      } else {
        // If no <html> tag, prepend the style tag
        indexContent = `<head>\n${styleTag}\n</head>\n${indexContent}`;
      }
    }
    console.log('🎨 Injected accumulated styles into <head>');
  }

  // Inject the registration script before the closing </body> tag
  if (fullScript.trim()) {
    const scriptTag = `<script>
${fullScript}
</script>
`;

    if (indexContent.includes('</body>')) {
      indexContent = indexContent.replace('</body>', `${scriptTag}</body>`);
    } else {
      // If no </body> tag, append the script at the end
      indexContent += `\n${scriptTag}`;
    }
    console.log('📝 Injected component and page registration scripts.');
  }

  // -----------------------
  // Step 7: Return Compiled Content
  // -----------------------

  return indexContent;
}

module.exports = { compile };

// cat/src/scripter.js

const acorn = require('acorn'); // Import Acorn for JavaScript parsing
const { parseDocument } = require('htmlparser2');

/**
 * Parse the script content to extract properties and methods.
 * @param {string} script - The script content.
 * @returns {{ properties: Array, methods: Array }} - Parsed properties and methods.
 */
function parseScript(script) {
  const properties = [];
  const methods = [];

  try {
    // Parse the script content into an AST
    const ast = acorn.parse(script, { ecmaVersion: 2020, locations: true });

    ast.body.forEach(node => {
      if (node.type === 'VariableDeclaration') {
        node.declarations.forEach(declarator => {
          if (declarator.id.type === 'Identifier') {
            const varName = declarator.id.name;
            const varValue = script.substring(declarator.init.start, declarator.init.end);
            properties.push({ name: varName, value: varValue });
          }
        });
      } else if (node.type === 'FunctionDeclaration') {
        const funcName = node.id.name;
        const params = node.params.map(param => script.substring(param.start, param.end)).join(', ');
        const body = script.substring(node.body.start, node.body.end);
        methods.push({ name: funcName, params, body });
      }
    });
  } catch (error) {
    console.error(`Error parsing script: ${error.message}`);
  }

  return { properties, methods };
}

/**
 * Transform method body to replace variable references with 'this.' prefix.
 * @param {string} body - The method body.
 * @param {Array<string>} propNames - The property names to replace.
 * @returns {string} - The transformed method body.
 */
function transformMethodBody(body, propNames) {
  let transformedBody = body;

  propNames.forEach(propName => {
    // Replace assignments like 'propName = value;' with 'this.propName = value;'
    const assignRegex = new RegExp(`([^\\.\\w$])${propName}\\s*=`, 'g');
    transformedBody = transformedBody.replace(assignRegex, `$1this.${propName} =`);

    // Replace variable references with 'this.propName'
    const varRegex = new RegExp(`([^\\.\\w$])${propName}([^\\w$])`, 'g');
    transformedBody = transformedBody.replace(varRegex, `$1this.${propName}$2`);
  });

  // Ensure braces are correctly balanced and formatted
  transformedBody = transformedBody.trim();

  // Remove extra outer braces if they exist
  if (transformedBody.startsWith('{') && transformedBody.endsWith('}')) {
    transformedBody = transformedBody.slice(1, -1).trim();
  }

  // Properly indent the method body
  transformedBody = transformedBody
    .split('\n')
    .map(line => '    ' + line.trim())
    .join('\n');

  return transformedBody;
}

/**
 * Sanitize a string to be a valid JavaScript variable name.
 * @param {string} name - The original name.
 * @returns {string} - The sanitized name.
 */
function sanitizeVarName(name) {
  // Replace invalid characters with underscores
  return name.replace(/[^a-zA-Z0-9_$]/g, '_');
}

/**
 * Generate DOM creation code from HTML using htmlparser2.
 * @param {string} html - The inner HTML string of the component or page.
 * @returns {object} - Object containing generated code, cached nodes, and event listeners.
 */
function generateDOMCode(html) {
  const dom = parseDocument(html).children; // Array of DOM nodes

  let code = '';
  let varCounter = 0;
  const cachedNodes = {}; // For properties to nodes
  const eventListeners = [];

  function traverse(node, parentVarName) {
    if (node.type === 'tag') {
      const safeName = sanitizeVarName(node.name);
      const varName = safeName + ++varCounter;

      // Decide whether to assign to 'this.' or 'const'
      let declaration;
      if (needsReference(node)) {
        declaration = `this.${varName}`;
      } else {
        declaration = `const ${varName}`;
      }

      const varReference = declaration.replace(/^const /, '');
      code += `    ${declaration} = document.createElement('${node.name}');
    `;

      // Handle attributes
      const attribs = node.attribs || {};
      for (let [attrName, attrValue] of Object.entries(attribs)) {
        if (attrName === 'class' || attrName === 'style' || attrName.startsWith('data-') || attrName === 'id' || attrName === 'src' || attrName === 'alt') {
          // Handle attributes with embedded expressions
          const { expression, propNames } = generateAttributeExpression(attrValue);
          code += `    ${varReference}.setAttribute('${attrName}', ${expression});
    `;

          // Cache nodes for reactive updates
          propNames.forEach(propName => {
            if (!cachedNodes[propName]) cachedNodes[propName] = [];
            cachedNodes[propName].push({
              type: 'attribute',
              elementVarName: varReference.replace(/^this\./, ''),
              attrName: attrName,
              expression: generateAttributeExpression(attrValue).expression,
            });
          });
        } else if (attrName.startsWith('on')) {
          // Event listener
          const event = attrName.substring(2);
          const handlerName = attrValue.replace(/\(\)$/, '').trim();
          eventListeners.push({ elementVarName: varReference.replace(/^this\./, ''), event, handlerName });
        } else {
          // For other attributes
          code += `    ${varReference}.setAttribute('${attrName}', '${attrValue}');
    `;
        }
      }

      // Append to parent
      const parentRef = parentVarName ? parentVarName : 'fragment';
      code += `    ${parentRef}.appendChild(${varReference});
    `;

      // Traverse children
      if (node.children && node.children.length) {
        for (let child of node.children) {
          traverse(child, varReference);
        }
      }
    } else if (node.type === 'text') {
      const textContent = node.data;

      if (textContent.trim()) {
        // Handle text nodes with expressions
        const { expression, propNames } = generateTextExpression(textContent);

        const varName = 'textNode' + ++varCounter;

        // Decide whether to assign to 'this.' or 'const'
        let declaration;
        if (expression.includes('this._')) {
          declaration = `this.${varName}`;
        } else {
          declaration = `const ${varName}`;
        }

        const varReference = declaration.replace(/^const /, '');
        code += `    ${declaration} = document.createTextNode(${expression});
    `;
        code += `    ${parentVarName}.appendChild(${varReference});
    `;

        // Cache nodes for reactive updates
        propNames.forEach(propName => {
          if (!cachedNodes[propName]) cachedNodes[propName] = [];
          cachedNodes[propName].push({
            type: 'text',
            varName: varReference.replace(/^this\./, ''),
            expression: generateTextExpression(textContent).expression,
          });
        });
      }
    }
  }

  function needsReference(node) {
    // Determines if the element needs to be assigned to 'this.'
    // Elements that are:
    // - Targets of event listeners
    // - Contain reactive expressions
    // Need to be accessible outside of _buildDOM
    if (node.attribs) {
      const hasEventListener = Object.keys(node.attribs).some(attr => attr.startsWith('on'));
      const hasReactiveAttr = Object.values(node.attribs).some(value => /\{([\w$]+)\}/.test(value));
      if (hasEventListener || hasReactiveAttr) {
        return true;
      }
    }

    if (node.children && node.children.some(child => child.type === 'text' && /\{([\w$]+)\}/.test(child.data))) {
      return true;
    }

    return false;
  }

  function generateTextExpression(textContent) {
    const exprRegex = /\{([\w$]+)\}/g;
    let segments = [];
    let propNames = [];
    let lastIndex = 0;
    let match;

    while ((match = exprRegex.exec(textContent)) !== null) {
      if (match.index > lastIndex) {
        segments.push(JSON.stringify(textContent.slice(lastIndex, match.index)));
      }
      segments.push(`this._${match[1]}`);
      propNames.push(match[1]);
      lastIndex = exprRegex.lastIndex;
    }

    if (lastIndex < textContent.length) {
      segments.push(JSON.stringify(textContent.slice(lastIndex)));
    }

    return {
      expression: segments.join(' + '),
      propNames,
    };
  }

  function generateAttributeExpression(attrValue) {
    const exprRegex = /\{([\w$]+)\}/g;
    let segments = [];
    let propNames = [];
    let lastIndex = 0;
    let match;

    while ((match = exprRegex.exec(attrValue)) !== null) {
      if (match.index > lastIndex) {
        segments.push(JSON.stringify(attrValue.slice(lastIndex, match.index)));
      }
      segments.push(`this._${match[1]}`);
      propNames.push(match[1]);
      lastIndex = exprRegex.lastIndex;
    }

    if (lastIndex < attrValue.length) {
      segments.push(JSON.stringify(attrValue.slice(lastIndex)));
    }

    return {
      expression: segments.join(' + '),
      propNames,
    };
  }

  dom.forEach(node => traverse(node, null));

  return { code, cachedNodes, eventListeners };
}

/**
 * Generate the class body code for components and pages.
 * @param {object} options - Options for class body generation.
 * @returns {string} - The class body code.
 */
function generateClassBodyCode({ properties, methods, domCode, cachedNodes, eventListeners, isComponent, parentClass }) {
  let classBody = '';

  // Constructor
  classBody += `  constructor() {
    `;

  // Include super() call if there is a parent class
  if (parentClass) {
    classBody += `    super();
    `;
  }

  // Initialize properties
  properties.forEach(prop => {
    classBody += `    this._${prop.name} = ${prop.value};
    `;
  });

  // For components, do not build DOM in constructor
  if (!isComponent) {
    // For pages, build DOM in constructor
    classBody += `
    this._buildDOM();
    `;
  }

  classBody += `  }

    _buildDOM() {
      const fragment = document.createDocumentFragment();
  `;

  // Include DOM creation code
  classBody += domCode;

  if (isComponent) {
    classBody += `
      this._fragment = fragment;
    `;
  } else {
    classBody += `
      this.rootElement = fragment;
    `;
  }

  // Close _buildDOM
  classBody += `  }
  `;

  // connectedCallback
  classBody += `
    connectedCallback() {
  `;

  if (isComponent) {
    classBody += `    this._buildDOM();
      this.appendChild(this._fragment);
    `;
  }

  // Attach event listeners
  if (eventListeners && eventListeners.length > 0) {
    eventListeners.forEach(listener => {
      classBody += `    this.${listener.elementVarName}.addEventListener('${listener.event}', this.${listener.handlerName}.bind(this));
    `;
    });
  }
  classBody += `  }

    disconnectedCallback() {
  `;
  // Remove event listeners
  if (eventListeners && eventListeners.length > 0) {
    eventListeners.forEach(listener => {
      classBody += `    this.${listener.elementVarName}.removeEventListener('${listener.event}', this.${listener.handlerName}.bind(this));
    `;
    });
  }
  classBody += `  }
  `;

  // Generate getters and setters
  Object.keys(cachedNodes).forEach(propName => {
    const nodes = cachedNodes[propName];

    classBody += `
    get ${propName}() { return this._${propName}; }
    set ${propName}(value) {
      if (this._${propName} !== value) {
        this._${propName} = value;
  `;
    nodes.forEach(node => {
      if (node.type === 'text') {
        classBody += `        this.${node.varName}.textContent = ${node.expression};
  `;
      } else if (node.type === 'attribute') {
        classBody += `        this.${node.elementVarName}.setAttribute('${node.attrName}', ${node.expression});
  `;
      }
    });
    classBody += `      }
    }
  `;
  });

  // Add methods
  methods.forEach(method => {
    const transformedBody = transformMethodBody(method.body, properties.map(p => p.name));
    classBody += `
    ${method.name}(${method.params}) {
  ${transformedBody}
    }
  `;
  });

  return classBody;
}

module.exports = {
  parseScript,
  transformMethodBody,
  generateDOMCode,
  generateClassBodyCode,
};

// cat/src/component.js

const fs = require('fs-extra');
const path = require('path');
const {
  parseScript,
  generateDOMCode,
  generateClassBodyCode,
} = require('./scripter');

/**
 * Parse a component file to extract tagName, HTML, script, and style sections.
 * @param {string} filePath - Path to the .comp.html file.
 * @returns {Promise<{ tagName: string, html: string, script: string, style: string }>} - Component details.
 */
async function parseComponent(filePath) {
  const content = await fs.readFile(filePath, 'utf-8');

  // Extract the outermost tag name and inner HTML
  const componentRegex = /<([\w-]+)>([\s\S]*?)<\/\1>/;
  const componentMatch = content.match(componentRegex);

  if (!componentMatch) {
    throw new Error(`Invalid component structure in ${path.basename(filePath)}`);
  }

  const tagName = componentMatch[1];
  let innerContent = componentMatch[2];

  // Extract all <script> sections
  const scriptRegex = /<script>([\s\S]*?)<\/script>/g;
  let scriptContent = '';
  let scriptMatch;
  while ((scriptMatch = scriptRegex.exec(content)) !== null) {
    scriptContent += scriptMatch[1].trim() + '\n';
  }

  // Extract all <style> sections
  const styleRegex = /<style>([\s\S]*?)<\/style>/g;
  let styleContent = '';
  let styleMatch;
  while ((styleMatch = styleRegex.exec(content)) !== null) {
    styleContent += styleMatch[1].trim() + '\n';
  }

  // Remove all <script> and <style> tags from innerContent
  innerContent = innerContent
    .replace(scriptRegex, '')
    .replace(styleRegex, '')
    .trim();

  return {
    tagName,
    html: innerContent,
    script: scriptContent,
    style: styleContent,
  };
}

/**
 * Convert a kebab-case or other tag name to PascalCase for class naming.
 * @param {string} tagName - The custom element tag name.
 * @returns {string} - PascalCase string.
 */
function toPascalCase(tagName) {
  return tagName
    .split('-')
    .map(word => word.charAt(0).toUpperCase() + word.slice(1))
    .join('');
}

/**
 * Generate the class code for the component.
 * @param {object} component - Component details.
 * @returns {string} - The compiled class code.
 */
function generateComponentClassCode({ tagName, html, style, properties, methods }) {
  const className = toPascalCase(tagName);

  // Generate DOM code
  const { code: domCode, cachedNodes, eventListeners } = generateDOMCode(html);

  // Generate class body
  const classBody = generateClassBodyCode({
    properties,
    methods,
    domCode,
    cachedNodes,
    eventListeners,
    isComponent: true,
    parentClass: 'HTMLElement', // Specify parent class
  });

  // Assemble the full class code
  let classCode = `class ${className} extends HTMLElement {
${classBody}
}

customElements.define('${tagName}', ${className});
`;

  return classCode;
}

module.exports = {
  parseComponent,
  generateComponentClassCode,
};

// cat/src/page.js

const fs = require('fs-extra');
const path = require('path');
const {
  parseScript,
  generateDOMCode,
  generateClassBodyCode,
} = require('./scripter');

/**
 * Parse a page component file to extract route, HTML, script, and style sections.
 * @param {string} filePath - Path to the .page.html file.
 * @returns {Promise<{ route: string, html: string, script: string, style: string }>} - Page details.
 */
async function parsePageComponent(filePath) {
  const content = await fs.readFile(filePath, 'utf-8');

  // Extract the <page> tag with route attribute
  const pageTagRegex = /<page\s+[^>]*route=["']([^"']+)["'][^>]*>([\s\S]*?)<\/page>/i;
  const match = content.match(pageTagRegex);

  if (!match) {
    throw new Error(`No valid <page> tag with 'route' attribute found in ${path.basename(filePath)}`);
  }

  const route = match[1];
  let innerContent = match[2];

  // Extract all <script> sections from the entire content
  const scriptRegex = /<script>([\s\S]*?)<\/script>/g;
  let scriptContent = '';
  let scriptMatch;
  while ((scriptMatch = scriptRegex.exec(content)) !== null) {
    scriptContent += scriptMatch[1].trim() + '\n';
  }

  // Extract all <style> sections from the entire content
  const styleRegex = /<style>([\s\S]*?)<\/style>/g;
  let styleContent = '';
  let styleMatch;
  while ((styleMatch = styleRegex.exec(content)) !== null) {
    styleContent += styleMatch[1].trim() + '\n';
  }

  // Remove all <script> and <style> tags from innerContent
  innerContent = innerContent
    .replace(scriptRegex, '')
    .replace(styleRegex, '')
    .trim();

  return {
    route,
    html: innerContent,
    script: scriptContent,
    style: styleContent,
  };
}

/**
 * Generate the class code for the page.
 * @param {object} page - Page details.
 * @returns {string} - The compiled class code.
 */
function generatePageClassCode({ className, html, style, properties, methods }) {
  // Generate DOM code
  const { code: domCode, cachedNodes, eventListeners } = generateDOMCode(html);

  // Generate class body
  const classBody = generateClassBodyCode({
    properties,
    methods,
    domCode,
    cachedNodes,
    eventListeners,
    isComponent: false,
    parentClass: null, // Pages do not extend any class
  });

  // Assemble the full class code
  let classCode = `class ${className} {
${classBody}
}
`;

  return classCode;
}

/**
 * Create the Router class code.
 * @param {Array<{route: string, className: string}>} routeClassNames - Array of route and corresponding page class names.
 * @returns {string} - The Router class code.
 */
function generateRouterClassCode(routeClassNames) {
  let code = `
class Router {
  static init() {
    document.querySelectorAll('load[route]').forEach(async (loadElement) => {
      const route = loadElement.getAttribute('route');
      const pageClass = Router.routes[route];
      if (pageClass) {
        const page = new pageClass();
        if (typeof page.connectedCallback === 'function') {
          page.connectedCallback();
        }
        while (loadElement.firstChild) {
          loadElement.removeChild(loadElement.firstChild);
        }
        loadElement.appendChild(page.rootElement);
      } else {
        console.error('No page found for route:', route);
      }
    });
  }
}

Router.routes = {
`;
  routeClassNames.forEach(({ route, className }) => {
    code += `  '${route}': ${className},
`;
  });
  code += `};

window.addEventListener('DOMContentLoaded', () => {
  Router.init();
});
`;

  return code;
}

module.exports = {
  parsePageComponent,
  generatePageClassCode,
  generateRouterClassCode,
};
```
</code>
<context>

<instructions>
<issue>
The `connectedCallback()` and `disconnectedCallback()` lifecycle hooks are specific to custom elements in web components and do not work for regular JavaScript classes. These callbacks are part of the Web Components specification and are only available for classes that extend `HTMLElement` to create custom elements.
</issue>
<task>
Determine weather if is convenient compile `page.html` files as Custom Elements, instead of vanilla Class. Do a depth analysis about the browser runtime for understanding of the implications of both cases, and contrast it against use cases and edge-cases. 
</task>
</instructions>

<CoT>
In your internal dialogue, it’s essential to take notes and monitor your thought process as you reason through ideas. This practice will help you stay focused and prevent you from straying off topic or experiencing distractions. Your note-taking system should capture your initial plans, insights gained during the process, test results, and reflections for your future self. The effectiveness of your reasoning is directly tied to the quality of your self-notes.
</CoT>