project-root/
├── cat/
│   ├── bin/
│   │   └── cat.js
│   └── src/
│       └── compiler.js
├── index.html
├── package.json
└── cat.config.json

// cat/src/compiler.js

const fs = require('fs-extra');
const path = require('path');
const glob = require('glob');

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

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

  // For each component file, inject its content into index.html
  for (const file of compFiles) {
    const componentName = path.basename(file, '.comp.html');
    const componentContent = await fs.readFile(file, 'utf-8');

    // Define a placeholder in index.html where the component should be injected
    // For example: <!-- inject:componentName -->
    const placeholder = `<!-- inject:${componentName} -->`;

    if (indexContent.includes(placeholder)) {
      // Replace placeholder with component content
      indexContent = indexContent.replace(placeholder, componentContent);
    } else {
      // If no placeholder found, append the component at the end
      indexContent += `\n<!-- Component: ${componentName} -->\n${componentContent}`;
    }
  }

  return indexContent;
}

module.exports = { compile };

#!/usr/bin/env node

const { program } = require('commander');
const path = require('path');
const fs = require('fs-extra');
const compiler = require('../src/compiler');
const express = require('express');

/**
 * Initialize the package.json and cat.config.json
 */
function initializeProject() {
  const projectRoot = process.cwd();
  const packageJsonPath = path.join(projectRoot, 'package.json');
  const configPath = path.join(projectRoot, 'cat.config.json');

  // Initialize package.json if it doesn't exist
  if (!fs.existsSync(packageJsonPath)) {
    const defaultPackageJson = {
      name: path.basename(projectRoot),
      version: "1.0.0",
      description: "A project using the Cat framework.",
      main: "index.html",
      scripts: {
        cat: "node ./cat/bin/cat.js"
      },
      dependencies: {
        "commander": "^10.0.0",
        "express": "^4.18.2",
        "fs-extra": "^11.1.1",
        "glob": "^10.3.3"
      },
      author: "Your Name",
      license: "MIT"
    };
    fs.writeJsonSync(packageJsonPath, defaultPackageJson, { spaces: 2 });
    console.log('✅ package.json has been created at the project root.');
    console.log('👉 Please run "npm install" to install the dependencies.');
  } else {
    console.log('ℹ️  package.json already exists.');
  }

  // Initialize cat.config.json if it doesn't exist
  if (!fs.existsSync(configPath)) {
    const defaultConfig = {
      root: 'index.html'
    };
    fs.writeJsonSync(configPath, defaultConfig, { spaces: 2 });
    console.log('✅ cat.config.json has been created at the project root.');
  } else {
    console.log('ℹ️  cat.config.json already exists.');
  }
}

/**
 * Start the development server
 */
async function startServer() {
  const projectRoot = process.cwd();
  const configPath = path.join(projectRoot, 'cat.config.json');

  if (!fs.existsSync(configPath)) {
    console.error('❌ Error: cat.config.json not found. Please run "npm run cat init" first.');
    process.exit(1);
  }

  const config = fs.readJsonSync(configPath);
  const indexPath = path.join(projectRoot, config.root);

  if (!fs.existsSync(indexPath)) {
    console.error(`❌ Error: Root file "${config.root}" not found.`);
    process.exit(1);
  }

  const app = express();
  const PORT = 3000;

  app.get('*', async (req, res) => {
    try {
      const compiledHTML = await compiler.compile(indexPath);
      res.send(compiledHTML);
    } catch (error) {
      console.error('❌ Compilation Error:', error);
      res.status(500).send('Internal Server Error');
    }
  });

  app.listen(PORT, () => {
    console.log(`🚀 Development server is running at http://localhost:${PORT}`);
  });
}

// Define the version
program.version('1.0.0');

// Define the init command
program
  .command('init')
  .description('Initialize package.json and cat.config.json at the project root')
  .action(initializeProject);

// Define the start command
program
  .command('start')
  .description('Start the development server')
  .action(startServer);

// Parse the command-line arguments
program.parse(process.argv);

---------

**Requirements**  
Our compiler will examine `{filename}.comp.html` to identify the first wrapper that is neither a `<script>` nor a `<style>` tag. The name of this tag will be used as the custom element name. If the name lacks a hyphen (`-`), one will be automatically appended when the custom element is registered, resulting in `{name}-cat`.  

Our framework simplifies the use of these components by allowing you to declare them directly where they will be utilized. The compiler identifies which components have been declared and includes them in the JavaScript bundle for registration when the page loads.

**Component Syntax**  
```html
<{comp name}></{comp name}>
<script></script> <--- For now, this tag won't be compiled
<style></style> <--- For now, this tag won't be compiled
```

**Sample Usage**  
```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Cat Framework App</title>
</head>
<body>
    <hello-world></hello-world>
</body>
</html>

<!-- hello.comp.html -->
<hello-world> Hi there, everyone </hello-world>
```