#!/usr/bin/env node const { program } = require('commander'); const fs = require('fs'); const path = require('path'); const AeThexCompiler = require('./aethex-compiler'); const chalk = require('chalk'); program .name('aethex') .description('AeThex Language CLI - Write once, deploy everywhere') .version('1.0.0'); // Compile command program .command('compile ') .description('Compile an AeThex file') .option('-t, --target ', 'Target platform: javascript, roblox, uefn, unity', 'javascript') .option('-o, --output ', 'Output file path') .option('-w, --watch', 'Watch for file changes') .action((file, options) => { compileFile(file, options); if (options.watch) { console.log(chalk.blue('šŸ‘€ Watching for changes...')); fs.watchFile(file, () => { console.log(chalk.yellow('\nšŸ”„ File changed, recompiling...')); compileFile(file, options); }); } }); // New project command program .command('new ') .description('Create a new AeThex project') .option('-t, --template ', 'Project template: basic, passport, game', 'basic') .action((name, options) => { createProject(name, options.template); }); // Init command program .command('init') .description('Initialize AeThex in current directory') .action(() => { initProject(); }); program.parse(); // Helper functions function compileFile(file, options) { if (!fs.existsSync(file)) { console.error(chalk.red(`āŒ File not found: ${file}`)); process.exit(1); } const sourceCode = fs.readFileSync(file, 'utf-8'); const compiler = new AeThexCompiler({ target: options.target, sourceFile: file }); console.log(chalk.blue(`šŸ”Ø Compiling ${path.basename(file)} to ${options.target}...`)); const result = compiler.compile(sourceCode); // Show errors/warnings if (result.errors.length > 0) { console.log(chalk.red('\nāŒ Compilation failed:\n')); result.errors.forEach(err => { console.log(chalk.red(` ${err.file}:${err.line} - ${err.message}`)); }); process.exit(1); } if (result.warnings.length > 0) { console.log(chalk.yellow('\nāš ļø Warnings:\n')); result.warnings.forEach(warn => { console.log(chalk.yellow(` ${warn.file}:${warn.line} - ${warn.message}`)); }); } if (result.success) { // Determine output file let outputFile = options.output; if (!outputFile) { const ext = { 'javascript': '.js', 'roblox': '.lua', 'uefn': '.verse', 'unity': '.cs' }[options.target] || '.js'; outputFile = file.replace('.aethex', ext); } fs.writeFileSync(outputFile, result.code); console.log(chalk.green(`\nāœ… Compiled successfully to: ${outputFile}`)); } } function createProject(name, template) { const projectDir = path.join(process.cwd(), name); if (fs.existsSync(projectDir)) { console.error(chalk.red(`āŒ Directory ${name} already exists`)); process.exit(1); } console.log(chalk.blue(`šŸ“¦ Creating new AeThex project: ${name}`)); fs.mkdirSync(projectDir); fs.mkdirSync(path.join(projectDir, 'src')); fs.mkdirSync(path.join(projectDir, 'build')); // Create package.json const packageJson = { name: name, version: '1.0.0', description: 'An AeThex project', main: 'src/main.aethex', scripts: { build: 'aethex compile src/main.aethex -o build/main.js', 'build:roblox': 'aethex compile src/main.aethex -t roblox -o build/main.lua', watch: 'aethex compile src/main.aethex -w' }, dependencies: { '@aethex/core': '^1.0.0' } }; fs.writeFileSync( path.join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2) ); // Create main.aethex based on template let mainCode = ''; if (template === 'passport') { mainCode = `# AeThex Passport Example import { Passport } from "@aethex/core" reality ${name} { platforms: [roblox, web] } journey AuthenticateUser(username) { platform: all let passport = new Passport(username) when passport.verify() { sync passport across [roblox, web] notify "Welcome, " + username + "!" reveal passport } } `; } else { mainCode = `# ${name} # Created with AeThex CLI reality ${name} { platforms: all } journey Start() { platform: all notify "Hello from AeThex!" } `; } fs.writeFileSync(path.join(projectDir, 'src', 'main.aethex'), mainCode); // Create README const readme = `# ${name} An AeThex project created with \`aethex new\`. ## Getting Started \`\`\`bash # Install dependencies npm install # Build (JavaScript) npm run build # Build (Roblox/Lua) npm run build:roblox # Watch mode npm run watch \`\`\` ## Project Structure - \`src/\` - AeThex source files (.aethex) - \`build/\` - Compiled output ## Learn More - [AeThex Docs](https://aethex.dev/lang) - [Examples](https://github.com/aethex/aethex-lang/tree/main/examples) `; fs.writeFileSync(path.join(projectDir, 'README.md'), readme); console.log(chalk.green(`\nāœ… Project created successfully!`)); console.log(chalk.blue(`\nNext steps:`)); console.log(chalk.white(` cd ${name}`)); console.log(chalk.white(` npm install`)); console.log(chalk.white(` npm run build`)); } function initProject() { const cwd = process.cwd(); console.log(chalk.blue('šŸ“¦ Initializing AeThex project...')); // Create directories if they don't exist if (!fs.existsSync('src')) { fs.mkdirSync('src'); } if (!fs.existsSync('build')) { fs.mkdirSync('build'); } // Create aethex.config.json const config = { targets: ['javascript', 'roblox'], srcDir: 'src', outDir: 'build', stdlib: true }; fs.writeFileSync('aethex.config.json', JSON.stringify(config, null, 2)); console.log(chalk.green('āœ… AeThex initialized!')); console.log(chalk.blue('\nCreated:')); console.log(chalk.white(' aethex.config.json')); console.log(chalk.white(' src/')); console.log(chalk.white(' build/')); }