vako 1.3.13 → 1.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -106,36 +106,105 @@ class SetupExecutor {
106
106
  }
107
107
 
108
108
  getDirectoriesForTemplate() {
109
- const baseDirectories = [
110
- 'views',
111
- 'views/layouts',
112
- 'views/partials',
113
- 'views/components',
114
- 'routes',
115
- 'routes/api',
116
- 'public',
117
- 'public/css',
118
- 'public/js',
119
- 'public/images',
120
- 'config',
121
- 'middleware',
122
- 'plugins',
123
- 'data',
124
- 'utils'
125
- ];
126
-
127
- const templateDirectories = {
128
- blog: ['content', 'content/posts', 'admin', 'uploads'],
129
- admin: ['admin', 'admin/views', 'dashboard'],
130
- ecommerce: ['shop', 'products', 'orders', 'cart'],
131
- portfolio: ['portfolio', 'projects', 'gallery'],
132
- pwa: ['pwa', 'sw', 'manifest', 'offline']
133
- };
134
-
135
- return [
136
- ...baseDirectories,
137
- ...(templateDirectories[this.config.template] || [])
138
- ];
109
+ const { codeType } = this.config;
110
+
111
+ // Structure de base pour EJS
112
+ if (codeType === 'ejs' || !codeType) {
113
+ const baseDirectories = [
114
+ 'views',
115
+ 'views/layouts',
116
+ 'views/partials',
117
+ 'views/components',
118
+ 'routes',
119
+ 'routes/api',
120
+ 'public',
121
+ 'public/css',
122
+ 'public/js',
123
+ 'public/images',
124
+ 'config',
125
+ 'middleware',
126
+ 'plugins',
127
+ 'data',
128
+ 'utils',
129
+ 'locales' // Dossier pour les traductions
130
+ ];
131
+
132
+ const templateDirectories = {
133
+ blog: ['content', 'content/posts', 'admin', 'uploads'],
134
+ admin: ['admin', 'admin/views', 'dashboard'],
135
+ ecommerce: ['shop', 'products', 'orders', 'cart'],
136
+ portfolio: ['portfolio', 'projects', 'gallery'],
137
+ pwa: ['pwa', 'sw', 'manifest', 'offline']
138
+ };
139
+
140
+ return [
141
+ ...baseDirectories,
142
+ ...(templateDirectories[this.config.template] || [])
143
+ ];
144
+ }
145
+
146
+ // Structure pour TypeScript
147
+ if (codeType === 'typescript') {
148
+ const baseDirectories = [
149
+ 'src',
150
+ 'src/routes',
151
+ 'src/routes/api',
152
+ 'src/middleware',
153
+ 'src/utils',
154
+ 'src/types',
155
+ 'src/config',
156
+ 'views',
157
+ 'views/layouts',
158
+ 'public',
159
+ 'public/css',
160
+ 'public/js',
161
+ 'public/images',
162
+ 'config',
163
+ 'plugins',
164
+ 'data'
165
+ ];
166
+
167
+ const templateDirectories = {
168
+ blog: ['src/content', 'src/admin', 'uploads'],
169
+ admin: ['src/admin', 'src/dashboard'],
170
+ ecommerce: ['src/shop', 'src/products', 'src/orders'],
171
+ portfolio: ['src/portfolio', 'src/projects', 'src/gallery']
172
+ };
173
+
174
+ return [
175
+ ...baseDirectories,
176
+ ...(templateDirectories[this.config.template] || [])
177
+ ];
178
+ }
179
+
180
+ // Structure pour Next.js
181
+ if (codeType === 'nextjs') {
182
+ const baseDirectories = [
183
+ 'src',
184
+ 'src/app',
185
+ 'src/app/api',
186
+ 'src/components',
187
+ 'src/lib',
188
+ 'src/types',
189
+ 'public',
190
+ 'public/images',
191
+ 'config',
192
+ 'plugins'
193
+ ];
194
+
195
+ const templateDirectories = {
196
+ blog: ['src/app/blog', 'src/app/admin', 'src/content'],
197
+ admin: ['src/app/admin', 'src/app/dashboard'],
198
+ portfolio: ['src/app/portfolio', 'src/app/projects']
199
+ };
200
+
201
+ return [
202
+ ...baseDirectories,
203
+ ...(templateDirectories[this.config.template] || [])
204
+ ];
205
+ }
206
+
207
+ return [];
139
208
  }
140
209
 
141
210
  async generateTemplateFiles() {
@@ -154,9 +223,26 @@ class SetupExecutor {
154
223
  }
155
224
 
156
225
  generateFiles() {
157
- const { projectName, description, author, license, template, features, database, auth, styling } = this.config;
226
+ const { projectName, description, author, license, template, features, database, auth, styling, codeType } = this.config;
158
227
  const files = {};
159
228
 
229
+ // Générer les fichiers selon le type de code
230
+ if (codeType === 'nextjs') {
231
+ return this.generateNextJsFiles();
232
+ } else if (codeType === 'typescript') {
233
+ return this.generateTypeScriptFiles();
234
+ } else {
235
+ return this.generateEjsFiles();
236
+ }
237
+ }
238
+
239
+ generateEjsFiles() {
240
+ const { projectName, description, author, license, language } = this.config;
241
+ const files = {};
242
+
243
+ // Générer les fichiers de traduction selon la langue
244
+ const translations = this.getTranslations(language);
245
+
160
246
  // package.json
161
247
  files['package.json'] = JSON.stringify({
162
248
  name: projectName,
@@ -168,11 +254,11 @@ class SetupExecutor {
168
254
  start: 'vako start',
169
255
  build: 'vako build'
170
256
  },
171
- keywords: ['vako', 'framework', 'web'],
257
+ keywords: ['vako', 'framework', 'web', 'ejs'],
172
258
  author: author || '',
173
259
  license: license || 'MIT',
174
260
  dependencies: {
175
- vako: '^1.3.6'
261
+ vako: '^1.3.13'
176
262
  }
177
263
  }, null, 2);
178
264
 
@@ -265,6 +351,357 @@ h1 {
265
351
  return files;
266
352
  }
267
353
 
354
+ generateTypeScriptFiles() {
355
+ const { projectName, description, author, license } = this.config;
356
+ const files = {};
357
+
358
+ // package.json
359
+ files['package.json'] = JSON.stringify({
360
+ name: projectName,
361
+ version: '1.0.0',
362
+ description: description || 'A modern web application built with Vako and TypeScript',
363
+ main: 'dist/app.js',
364
+ scripts: {
365
+ dev: 'ts-node src/app.ts',
366
+ build: 'tsc',
367
+ start: 'node dist/app.js',
368
+ 'type-check': 'tsc --noEmit'
369
+ },
370
+ keywords: ['vako', 'framework', 'web', 'typescript'],
371
+ author: author || '',
372
+ license: license || 'MIT',
373
+ dependencies: {
374
+ vako: '^1.3.13'
375
+ },
376
+ devDependencies: {
377
+ '@types/node': '^20.10.5',
378
+ '@types/express': '^4.17.21',
379
+ 'ts-node': '^10.9.2',
380
+ 'typescript': '^5.3.3'
381
+ }
382
+ }, null, 2);
383
+
384
+ // tsconfig.json
385
+ files['tsconfig.json'] = JSON.stringify({
386
+ compilerOptions: {
387
+ target: 'ES2020',
388
+ module: 'commonjs',
389
+ lib: ['ES2020'],
390
+ outDir: './dist',
391
+ rootDir: './src',
392
+ strict: true,
393
+ esModuleInterop: true,
394
+ skipLibCheck: true,
395
+ forceConsistentCasingInFileNames: true,
396
+ resolveJsonModule: true,
397
+ declaration: true,
398
+ declarationMap: true,
399
+ sourceMap: true
400
+ },
401
+ include: ['src/**/*'],
402
+ exclude: ['node_modules', 'dist']
403
+ }, null, 2);
404
+
405
+ // src/app.ts
406
+ files['src/app.ts'] = `import { App } from 'vako';
407
+
408
+ const app = new App({
409
+ port: 3000,
410
+ isDev: true,
411
+ viewsDir: 'views',
412
+ staticDir: 'public',
413
+ routesDir: 'src/routes'
414
+ });
415
+
416
+ app.loadRoutes();
417
+ app.listen();
418
+ `;
419
+
420
+ // src/routes/index.ts
421
+ files['src/routes/index.ts'] = `import { Router, Request, Response } from 'express';
422
+
423
+ const router = Router();
424
+
425
+ router.get('/', (req: Request, res: Response) => {
426
+ res.render('index', {
427
+ title: 'Welcome to ${projectName}'
428
+ });
429
+ });
430
+
431
+ export default router;
432
+ `;
433
+
434
+ // README.md
435
+ files['README.md'] = `# ${projectName}
436
+
437
+ ${description || 'A modern web application built with Vako and TypeScript'}
438
+
439
+ ## Getting Started
440
+
441
+ \`\`\`bash
442
+ npm install
443
+ npm run dev
444
+ \`\`\`
445
+
446
+ ## Building for Production
447
+
448
+ \`\`\`bash
449
+ npm run build
450
+ npm start
451
+ \`\`\`
452
+
453
+ ## Documentation
454
+
455
+ Visit [https://vako.js.org](https://vako.js.org) for more information.
456
+ `;
457
+
458
+ // .gitignore
459
+ files['.gitignore'] = `node_modules/
460
+ .env
461
+ *.log
462
+ .DS_Store
463
+ dist/
464
+ coverage/
465
+ *.tsbuildinfo
466
+ `;
467
+
468
+ // views/index.ejs
469
+ files['views/index.ejs'] = `<!DOCTYPE html>
470
+ <html lang="en">
471
+ <head>
472
+ <meta charset="UTF-8">
473
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
474
+ <title><%= title %></title>
475
+ </head>
476
+ <body>
477
+ <h1><%= title %></h1>
478
+ <p>Welcome to your Vako TypeScript application!</p>
479
+ </body>
480
+ </html>
481
+ `;
482
+
483
+ return files;
484
+ }
485
+
486
+ generateNextJsFiles() {
487
+ const { projectName, description, author, license } = this.config;
488
+ const files = {};
489
+
490
+ // package.json
491
+ files['package.json'] = JSON.stringify({
492
+ name: projectName,
493
+ version: '1.0.0',
494
+ description: description || 'A modern web application built with Vako and Next.js',
495
+ scripts: {
496
+ dev: 'next dev',
497
+ build: 'next build',
498
+ start: 'next start',
499
+ lint: 'next lint'
500
+ },
501
+ keywords: ['vako', 'framework', 'web', 'nextjs', 'react'],
502
+ author: author || '',
503
+ license: license || 'MIT',
504
+ dependencies: {
505
+ vako: '^1.3.13',
506
+ next: '^14.0.0',
507
+ react: '^18.2.0',
508
+ 'react-dom': '^18.2.0'
509
+ },
510
+ devDependencies: {
511
+ '@types/node': '^20.10.5',
512
+ '@types/react': '^18.2.0',
513
+ '@types/react-dom': '^18.2.0',
514
+ typescript: '^5.3.3',
515
+ eslint: '^8.56.0',
516
+ 'eslint-config-next': '^14.0.0'
517
+ }
518
+ }, null, 2);
519
+
520
+ // next.config.js
521
+ files['next.config.js'] = `/** @type {import('next').NextConfig} */
522
+ const { NextJsAdapter } = require('vako');
523
+ const { App } = require('vako');
524
+
525
+ const nextConfig = {
526
+ reactStrictMode: true,
527
+ // Configuration Vako
528
+ webpack: (config, { isServer }) => {
529
+ if (!isServer) {
530
+ // Configuration pour le client
531
+ }
532
+ return config;
533
+ }
534
+ };
535
+
536
+ module.exports = nextConfig;
537
+ `;
538
+
539
+ // tsconfig.json (pour Next.js)
540
+ files['tsconfig.json'] = JSON.stringify({
541
+ compilerOptions: {
542
+ target: 'ES2020',
543
+ lib: ['dom', 'dom.iterable', 'esnext'],
544
+ allowJs: true,
545
+ skipLibCheck: true,
546
+ strict: true,
547
+ forceConsistentCasingInFileNames: true,
548
+ noEmit: true,
549
+ esModuleInterop: true,
550
+ module: 'esnext',
551
+ moduleResolution: 'bundler',
552
+ resolveJsonModule: true,
553
+ isolatedModules: true,
554
+ jsx: 'preserve',
555
+ incremental: true,
556
+ plugins: [
557
+ {
558
+ name: 'next'
559
+ }
560
+ ],
561
+ paths: {
562
+ '@/*': ['./src/*']
563
+ }
564
+ },
565
+ include: ['next-env.d.ts', '**/*.ts', '**/*.tsx', '.next/types/**/*.ts'],
566
+ exclude: ['node_modules']
567
+ }, null, 2);
568
+
569
+ // server.js (serveur personnalisé avec Vako)
570
+ files['server.js'] = `const { createServer } = require('http');
571
+ const { parse } = require('url');
572
+ const next = require('next');
573
+ const { App } = require('vako');
574
+ const { NextJsAdapter } = require('vako');
575
+
576
+ const dev = process.env.NODE_ENV !== 'production';
577
+ const hostname = 'localhost';
578
+ const port = parseInt(process.env.PORT || '3000', 10);
579
+
580
+ const app = next({ dev, hostname, port });
581
+ const handle = app.getRequestHandler();
582
+
583
+ app.prepare().then(() => {
584
+ // Créer l'instance Vako
585
+ const vakoApp = new App({
586
+ port: port + 1, // Port différent pour Vako
587
+ isDev: dev
588
+ });
589
+
590
+ // Intégrer Vako avec Next.js
591
+ const adapter = new NextJsAdapter({
592
+ nextApp: app,
593
+ enableVakoRoutes: true,
594
+ enableVakoPlugins: true,
595
+ routePrefix: '/api/vako'
596
+ });
597
+
598
+ adapter.integrateRoutes(vakoApp);
599
+ adapter.usePlugins(vakoApp);
600
+
601
+ // Créer le serveur HTTP
602
+ createServer(async (req, res) => {
603
+ try {
604
+ const parsedUrl = parse(req.url, true);
605
+ await handle(req, res, parsedUrl);
606
+ } catch (err) {
607
+ console.error('Error occurred handling', req.url, err);
608
+ res.statusCode = 500;
609
+ res.end('internal server error');
610
+ }
611
+ }).listen(port, (err) => {
612
+ if (err) throw err;
613
+ console.log(\`> Ready on http://\${hostname}:\${port}\`);
614
+ });
615
+ });
616
+ `;
617
+
618
+ // src/app/layout.tsx
619
+ files['src/app/layout.tsx'] = `import type { Metadata } from 'next';
620
+ import './globals.css';
621
+
622
+ export const metadata: Metadata = {
623
+ title: '${projectName}',
624
+ description: '${description || 'A modern web application built with Vako and Next.js'}'
625
+ };
626
+
627
+ export default function RootLayout({
628
+ children
629
+ }: {
630
+ children: React.ReactNode;
631
+ }) {
632
+ return (
633
+ <html lang="en">
634
+ <body>{children}</body>
635
+ </html>
636
+ );
637
+ }
638
+ `;
639
+
640
+ // src/app/page.tsx
641
+ files['src/app/page.tsx'] = `export default function Home() {
642
+ return (
643
+ <main>
644
+ <h1>Welcome to ${projectName}</h1>
645
+ <p>Welcome to your Vako Next.js application!</p>
646
+ </main>
647
+ );
648
+ }
649
+ `;
650
+
651
+ // src/app/globals.css
652
+ files['src/app/globals.css'] = `body {
653
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
654
+ margin: 0;
655
+ padding: 20px;
656
+ background-color: #f5f5f5;
657
+ }
658
+
659
+ h1 {
660
+ color: #333;
661
+ }
662
+ `;
663
+
664
+ // README.md
665
+ files['README.md'] = `# ${projectName}
666
+
667
+ ${description || 'A modern web application built with Vako and Next.js'}
668
+
669
+ ## Getting Started
670
+
671
+ \`\`\`bash
672
+ npm install
673
+ npm run dev
674
+ \`\`\`
675
+
676
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
677
+
678
+ ## Building for Production
679
+
680
+ \`\`\`bash
681
+ npm run build
682
+ npm start
683
+ \`\`\`
684
+
685
+ ## Documentation
686
+
687
+ - [Next.js Documentation](https://nextjs.org/docs)
688
+ - [Vako Documentation](https://vako.js.org)
689
+ `;
690
+
691
+ // .gitignore
692
+ files['.gitignore'] = `node_modules/
693
+ .env
694
+ *.log
695
+ .DS_Store
696
+ .next/
697
+ out/
698
+ dist/
699
+ coverage/
700
+ `;
701
+
702
+ return files;
703
+ }
704
+
268
705
  async configureFeatures() {
269
706
  // Configure features based on this.config.features
270
707
  // This is a placeholder - features are already configured in generateFiles()
@@ -17,6 +17,8 @@ class SetupWizard {
17
17
  this.config = {
18
18
  projectName: '',
19
19
  template: 'default',
20
+ codeType: 'ejs', // 'ejs', 'typescript', 'nextjs'
21
+ language: 'fr', // 'fr', 'en', 'es', 'de', etc.
20
22
  features: [],
21
23
  database: 'sqlite',
22
24
  auth: { enabled: false },
@@ -206,13 +208,130 @@ class SetupWizard {
206
208
  Object.assign(this.config, this.sanitizeProjectInfo(answers));
207
209
  }
208
210
 
211
+ /**
212
+ * Sélection du type de code (EJS, TypeScript, Next.js)
213
+ */
214
+ async selectCodeType() {
215
+ console.log(chalk.blue.bold('\n💻 Choose Your Code Type\n'));
216
+
217
+ const codeTypeChoices = [
218
+ {
219
+ name: '📄 EJS - Traditional server-side rendering with EJS templates',
220
+ value: 'ejs',
221
+ description: 'Classic Vako.js with EJS views, perfect for traditional web apps'
222
+ },
223
+ {
224
+ name: '📘 TypeScript - Type-safe JavaScript with TypeScript',
225
+ value: 'typescript',
226
+ description: 'Modern TypeScript support with type definitions and IntelliSense'
227
+ },
228
+ {
229
+ name: '⚛️ Next.js - React framework with SSR and SSG',
230
+ value: 'nextjs',
231
+ description: 'Next.js integration with React, Server-Side Rendering, and Static Generation'
232
+ }
233
+ ];
234
+
235
+ const { codeType } = await inquirer.prompt([{
236
+ type: 'list',
237
+ name: 'codeType',
238
+ message: '🎯 Select your preferred code type:',
239
+ choices: codeTypeChoices.map(choice => ({
240
+ name: choice.name,
241
+ value: choice.value
242
+ })),
243
+ pageSize: 10
244
+ }]);
245
+
246
+ this.config.codeType = codeType;
247
+
248
+ const selectedChoice = codeTypeChoices.find(c => c.value === codeType);
249
+ console.log(chalk.gray(`\n✓ Selected: ${selectedChoice.description}\n`));
250
+ }
251
+
252
+ /**
253
+ * Sélection de la langue du site
254
+ */
255
+ async selectLanguage() {
256
+ console.log(chalk.blue.bold('\n🌍 Choose Your Site Language\n'));
257
+
258
+ const languageChoices = [
259
+ {
260
+ name: '🇫🇷 Français - French',
261
+ value: 'fr',
262
+ description: 'French language for your site'
263
+ },
264
+ {
265
+ name: '🇬🇧 English - English',
266
+ value: 'en',
267
+ description: 'English language for your site'
268
+ },
269
+ {
270
+ name: '🇪🇸 Español - Spanish',
271
+ value: 'es',
272
+ description: 'Spanish language for your site'
273
+ },
274
+ {
275
+ name: '🇩🇪 Deutsch - German',
276
+ value: 'de',
277
+ description: 'German language for your site'
278
+ },
279
+ {
280
+ name: '🇮🇹 Italiano - Italian',
281
+ value: 'it',
282
+ description: 'Italian language for your site'
283
+ },
284
+ {
285
+ name: '🇵🇹 Português - Portuguese',
286
+ value: 'pt',
287
+ description: 'Portuguese language for your site'
288
+ },
289
+ {
290
+ name: '🇳🇱 Nederlands - Dutch',
291
+ value: 'nl',
292
+ description: 'Dutch language for your site'
293
+ },
294
+ {
295
+ name: '🌐 Multi-language - Multiple languages',
296
+ value: 'multi',
297
+ description: 'Support for multiple languages'
298
+ }
299
+ ];
300
+
301
+ const { language } = await inquirer.prompt([{
302
+ type: 'list',
303
+ name: 'language',
304
+ message: '🌍 Select the language for your site:',
305
+ choices: languageChoices.map(choice => ({
306
+ name: choice.name,
307
+ value: choice.value
308
+ })),
309
+ pageSize: 10
310
+ }]);
311
+
312
+ this.config.language = language;
313
+
314
+ const selectedChoice = languageChoices.find(c => c.value === language);
315
+ console.log(chalk.gray(`\n✓ Selected: ${selectedChoice.description}\n`));
316
+ }
317
+
209
318
  /**
210
319
  * Sélection du template de projet
211
320
  */
212
321
  async selectTemplate() {
213
322
  console.log(chalk.blue.bold('\n🎨 Choose Your Template\n'));
214
323
 
215
- const templateChoices = Array.from(this.templates.entries()).map(([value, template]) => ({
324
+ // Filtrer les templates selon le type de code
325
+ let availableTemplates = Array.from(this.templates.entries());
326
+
327
+ // Si Next.js est sélectionné, limiter les options
328
+ if (this.config.codeType === 'nextjs') {
329
+ availableTemplates = availableTemplates.filter(([key]) =>
330
+ ['default', 'api', 'blog', 'portfolio'].includes(key)
331
+ );
332
+ }
333
+
334
+ const templateChoices = availableTemplates.map(([value, template]) => ({
216
335
  name: template.name,
217
336
  value
218
337
  }));
@@ -532,12 +651,19 @@ class SetupWizard {
532
651
  * Génération du résumé de configuration
533
652
  */
534
653
  generateSummary() {
535
- const { projectName, template, features, database, auth, plugins, styling, theme } = this.config;
654
+ const { projectName, template, features, database, auth, plugins, styling, theme, codeType } = this.config;
655
+
656
+ const codeTypeLabels = {
657
+ 'ejs': '📄 EJS',
658
+ 'typescript': '📘 TypeScript',
659
+ 'nextjs': '⚛️ Next.js'
660
+ };
536
661
 
537
662
  return chalk.white(`
538
663
  🏷️ Project: ${chalk.cyan.bold(projectName)}
539
664
  📝 Description: ${chalk.gray(this.config.description)}
540
665
  👤 Author: ${chalk.green(this.config.author)}
666
+ 💻 Code Type: ${chalk.cyan(codeTypeLabels[codeType] || codeType)}
541
667
  🎨 Template: ${chalk.yellow(template)}
542
668
  🗄️ Database: ${chalk.blue(database)}
543
669
  🔐 Auth: ${chalk.magenta(auth.enabled ? '✅ Enabled' : '❌ Disabled')}
package/bin/vako.js CHANGED
@@ -21,7 +21,7 @@ const program = new Command();
21
21
  program
22
22
  .name('vako')
23
23
  .description('Vako Framework CLI')
24
- .version('1.3.13');
24
+ .version('1.3.15');
25
25
 
26
26
  // ============= DEV COMMAND =============
27
27
  program
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vako",
3
- "version": "1.3.13",
3
+ "version": "1.3.15",
4
4
  "description": "🚀 Ultra-modern Node.js framework with hot reload, plugins, authentication, TypeScript support, and Next.js integration",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",