#!/usr/bin/env node import { execSync } from 'child_process'; import fs from 'fs-extra'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const logStep = (stepNumber, message) => { console.log(`\n📋 Étape ${stepNumber}: ${message}`); }; // Templates zen (inline pour Ă©viter des dĂ©pendances externes) const zenTemplates = { instrumentation: `export async function register() { if (process.env.NEXT_RUNTIME === 'nodejs') { const { initializeZen } = await import('@zen/core'); await initializeZen(); } } `, authRedirect: `import { redirect } from 'next/navigation'; export default function Redirect() { redirect('/auth/login/'); } `, authCatchAll: `export { default } from '@zen/core/auth/page'; `, adminRedirect: `import { redirect } from 'next/navigation'; export default function Redirect() { redirect('/admin/dashboard'); } `, adminCatchAll: `export { default } from '@zen/core/admin/page'; `, zenApiRoute: `export { GET, POST, PUT, DELETE, PATCH } from '@zen/core/zen/api'; `, zenPageRoute: `export { default, generateMetadata } from '@zen/core/modules/page'; `, }; // Fichiers zen Ă  crĂ©er dans le projet cible const zenFiles = [ { path: 'instrumentation.js', template: 'instrumentation' }, { path: 'app/(auth)/auth/page.js', template: 'authRedirect' }, { path: 'app/(auth)/auth/[...auth]/page.js', template: 'authCatchAll' }, { path: 'app/(admin)/admin/page.js', template: 'adminRedirect' }, { path: 'app/(admin)/admin/[...admin]/page.js', template: 'adminCatchAll' }, { path: 'app/zen/api/[...path]/route.js', template: 'zenApiRoute' }, { path: 'app/zen/[...zen]/page.js', template: 'zenPageRoute' }, ]; async function createZenFile(filePath, content) { const fullPath = path.resolve(process.cwd(), filePath); const dir = path.dirname(fullPath); await fs.ensureDir(dir); await fs.writeFile(fullPath, content, 'utf-8'); console.log(` ✅ ${filePath}`); } async function initProject() { try { console.log('\n🚀 Initialisation du projet Next.js avec @zen/core...\n'); // Étape 1 : CrĂ©er le projet Next.js (le dossier doit ĂȘtre vide) logStep(1, 'CrĂ©ation du projet Next.js'); execSync('npx create-next-app@latest ./ --javascript --tailwind --app --empty', { stdio: 'inherit' }); // Étape 2 : Supprimer /app (sera remplacĂ© par le template) logStep(2, 'Suppression du dossier /app par dĂ©faut'); if (fs.existsSync('./app')) { fs.removeSync('./app'); console.log(' 📁 Dossier /app supprimĂ©'); } // Étape 3 : Mettre Ă  jour jsconfig.json (path aliases) logStep(3, 'Configuration des path aliases (jsconfig.json)'); fs.writeJsonSync('./jsconfig.json', { compilerOptions: { paths: { '@*': ['./*'] }, }, }, { spaces: 2 }); console.log(' ⚙ jsconfig.json mis Ă  jour'); // Étape 4 : Mettre Ă  jour next.config.mjs logStep(4, 'Configuration de next.config.mjs'); fs.writeFileSync('./next.config.mjs', `/** @type {import('next').NextConfig} */ const nextConfig = { \tdevIndicators: false, \texperimental: { \t\tinstrumentationHook: true, \t}, }; export default nextConfig; `); console.log(' ⚙ next.config.mjs mis Ă  jour'); // Étape 5 : Mettre Ă  jour README.md logStep(5, 'Mise Ă  jour du README.md'); const packageJsonPath = './package.json'; if (fs.existsSync(packageJsonPath)) { const packageJson = fs.readJsonSync(packageJsonPath); const projectName = packageJson.name || 'Mon projet'; fs.writeFileSync('README.md', `# ${projectName} Un site web construit avec Next.js, Tailwind CSS et @zen/core. ![screenshot](/.github/assets/screenshot.png)`); console.log(' 📘 README.md mis Ă  jour'); } // Étape 6 : Ajouter le script make-favicon dans package.json logStep(6, 'Ajout du script make-favicon'); if (fs.existsSync(packageJsonPath)) { const packageJson = fs.readJsonSync(packageJsonPath); if (!packageJson.scripts) packageJson.scripts = {}; packageJson.scripts['make-favicon'] = 'node dev/icons/make-favicon.js'; fs.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 }); console.log(' ⚙ Script make-favicon ajoutĂ©'); } // Étape 7 : Copier les fichiers template (app/, styles/, dev/, components/) logStep(7, 'Copie des fichiers template'); const templatesPath = path.join(__dirname, '..', 'templates'); if (fs.existsSync(templatesPath)) { fs.copySync(templatesPath, './', { overwrite: true }); console.log(' 📁 Fichiers template copiĂ©s'); } else { console.error(' ❌ Dossier templates introuvable dans le package zen-start'); process.exit(1); } // Étape 8 : CrĂ©er les fichiers zen (auth, admin, api, instrumentation) logStep(8, 'CrĂ©ation des fichiers @zen/core'); for (const file of zenFiles) { await createZenFile(file.path, zenTemplates[file.template]); } // Étape 9 : CrĂ©er .npmrc avec le registre Gitea (APRÈS create-next-app !) logStep(9, 'Configuration du registre npm (@zen/core)'); fs.writeFileSync('./.npmrc', '@zen:registry=https://git.hyko.cx/api/packages/zen/npm/\n'); console.log(' ⚙ .npmrc créé'); // Étape 10 : Installer @zen/core logStep(10, 'Installation de @zen/core'); execSync('npm install @zen/core', { stdio: 'inherit' }); // Fin console.log('\n✅ Projet zen prĂȘt !\n'); console.log('Prochaines Ă©tapes :'); console.log(' 1. Configurer les variables d\'environnement'); console.log(' (voir la doc : https://git.hyko.cx/zen/core)'); console.log(' 2. Initialiser la base de donnĂ©es :'); console.log(' npx zen-db init'); console.log(''); } catch (error) { console.error('\n❌ Une erreur est survenue :', error.message); process.exit(1); } } initProject();