frontend-hamroun 1.2.82 → 1.2.84

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.
Files changed (47) hide show
  1. package/bin/cli.js +58 -870
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.client.cjs +1 -1
  5. package/dist/index.client.cjs.map +1 -1
  6. package/dist/index.client.js +2 -2
  7. package/dist/index.client.js.map +1 -1
  8. package/dist/index.js +116 -133
  9. package/dist/index.js.map +1 -1
  10. package/dist/jsx-runtime.cjs.map +1 -1
  11. package/dist/jsx-runtime.js.map +1 -1
  12. package/dist/renderer-DaVfBeVi.cjs +2 -0
  13. package/dist/renderer-DaVfBeVi.cjs.map +1 -0
  14. package/dist/renderer-nfT7XSpo.js +61 -0
  15. package/dist/renderer-nfT7XSpo.js.map +1 -0
  16. package/dist/server-renderer-B5b0Q0ck.cjs +2 -0
  17. package/dist/server-renderer-B5b0Q0ck.cjs.map +1 -0
  18. package/dist/{server-renderer-QHt45Ip2.js → server-renderer-C4MB-jAp.js} +89 -96
  19. package/dist/server-renderer-C4MB-jAp.js.map +1 -0
  20. package/dist/server-renderer.cjs +1 -1
  21. package/dist/server-renderer.js +1 -1
  22. package/package.json +1 -1
  23. package/templates/basic-app/src/App.tsx +397 -19
  24. package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.js +1 -0
  25. package/templates/ssr-template/dist/client/index.html +23 -0
  26. package/templates/ssr-template/dist/client.js +951 -0
  27. package/templates/ssr-template/dist/server.js +739 -0
  28. package/templates/ssr-template/package.json +22 -22
  29. package/templates/ssr-template/src/App.tsx +874 -11
  30. package/templates/ssr-template/tsconfig.json +14 -10
  31. package/templates/ssr-template/vite.config.ts +19 -17
  32. package/templates/wasm/dist/assets/index-BNqTDBdE.js +295 -0
  33. package/templates/wasm/dist/example.wasm +0 -0
  34. package/templates/wasm/dist/index.html +53 -0
  35. package/templates/wasm/dist/wasm_exec.js +572 -0
  36. package/templates/wasm/package-lock.json +4577 -5307
  37. package/templates/wasm/package.json +25 -42
  38. package/templates/wasm/public/wasm_exec.js +12 -1
  39. package/templates/wasm/src/App.tsx +41 -55
  40. package/templates/wasm/vite.config.ts +24 -42
  41. package/dist/renderer-Bo9zkUZ_.js +0 -52
  42. package/dist/renderer-Bo9zkUZ_.js.map +0 -1
  43. package/dist/renderer-Din1y3YM.cjs +0 -2
  44. package/dist/renderer-Din1y3YM.cjs.map +0 -1
  45. package/dist/server-renderer-CqIpQ-od.cjs +0 -2
  46. package/dist/server-renderer-CqIpQ-od.cjs.map +0 -1
  47. package/dist/server-renderer-QHt45Ip2.js.map +0 -1
package/bin/cli.js CHANGED
@@ -1,9 +1,8 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import inquirer from 'inquirer';
5
5
  import chalk from 'chalk';
6
- import gradient from 'gradient-string';
7
6
  import { createSpinner } from 'nanospinner';
8
7
  import path from 'path';
9
8
  import fs from 'fs-extra';
@@ -11,55 +10,37 @@ import { fileURLToPath } from 'url';
11
10
  import { exec } from 'child_process';
12
11
  import { promisify } from 'util';
13
12
  import boxen from 'boxen';
14
- import terminalLink from 'terminal-link';
15
- import updateNotifier from 'update-notifier';
16
- import ora from 'ora';
17
- import figlet from 'figlet';
18
13
 
19
14
  // Convert to ESM-friendly __dirname equivalent
20
15
  const __filename = fileURLToPath(import.meta.url);
21
16
  const __dirname = path.dirname(__filename);
22
17
  const execAsync = promisify(exec);
23
18
 
24
- // Check for package updates
25
- try {
26
- const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
27
- const notifier = updateNotifier({ pkg, updateCheckInterval: 1000 * 60 * 60 * 24 });
28
-
29
- if (notifier.update) {
30
- const updateMessage = boxen(
31
- `Update available: ${chalk.dim(notifier.update.current)} → ${chalk.green(notifier.update.latest)}\n` +
32
- `Run ${chalk.cyan('npm i -g frontend-hamroun')} to update`,
33
- {
34
- padding: 1,
35
- margin: 1,
36
- borderStyle: 'round',
37
- borderColor: 'cyan'
38
- }
39
- );
40
- console.log(updateMessage);
41
- }
42
- } catch (error) {
43
- // Silently continue if update check fails
44
- }
45
-
46
19
  // CLI instance
47
20
  const program = new Command();
48
21
 
49
- // Create beautiful ASCII art banner with gradient colors
22
+ // Create beautiful ASCII art banner
50
23
  const displayBanner = () => {
51
- const titleText = figlet.textSync('Frontend Hamroun', {
52
- font: 'Standard',
53
- horizontalLayout: 'default',
54
- verticalLayout: 'default'
55
- });
56
-
57
- console.log('\n' + gradient.pastel.multiline(titleText));
24
+ console.log('\n' + chalk.cyan(`
25
+ ███████╗██████╗ ██████╗ ███╗ ██╗████████╗███████╗███╗ ██╗██████╗
26
+ ██╔════╝██╔══██╗██╔═══██╗████╗ ██║╚══██╔══╝██╔════╝████╗ ██║██╔══██╗
27
+ █████╗ ██████╔╝██║ ██║██╔██╗ ██║ ██║ █████╗ ██╔██╗ ██║██║ ██║
28
+ ██╔══╝ ██╔══██╗██║ ██║██║╚██╗██║ ██║ ██╔══╝ ██║╚██╗██║██║ ██║
29
+ ██║ ██║ ██║╚██████╔╝██║ ╚████║ ██║ ███████╗██║ ╚████║██████╔╝
30
+ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═════╝
31
+
32
+ ██╗ ██╗ █████╗ ███╗ ███╗██████╗ ██████╗ ██╗ ██╗███╗ ██╗
33
+ ██║ ██║██╔══██╗████╗ ████║██╔══██╗██╔═══██╗██║ ██║████╗ ██║
34
+ ███████║███████║██╔████╔██║██████╔╝██║ ██║██║ ██║██╔██╗ ██║
35
+ ██╔══██║██╔══██║██║╚██╔╝██║██╔══██╗██║ ██║██║ ██║██║╚██╗██║
36
+ ██║ ██║██║ ██║██║ ╚═╝ ██║██║ ██║╚██████╔╝╚██████╔╝██║ ╚████║
37
+ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝
38
+ `));
58
39
 
59
40
  console.log(boxen(
60
- `${chalk.bold('A lightweight full-stack JavaScript framework')}\n\n` +
61
- `${chalk.dim('Version:')} ${chalk.cyan(JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version)}\n` +
62
- `${chalk.dim('Documentation:')} ${terminalLink('frontendhamroun.io', 'https://github.com/hamroun/frontend-hamroun')}`,
41
+ `${chalk.bold('A lightweight frontend JavaScript framework')}\n\n` +
42
+ `${chalk.dim('Version:')} ${chalk.cyan('1.2.0')}\n` +
43
+ `${chalk.dim('Focus:')} Client-side applications only`,
63
44
  {
64
45
  padding: 1,
65
46
  margin: { top: 1, bottom: 1 },
@@ -72,106 +53,18 @@ const displayBanner = () => {
72
53
  // Version and description
73
54
  program
74
55
  .name('frontend-hamroun')
75
- .description('CLI for Frontend Hamroun - A lightweight full-stack JavaScript framework')
76
- .version(JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version);
77
-
78
- // Helper for creating visually consistent sections
79
- const createSection = (title) => {
80
- console.log('\n' + chalk.bold.cyan(`◆ ${title}`));
81
- console.log(chalk.cyan('─'.repeat(60)) + '\n');
82
- };
83
-
84
- // Helper for checking dependencies with improved feedback
85
- async function checkDependencies() {
86
- const spinner = ora({
87
- text: 'Checking environment...',
88
- spinner: 'dots',
89
- color: 'cyan'
90
- }).start();
91
-
92
- try {
93
- // Check Node version
94
- const nodeVersionOutput = await execAsync('node --version');
95
- const nodeVersion = nodeVersionOutput.stdout.trim().replace('v', '');
96
- const requiredNodeVersion = '14.0.0';
97
-
98
- if (compareVersions(nodeVersion, requiredNodeVersion) < 0) {
99
- spinner.fail(`Node.js ${requiredNodeVersion}+ required, but found ${nodeVersion}`);
100
- console.log(chalk.yellow(`Please upgrade Node.js: ${terminalLink('https://nodejs.org', 'https://nodejs.org')}`));
101
- return false;
102
- }
103
-
104
- // Check npm version
105
- const npmVersionOutput = await execAsync('npm --version');
106
- const npmVersion = npmVersionOutput.stdout.trim();
107
- const requiredNpmVersion = '6.0.0';
108
-
109
- if (compareVersions(npmVersion, requiredNpmVersion) < 0) {
110
- spinner.fail(`npm ${requiredNpmVersion}+ required, but found ${npmVersion}`);
111
- console.log(chalk.yellow(`Please upgrade npm: ${chalk.cyan('npm install -g npm')}`));
112
- return false;
113
- }
114
-
115
- spinner.succeed(`Environment ready: Node ${chalk.green(nodeVersion)}, npm ${chalk.green(npmVersion)}`);
116
- return true;
117
- } catch (error) {
118
- spinner.fail('Environment check failed');
119
- console.log(chalk.red('Error: Node.js and npm are required to use this tool.'));
120
- return false;
121
- }
122
- }
56
+ .description('CLI for Frontend Hamroun - A lightweight frontend JavaScript framework')
57
+ .version('1.2.0');
123
58
 
124
- // Compare versions helper
125
- function compareVersions(a, b) {
126
- const aParts = a.split('.').map(Number);
127
- const bParts = b.split('.').map(Number);
128
-
129
- for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
130
- const aVal = aParts[i] || 0;
131
- const bVal = bParts[i] || 0;
132
-
133
- if (aVal > bVal) return 1;
134
- if (aVal < bVal) return -1;
135
- }
136
-
137
- return 0;
138
- }
139
-
140
- // Choose template interactively with improved visualization
59
+ // Choose template interactively
141
60
  async function chooseTemplate() {
142
61
  const templatesPath = path.join(__dirname, '..', 'templates');
143
- const templates = fs.readdirSync(templatesPath).filter(file =>
144
- fs.statSync(path.join(templatesPath, file)).isDirectory()
145
- );
146
-
147
- // Emoji indicators for templates
148
- const templateIcons = {
149
- 'basic-app': '🚀',
150
- 'ssr-template': '🌐',
151
- 'fullstack-app': '⚡',
152
- 'go-wasm-app': '🔄',
153
- };
154
-
155
- // Detailed descriptions
156
- const templateDescriptions = {
157
- 'basic-app': 'Single-page application with just the essentials. Perfect for learning the framework or building simple apps.',
158
- 'ssr-template': 'Server-side rendered application with hydration. Optimized for SEO and fast initial load.',
159
- 'fullstack-app': 'Complete solution with API routes, authentication, and database integration ready to go.',
160
- 'go-wasm-app': 'WebAssembly integration with Go for high-performance computing in the browser and Node.js.'
161
- };
62
+ const templates = ['basic-app']; // Only frontend templates
162
63
 
163
64
  console.log(boxen(
164
65
  `${chalk.bold('Available Project Templates')}\n\n` +
165
- templates.map(template => {
166
- const icon = templateIcons[template] || '📦';
167
- const shortDesc = {
168
- 'basic-app': 'Simple client-side application',
169
- 'ssr-template': 'Server-side rendering with hydration',
170
- 'fullstack-app': 'Complete fullstack application with API'
171
- }[template] || 'Application template';
172
-
173
- return `${icon} ${chalk.cyan(template)}\n ${chalk.dim(shortDesc)}`;
174
- }).join('\n\n'),
66
+ `🚀 ${chalk.cyan('basic-app')}\n` +
67
+ ` Single-page application with client-side features`,
175
68
  {
176
69
  padding: 1,
177
70
  margin: 1,
@@ -180,129 +73,12 @@ async function chooseTemplate() {
180
73
  }
181
74
  ));
182
75
 
183
- const templateChoices = templates.map(template => ({
184
- name: `${templateIcons[template] || '📦'} ${chalk.bold(template)}`,
185
- value: template,
186
- description: templateDescriptions[template] || 'An application template'
187
- }));
188
-
189
- const answers = await inquirer.prompt([
190
- {
191
- type: 'list',
192
- name: 'template',
193
- message: chalk.green('Select a project template:'),
194
- choices: templateChoices,
195
- loop: false,
196
- pageSize: 10
197
- },
198
- {
199
- type: 'confirm',
200
- name: 'viewDetails',
201
- message: 'Would you like to see template details before proceeding?',
202
- default: false
203
- }
204
- ]);
205
-
206
- if (answers.viewDetails) {
207
- const detailedDescription = {
208
- 'basic-app': [
209
- `${chalk.bold('Basic App Template')} ${templateIcons['basic-app']}`,
210
- '',
211
- `${chalk.dim('A lightweight client-side application template.')}`,
212
- '',
213
- `${chalk.yellow('Features:')}`,
214
- '• No build step required for development',
215
- '• Built-in state management with hooks',
216
- '• Component-based architecture',
217
- '• Tailwind CSS integration',
218
- '',
219
- `${chalk.yellow('Best for:')}`,
220
- '• Simple web applications',
221
- '• Learning the framework',
222
- '• Quick prototyping',
223
- ],
224
- 'ssr-template': [
225
- `${chalk.bold('SSR Template')} ${templateIcons['ssr-template']}`,
226
- '',
227
- `${chalk.dim('Server-side rendering with client hydration.')}`,
228
- '',
229
- `${chalk.yellow('Features:')}`,
230
- '• React-like development experience',
231
- '• SEO-friendly rendered HTML',
232
- '• Fast initial page load',
233
- '• Smooth client-side transitions',
234
- '• Built-in dynamic meta tag generation',
235
- '',
236
- `${chalk.yellow('Best for:')}`,
237
- '• Production websites needing SEO',
238
- '• Content-focused applications',
239
- '• Sites requiring social sharing previews'
240
- ],
241
- 'fullstack-app': [
242
- `${chalk.bold('Fullstack App Template')} ${templateIcons['fullstack-app']}`,
243
- '',
244
- `${chalk.dim('Complete solution with frontend and backend.')}`,
245
- '',
246
- `${chalk.yellow('Features:')}`,
247
- '• API routes with Express integration',
248
- '• File-based routing system',
249
- '• Authentication system with JWT',
250
- '• Database connectors (MongoDB, MySQL, PostgreSQL)',
251
- '• Server-side rendering with hydration',
252
- '• WebSocket support',
253
- '',
254
- `${chalk.yellow('Best for:')}`,
255
- '• Full production applications',
256
- '• Apps needing authentication',
257
- '• Projects requiring database integration'
258
- ],
259
- 'go-wasm-app': [
260
- `${chalk.bold('Go WASM App Template')} ${templateIcons['go-wasm-app'] || '🔄'}`,
261
- '',
262
- `${chalk.dim('WebAssembly integration with Go programming language.')}`,
263
- '',
264
- `${chalk.yellow('Features:')}`,
265
- '• Go + WebAssembly integration',
266
- '• High-performance computation in browser',
267
- '• Server-side WASM processing',
268
- '• Shared code between Go and JavaScript',
269
- '• Optimized build pipeline',
270
- '',
271
- `${chalk.yellow('Best for:')}`,
272
- '• Computation-heavy applications',
273
- '• Projects requiring Go libraries',
274
- '• Performance-critical features'
275
- ]
276
- }[answers.template] || ['No detailed information available for this template'];
277
-
278
- console.log(boxen(detailedDescription.join('\n'), {
279
- padding: 1,
280
- margin: 1,
281
- title: answers.template,
282
- titleAlignment: 'center',
283
- borderStyle: 'round',
284
- borderColor: 'yellow'
285
- }));
286
-
287
- const proceed = await inquirer.prompt([{
288
- type: 'confirm',
289
- name: 'continue',
290
- message: 'Continue with this template?',
291
- default: true
292
- }]);
293
-
294
- if (!proceed.continue) {
295
- return chooseTemplate();
296
- }
297
- }
298
-
299
- return answers.template;
76
+ return 'basic-app'; // Default to basic-app for frontend-only
300
77
  }
301
78
 
302
- // Create a new project with enhanced visuals and status updates
79
+ // Create a new project
303
80
  async function createProject(projectName, options) {
304
81
  displayBanner();
305
- createSection('Project Setup');
306
82
 
307
83
  if (!projectName) {
308
84
  const answers = await inquirer.prompt([
@@ -320,8 +96,6 @@ async function createProject(projectName, options) {
320
96
  projectName = answers.projectName;
321
97
  }
322
98
 
323
- if (!await checkDependencies()) return;
324
-
325
99
  let template = options.template || await chooseTemplate();
326
100
 
327
101
  const targetDir = path.resolve(projectName);
@@ -342,73 +116,46 @@ async function createProject(projectName, options) {
342
116
  }
343
117
  }
344
118
 
345
- // Multi-step execution with progress reporting
346
- console.log(chalk.dim('\nCreating your new project...'));
119
+ const spinner = createSpinner('Creating project...').start();
347
120
 
348
- // Step 1: Create directory
349
- const step1 = ora({text: 'Creating project directory', color: 'cyan'}).start();
350
121
  try {
122
+ // Create directory and copy template
351
123
  await fs.ensureDir(targetDir);
352
- step1.succeed();
353
- } catch (error) {
354
- step1.fail();
355
- console.error(chalk.red(`Error creating directory: ${error.message}`));
356
- return;
357
- }
358
-
359
- // Step 2: Copy template files
360
- const step2 = ora({text: 'Copying template files', color: 'cyan'}).start();
361
- try {
362
124
  await fs.copy(templateDir, targetDir, { overwrite: true });
363
- step2.succeed();
364
- } catch (error) {
365
- step2.fail();
366
- console.error(chalk.red(`Error copying files: ${error.message}`));
367
- return;
368
- }
369
-
370
- // Step 3: Update package.json
371
- const step3 = ora({text: 'Configuring package.json', color: 'cyan'}).start();
372
- try {
125
+
126
+ // Update package.json
373
127
  const pkgJsonPath = path.join(targetDir, 'package.json');
374
128
  if (fs.existsSync(pkgJsonPath)) {
375
129
  const pkgJson = await fs.readJson(pkgJsonPath);
376
130
  pkgJson.name = projectName;
377
131
  await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
378
- step3.succeed();
379
- } else {
380
- step3.warn('No package.json found in template');
381
132
  }
133
+
134
+ spinner.success({ text: `Project created successfully!` });
135
+
136
+ console.log('\n' + boxen(
137
+ `${chalk.bold.green('Frontend project created!')}\n\n` +
138
+ `${chalk.bold('Project:')} ${chalk.cyan(projectName)}\n` +
139
+ `${chalk.bold('Template:')} ${chalk.cyan(template)}\n` +
140
+ `${chalk.bold('Type:')} Frontend-only application\n\n` +
141
+ `${chalk.bold.yellow('Next steps:')}\n\n` +
142
+ ` ${chalk.dim('1.')} ${chalk.cyan(`cd ${projectName}`)}\n` +
143
+ ` ${chalk.dim('2.')} ${chalk.cyan('npm install')}\n` +
144
+ ` ${chalk.dim('3.')} ${chalk.cyan('npm run dev')}\n\n` +
145
+ `${chalk.dim('Your app will run at:')} ${chalk.cyan('http://localhost:3000')}`,
146
+ {
147
+ padding: 1,
148
+ margin: 1,
149
+ borderStyle: 'round',
150
+ borderColor: 'green'
151
+ }
152
+ ));
382
153
  } catch (error) {
383
- step3.fail();
384
- console.error(chalk.red(`Error updating package.json: ${error.message}`));
385
- return;
154
+ spinner.error({ text: `Failed to create project: ${error.message}` });
386
155
  }
387
-
388
- // Final success message with helpful instructions
389
- console.log('\n' + boxen(
390
- `${chalk.bold.green('Project created successfully!')}\n\n` +
391
- `${chalk.bold('Project:')} ${chalk.cyan(projectName)}\n` +
392
- `${chalk.bold('Template:')} ${chalk.cyan(template)}\n` +
393
- `${chalk.bold('Location:')} ${chalk.cyan(targetDir)}\n\n` +
394
- `${chalk.bold.yellow('Next steps:')}\n\n` +
395
- ` ${chalk.dim('1.')} ${chalk.cyan(`cd ${projectName}`)}\n` +
396
- ` ${chalk.dim('2.')} ${chalk.cyan('npm install')}\n` +
397
- ` ${chalk.dim('3.')} ${chalk.cyan('npm run dev')}\n\n` +
398
- `${chalk.dim('For help and documentation:')} ${terminalLink('frontendhamroun.io', 'https://github.com/hamroun/frontend-hamroun')}`,
399
- {
400
- padding: 1,
401
- margin: 1,
402
- borderStyle: 'round',
403
- borderColor: 'green'
404
- }
405
- ));
406
-
407
- // Suggest next command
408
- console.log(`\n${chalk.cyan('Tip:')} Run ${chalk.bold.green(`cd ${projectName} && npm install`)} to get started right away.\n`);
409
156
  }
410
157
 
411
- // Add component with improved interactive experience
158
+ // Add component
412
159
  async function addComponent(componentName, options) {
413
160
  displayBanner();
414
161
  createSection('Create Component');
@@ -738,11 +485,11 @@ function showDashboard() {
738
485
  ));
739
486
  }
740
487
 
741
- // Register commands with improved descriptions
488
+ // Register commands
742
489
  program
743
490
  .command('create [name]')
744
491
  .description('Create a new Frontend Hamroun project')
745
- .option('-t, --template <template>', 'Specify template (basic-app, ssr-template, fullstack-app)')
492
+ .option('-t, --template <template>', 'Specify template (basic-app)')
746
493
  .action(createProject);
747
494
 
748
495
  program
@@ -753,569 +500,10 @@ program
753
500
  .option('-jsx, --jsx', 'Use JSX')
754
501
  .action(addComponent);
755
502
 
756
- program
757
- .command('add:page [name]')
758
- .description('Create a new page')
759
- .option('-p, --path <path>', 'Path where the page should be created')
760
- .option('-ts, --typescript', 'Use TypeScript')
761
- .option('-jsx, --jsx', 'Use JSX')
762
- .action((pageName, options) => {
763
- // We'll keep the existing implementation for now
764
- console.log("The add:page command has been improved in your version.");
765
- });
766
-
767
- program
768
- .command('add:api [name]')
769
- .description('Create a new API route')
770
- .option('-p, --path <path>', 'Path where the API route should be created')
771
- .option('-ts, --typescript', 'Use TypeScript')
772
- .option('-js, --javascript', 'Use JavaScript')
773
- .option('-m, --methods <methods>', 'HTTP methods to implement (comma-separated: get,post,put,delete,patch)')
774
- .action((routeName, options) => {
775
- // We'll keep the existing implementation for now
776
- console.log("The add:api command has been improved in your version.");
777
- });
778
-
779
- program
780
- .command('dev:tools')
781
- .description('Show development tools and tips')
782
- .action(async () => {
783
- displayBanner();
784
- createSection('Development Tools & Tips');
785
-
786
- // Check current project context
787
- const isInProject = fs.existsSync(path.join(process.cwd(), 'package.json'));
788
- let projectInfo = null;
789
-
790
- if (isInProject) {
791
- try {
792
- const packageJson = await fs.readJson(path.join(process.cwd(), 'package.json'));
793
- projectInfo = {
794
- name: packageJson.name,
795
- version: packageJson.version,
796
- isFrontendHamroun: packageJson.dependencies && packageJson.dependencies['frontend-hamroun']
797
- };
798
- } catch (error) {
799
- // Continue without project info
800
- }
801
- }
802
-
803
- // Show project status
804
- if (projectInfo) {
805
- console.log(boxen(
806
- `${chalk.bold('Current Project')}\n\n` +
807
- `${chalk.dim('Name:')} ${chalk.cyan(projectInfo.name)}\n` +
808
- `${chalk.dim('Version:')} ${chalk.cyan(projectInfo.version)}\n` +
809
- `${chalk.dim('Frontend Hamroun:')} ${projectInfo.isFrontendHamroun ? chalk.green('✓ Detected') : chalk.yellow('✗ Not detected')}`,
810
- {
811
- padding: 1,
812
- margin: 1,
813
- borderStyle: 'round',
814
- borderColor: projectInfo.isFrontendHamroun ? 'green' : 'yellow'
815
- }
816
- ));
817
- } else {
818
- console.log(boxen(
819
- `${chalk.yellow('⚠ No project detected')}\n\n` +
820
- `Run ${chalk.cyan('frontend-hamroun create my-app')} to create a new project.`,
821
- {
822
- padding: 1,
823
- margin: 1,
824
- borderStyle: 'round',
825
- borderColor: 'yellow'
826
- }
827
- ));
828
- }
829
-
830
- // Interactive tools menu
831
- const toolsMenu = await inquirer.prompt([
832
- {
833
- type: 'list',
834
- name: 'tool',
835
- message: chalk.green('Select a development tool:'),
836
- choices: [
837
- { name: '🔧 Performance Analysis', value: 'performance' },
838
- { name: '📊 Bundle Analyzer', value: 'bundle' },
839
- { name: '🧪 Testing Tools', value: 'testing' },
840
- { name: '🔍 Code Quality Check', value: 'quality' },
841
- { name: '📝 Project Templates', value: 'templates' },
842
- { name: '🚀 Deployment Guide', value: 'deployment' },
843
- { name: '🐛 Debug Helper', value: 'debug' },
844
- { name: '📚 Learning Resources', value: 'resources' },
845
- { name: '⚙️ Configuration Validator', value: 'config' },
846
- { name: '📈 Benchmark Runner', value: 'benchmark' }
847
- ],
848
- loop: false
849
- }
850
- ]);
851
-
852
- switch (toolsMenu.tool) {
853
- case 'performance':
854
- await showPerformanceTools();
855
- break;
856
- case 'bundle':
857
- await showBundleAnalyzer();
858
- break;
859
- case 'testing':
860
- await showTestingTools();
861
- break;
862
- case 'quality':
863
- await showCodeQuality();
864
- break;
865
- case 'templates':
866
- await showTemplateInfo();
867
- break;
868
- case 'deployment':
869
- await showDeploymentGuide();
870
- break;
871
- case 'debug':
872
- await showDebugHelper();
873
- break;
874
- case 'resources':
875
- await showLearningResources();
876
- break;
877
- case 'config':
878
- await showConfigValidator();
879
- break;
880
- case 'benchmark':
881
- await showBenchmarkRunner();
882
- break;
883
- }
884
- });
885
-
886
- // Performance analysis tools
887
- async function showPerformanceTools() {
888
- console.log(boxen(
889
- `${chalk.bold.cyan('🔧 Performance Analysis Tools')}\n\n` +
890
- `${chalk.bold('Bundle Size Analysis:')}\n` +
891
- `• ${chalk.cyan('npm run analyze')} - Analyze bundle composition\n` +
892
- `• ${chalk.cyan('npm run size-check')} - Check bundle size limits\n\n` +
893
- `${chalk.bold('Runtime Performance:')}\n` +
894
- `• ${chalk.cyan('npm run perf')} - Run performance benchmarks\n` +
895
- `• ${chalk.cyan('npm run lighthouse')} - Lighthouse audit\n\n` +
896
- `${chalk.bold('Memory Analysis:')}\n` +
897
- `• ${chalk.cyan('npm run memory-profile')} - Memory usage profiling\n` +
898
- `• ${chalk.cyan('npm run leak-detect')} - Memory leak detection\n\n` +
899
- `${chalk.bold('Recommended Tools:')}\n` +
900
- `• Chrome DevTools Performance tab\n` +
901
- `• React Profiler (if using React mode)\n` +
902
- `• Bundle Analyzer webpack plugin`,
903
- {
904
- padding: 1,
905
- margin: 1,
906
- borderStyle: 'round',
907
- borderColor: 'cyan'
908
- }
909
- ));
910
-
911
- const performanceCheck = await inquirer.prompt([
912
- {
913
- type: 'confirm',
914
- name: 'runAnalysis',
915
- message: 'Would you like to run a quick performance analysis?',
916
- default: false
917
- }
918
- ]);
919
-
920
- if (performanceCheck.runAnalysis) {
921
- const spinner = ora('Analyzing performance...').start();
922
-
923
- // Simulate performance analysis
924
- await new Promise(resolve => setTimeout(resolve, 2000));
925
-
926
- spinner.succeed('Performance analysis complete!');
927
-
928
- console.log(boxen(
929
- `${chalk.bold.green('Performance Report')}\n\n` +
930
- `${chalk.dim('Bundle Size:')} ${chalk.green('125.3 KB')} ${chalk.dim('(gzipped)')}\n` +
931
- `${chalk.dim('Load Time:')} ${chalk.green('1.2s')} ${chalk.dim('(3G connection)')}\n` +
932
- `${chalk.dim('First Paint:')} ${chalk.green('0.8s')}\n` +
933
- `${chalk.dim('Interactive:')} ${chalk.green('1.5s')}\n\n` +
934
- `${chalk.bold.yellow('Recommendations:')}\n` +
935
- `• Consider code splitting for large routes\n` +
936
- `• Enable compression on your server\n` +
937
- `• Optimize images and assets`,
938
- {
939
- padding: 1,
940
- margin: 1,
941
- borderStyle: 'round',
942
- borderColor: 'green'
943
- }
944
- ));
945
- }
946
- }
947
-
948
- // Bundle analyzer
949
- async function showBundleAnalyzer() {
950
- console.log(boxen(
951
- `${chalk.bold.cyan('📊 Bundle Analyzer')}\n\n` +
952
- `Analyze your application bundle to understand:\n` +
953
- `• Which modules take up the most space\n` +
954
- `• Duplicate dependencies\n` +
955
- `• Unused code\n` +
956
- `• Optimization opportunities\n\n` +
957
- `${chalk.bold('Commands:')}\n` +
958
- `• ${chalk.cyan('npm run build -- --analyze')} - Generate bundle report\n` +
959
- `• ${chalk.cyan('npm run bundle-visualizer')} - Interactive bundle explorer\n\n` +
960
- `${chalk.bold('Key Metrics to Watch:')}\n` +
961
- `• Total bundle size < 250KB (gzipped)\n` +
962
- `• Main chunk < 150KB\n` +
963
- `• No duplicate large libraries\n` +
964
- `• Tree shaking effectiveness > 80%`,
965
- {
966
- padding: 1,
967
- margin: 1,
968
- borderStyle: 'round',
969
- borderColor: 'cyan'
970
- }
971
- ));
972
- }
973
-
974
- // Testing tools
975
- async function showTestingTools() {
976
- console.log(boxen(
977
- `${chalk.bold.cyan('🧪 Testing Tools & Best Practices')}\n\n` +
978
- `${chalk.bold('Unit Testing:')}\n` +
979
- `• ${chalk.cyan('npm test')} - Run all tests\n` +
980
- `• ${chalk.cyan('npm run test:watch')} - Watch mode\n` +
981
- `• ${chalk.cyan('npm run test:coverage')} - Coverage report\n\n` +
982
- `${chalk.bold('E2E Testing:')}\n` +
983
- `• ${chalk.cyan('npm run e2e')} - End-to-end tests\n` +
984
- `• ${chalk.cyan('npm run e2e:headless')} - Headless mode\n\n` +
985
- `${chalk.bold('Component Testing:')}\n` +
986
- `• ${chalk.cyan('npm run test:components')} - Component tests\n` +
987
- `• ${chalk.cyan('npm run storybook')} - Component playground\n\n` +
988
- `${chalk.bold('Testing Utilities:')}\n` +
989
- `• @frontend-hamroun/testing-utils\n` +
990
- `• Jest with Frontend Hamroun preset\n` +
991
- `• Playwright for E2E testing`,
992
- {
993
- padding: 1,
994
- margin: 1,
995
- borderStyle: 'round',
996
- borderColor: 'cyan'
997
- }
998
- ));
999
-
1000
- const testExample = `// Example component test
1001
- import { render, screen } from '@frontend-hamroun/testing-utils';
1002
- import Button from '../Button';
1003
-
1004
- test('renders button with text', () => {
1005
- render(<Button>Click me</Button>);
1006
- expect(screen.getByText('Click me')).toBeInTheDocument();
1007
- });
1008
-
1009
- test('calls onClick when clicked', () => {
1010
- const handleClick = jest.fn();
1011
- render(<Button onClick={handleClick}>Click me</Button>);
1012
-
1013
- screen.getByText('Click me').click();
1014
- expect(handleClick).toHaveBeenCalledTimes(1);
1015
- });`;
1016
-
1017
- console.log(boxen(
1018
- `${chalk.bold('Example Test:')}\n\n${chalk.gray(testExample)}`,
1019
- {
1020
- padding: 1,
1021
- margin: 1,
1022
- borderStyle: 'round',
1023
- borderColor: 'gray'
1024
- }
1025
- ));
1026
- }
1027
-
1028
- // Code quality checker
1029
- async function showCodeQuality() {
1030
- console.log(boxen(
1031
- `${chalk.bold.cyan('🔍 Code Quality Tools')}\n\n` +
1032
- `${chalk.bold('Linting & Formatting:')}\n` +
1033
- `• ${chalk.cyan('npm run lint')} - ESLint check\n` +
1034
- `• ${chalk.cyan('npm run lint:fix')} - Auto-fix issues\n` +
1035
- `• ${chalk.cyan('npm run format')} - Prettier formatting\n\n` +
1036
- `${chalk.bold('Type Checking:')}\n` +
1037
- `• ${chalk.cyan('npm run type-check')} - TypeScript validation\n` +
1038
- `• ${chalk.cyan('npm run type-coverage')} - Type coverage report\n\n` +
1039
- `${chalk.bold('Security:')}\n` +
1040
- `• ${chalk.cyan('npm audit')} - Dependency security audit\n` +
1041
- `• ${chalk.cyan('npm run security-check')} - Security scan\n\n` +
1042
- `${chalk.bold('Quality Metrics:')}\n` +
1043
- `• Code coverage > 80%\n` +
1044
- `• Type coverage > 90%\n` +
1045
- `• No security vulnerabilities\n` +
1046
- `• ESLint score: A grade`,
1047
- {
1048
- padding: 1,
1049
- margin: 1,
1050
- borderStyle: 'round',
1051
- borderColor: 'cyan'
1052
- }
1053
- ));
1054
-
1055
- const qualityCheck = await inquirer.prompt([
1056
- {
1057
- type: 'confirm',
1058
- name: 'runCheck',
1059
- message: 'Would you like to run a code quality check?',
1060
- default: false
1061
- }
1062
- ]);
1063
-
1064
- if (qualityCheck.runCheck) {
1065
- const spinner = ora('Running code quality analysis...').start();
1066
-
1067
- // Simulate quality check
1068
- await new Promise(resolve => setTimeout(resolve, 3000));
1069
-
1070
- spinner.succeed('Code quality analysis complete!');
1071
-
1072
- console.log(boxen(
1073
- `${chalk.bold.green('Quality Report')}\n\n` +
1074
- `${chalk.dim('ESLint:')} ${chalk.green('✓ No issues')} ${chalk.dim('(0 errors, 0 warnings)')}\n` +
1075
- `${chalk.dim('TypeScript:')} ${chalk.green('✓ No type errors')}\n` +
1076
- `${chalk.dim('Security:')} ${chalk.green('✓ No vulnerabilities')}\n` +
1077
- `${chalk.dim('Test Coverage:')} ${chalk.green('87%')} ${chalk.dim('(target: 80%)')}\n` +
1078
- `${chalk.dim('Code Formatting:')} ${chalk.green('✓ Consistent')}\n\n` +
1079
- `${chalk.bold.green('Overall Grade: A+')}`,
1080
- {
1081
- padding: 1,
1082
- margin: 1,
1083
- borderStyle: 'round',
1084
- borderColor: 'green'
1085
- }
1086
- ));
1087
- }
1088
- }
1089
-
1090
- // Template information
1091
- async function showTemplateInfo() {
1092
- console.log(boxen(
1093
- `${chalk.bold.cyan('📝 Available Project Templates')}\n\n` +
1094
- `${chalk.bold('🚀 basic-app')}\n` +
1095
- `Single-page application with essential features\n` +
1096
- `• Client-side rendering\n` +
1097
- `• Component library\n` +
1098
- `• State management\n\n` +
1099
- `${chalk.bold('🌐 ssr-template')}\n` +
1100
- `Server-side rendering with hydration\n` +
1101
- `• SEO optimization\n` +
1102
- `• Fast initial load\n` +
1103
- `• Progressive enhancement\n\n` +
1104
- `${chalk.bold('⚡ fullstack-app')}\n` +
1105
- `Complete full-stack solution\n` +
1106
- `• API routes\n` +
1107
- `• Database integration\n` +
1108
- `• Authentication\n\n` +
1109
- `${chalk.bold('🔄 go-wasm-app')}\n` +
1110
- `WebAssembly integration with Go\n` +
1111
- `• High-performance computing\n` +
1112
- `• Go + JavaScript interop\n` +
1113
- `• Optimized builds`,
1114
- {
1115
- padding: 1,
1116
- margin: 1,
1117
- borderStyle: 'round',
1118
- borderColor: 'cyan'
1119
- }
1120
- ));
1121
-
1122
- console.log(`\n${chalk.dim('Create a new project:')} ${chalk.cyan('frontend-hamroun create my-app')}`);
1123
- }
1124
-
1125
- // Deployment guide
1126
- async function showDeploymentGuide() {
1127
- console.log(boxen(
1128
- `${chalk.bold.cyan('🚀 Deployment Guide')}\n\n` +
1129
- `${chalk.bold('Build for Production:')}\n` +
1130
- `• ${chalk.cyan('npm run build')} - Create production build\n` +
1131
- `• ${chalk.cyan('npm run build:analyze')} - Build with analysis\n\n` +
1132
- `${chalk.bold('Deployment Platforms:')}\n` +
1133
- `• ${chalk.green('Vercel:')} ${chalk.cyan('npm run deploy:vercel')}\n` +
1134
- `• ${chalk.green('Netlify:')} ${chalk.cyan('npm run deploy:netlify')}\n` +
1135
- `• ${chalk.green('Railway:')} ${chalk.cyan('npm run deploy:railway')}\n` +
1136
- `• ${chalk.green('Docker:')} ${chalk.cyan('docker build -t my-app .')}\n\n` +
1137
- `${chalk.bold('Environment Setup:')}\n` +
1138
- `• Configure environment variables\n` +
1139
- `• Set up SSL certificates\n` +
1140
- `• Configure CDN for static assets\n` +
1141
- `• Set up monitoring and analytics`,
1142
- {
1143
- padding: 1,
1144
- margin: 1,
1145
- borderStyle: 'round',
1146
- borderColor: 'cyan'
1147
- }
1148
- ));
1149
-
1150
- const deploymentExample = `# .env.production
1151
- NODE_ENV=production
1152
- API_URL=https://api.myapp.com
1153
- CDN_URL=https://cdn.myapp.com
1154
- ANALYTICS_ID=your-analytics-id`;
1155
-
1156
- console.log(boxen(
1157
- `${chalk.bold('Example Environment Config:')}\n\n${chalk.gray(deploymentExample)}`,
1158
- {
1159
- padding: 1,
1160
- margin: 1,
1161
- borderStyle: 'round',
1162
- borderColor: 'gray'
1163
- }
1164
- ));
1165
- }
1166
-
1167
- // Debug helper
1168
- async function showDebugHelper() {
1169
- console.log(boxen(
1170
- `${chalk.bold.cyan('🐛 Debug Helper')}\n\n` +
1171
- `${chalk.bold('Common Issues & Solutions:')}\n\n` +
1172
- `${chalk.yellow('• Component not rendering:')}\n` +
1173
- ` - Check JSX syntax\n` +
1174
- ` - Verify component import/export\n` +
1175
- ` - Check console for errors\n\n` +
1176
- `${chalk.yellow('• State not updating:')}\n` +
1177
- ` - Use functional state updates\n` +
1178
- ` - Check dependency arrays\n` +
1179
- ` - Verify state immutability\n\n` +
1180
- `${chalk.yellow('• Performance issues:')}\n` +
1181
- ` - Use React.memo for expensive components\n` +
1182
- ` - Implement useMemo for calculations\n` +
1183
- ` - Check for unnecessary re-renders\n\n` +
1184
- `${chalk.bold('Debug Tools:')}\n` +
1185
- `• ${chalk.cyan('npm run debug')} - Debug mode\n` +
1186
- `• Browser DevTools Extensions\n` +
1187
- `• Frontend Hamroun DevTools\n` +
1188
- `• Performance Profiler`,
1189
- {
1190
- padding: 1,
1191
- margin: 1,
1192
- borderStyle: 'round',
1193
- borderColor: 'cyan'
1194
- }
1195
- ));
1196
- }
1197
-
1198
- // Learning resources
1199
- async function showLearningResources() {
1200
- console.log(boxen(
1201
- `${chalk.bold.cyan('📚 Learning Resources')}\n\n` +
1202
- `${chalk.bold('Official Documentation:')}\n` +
1203
- `• ${terminalLink('Getting Started', 'https://github.com/hamroun/frontend-hamroun')}\n` +
1204
- `• ${terminalLink('API Reference', 'https://github.com/hamroun/frontend-hamroun/docs')}\n` +
1205
- `• ${terminalLink('Examples', 'https://github.com/hamroun/frontend-hamroun/examples')}\n\n` +
1206
- `${chalk.bold('Tutorials:')}\n` +
1207
- `• Building Your First App\n` +
1208
- `• State Management Patterns\n` +
1209
- `• Performance Optimization\n` +
1210
- `• Testing Best Practices\n\n` +
1211
- `${chalk.bold('Community:')}\n` +
1212
- `• ${terminalLink('Discord Server', 'https://discord.gg/frontend-hamroun')}\n` +
1213
- `• ${terminalLink('GitHub Discussions', 'https://github.com/hamroun/frontend-hamroun/discussions')}\n` +
1214
- `• ${terminalLink('Stack Overflow', 'https://stackoverflow.com/questions/tagged/frontend-hamroun')}\n\n` +
1215
- `${chalk.bold('Video Content:')}\n` +
1216
- `• YouTube Channel\n` +
1217
- `• Conference Talks\n` +
1218
- `• Live Coding Sessions`,
1219
- {
1220
- padding: 1,
1221
- margin: 1,
1222
- borderStyle: 'round',
1223
- borderColor: 'cyan'
1224
- }
1225
- ));
1226
- }
1227
-
1228
- // Configuration validator
1229
- async function showConfigValidator() {
1230
- const spinner = ora('Validating project configuration...').start();
1231
-
1232
- // Simulate config validation
1233
- await new Promise(resolve => setTimeout(resolve, 2000));
1234
-
1235
- spinner.succeed('Configuration validation complete!');
1236
-
1237
- console.log(boxen(
1238
- `${chalk.bold.green('Configuration Status')}\n\n` +
1239
- `${chalk.dim('package.json:')} ${chalk.green('✓ Valid')}\n` +
1240
- `${chalk.dim('tsconfig.json:')} ${chalk.green('✓ Valid')}\n` +
1241
- `${chalk.dim('hamroun.config.js:')} ${chalk.green('✓ Valid')}\n` +
1242
- `${chalk.dim('ESLint config:')} ${chalk.green('✓ Valid')}\n` +
1243
- `${chalk.dim('Environment variables:')} ${chalk.yellow('⚠ Missing some optional vars')}\n\n` +
1244
- `${chalk.bold.yellow('Recommendations:')}\n` +
1245
- `• Add ANALYTICS_ID environment variable\n` +
1246
- `• Consider enabling strict mode in TypeScript\n` +
1247
- `• Update ESLint rules for better practices`,
1248
- {
1249
- padding: 1,
1250
- margin: 1,
1251
- borderStyle: 'round',
1252
- borderColor: 'green'
1253
- }
1254
- ));
1255
- }
1256
-
1257
- // Benchmark runner
1258
- async function showBenchmarkRunner() {
1259
- console.log(boxen(
1260
- `${chalk.bold.cyan('📈 Benchmark Runner')}\n\n` +
1261
- `Run performance benchmarks to compare:\n` +
1262
- `• Rendering performance vs other frameworks\n` +
1263
- `• Bundle size comparisons\n` +
1264
- `• Memory usage analysis\n` +
1265
- `• Runtime performance metrics\n\n` +
1266
- `${chalk.bold('Available Benchmarks:')}\n` +
1267
- `• ${chalk.cyan('npm run bench:render')} - Rendering performance\n` +
1268
- `• ${chalk.cyan('npm run bench:bundle')} - Bundle size comparison\n` +
1269
- `• ${chalk.cyan('npm run bench:memory')} - Memory usage\n` +
1270
- `• ${chalk.cyan('npm run bench:all')} - Full benchmark suite`,
1271
- {
1272
- padding: 1,
1273
- margin: 1,
1274
- borderStyle: 'round',
1275
- borderColor: 'cyan'
1276
- }
1277
- ));
1278
-
1279
- const runBenchmark = await inquirer.prompt([
1280
- {
1281
- type: 'confirm',
1282
- name: 'run',
1283
- message: 'Would you like to run a quick benchmark?',
1284
- default: false
1285
- }
1286
- ]);
1287
-
1288
- if (runBenchmark.run) {
1289
- const spinner = ora('Running performance benchmarks...').start();
1290
-
1291
- // Simulate benchmark
1292
- await new Promise(resolve => setTimeout(resolve, 4000));
1293
-
1294
- spinner.succeed('Benchmark complete!');
1295
-
1296
- console.log(boxen(
1297
- `${chalk.bold.green('Benchmark Results')}\n\n` +
1298
- `${chalk.dim('Rendering (1000 components):')} ${chalk.green('23.4ms')}\n` +
1299
- `${chalk.dim('Bundle size (gzipped):')} ${chalk.green('125.3 KB')}\n` +
1300
- `${chalk.dim('Memory usage (peak):')} ${chalk.green('45.2 MB')}\n` +
1301
- `${chalk.dim('First paint:')} ${chalk.green('0.8s')}\n` +
1302
- `${chalk.dim('Interactive:')} ${chalk.green('1.2s')}\n\n` +
1303
- `${chalk.bold.green('Performance Grade: A')}\n\n` +
1304
- `${chalk.dim('Comparison with React:')} ${chalk.green('18% faster')}\n` +
1305
- `${chalk.dim('Comparison with Vue:')} ${chalk.green('12% faster')}`,
1306
- {
1307
- padding: 1,
1308
- margin: 1,
1309
- borderStyle: 'round',
1310
- borderColor: 'green'
1311
- }
1312
- ));
1313
- }
1314
- }
1315
-
1316
503
  // Default command when no arguments
1317
504
  if (process.argv.length <= 2) {
1318
- showDashboard();
505
+ displayBanner();
506
+ console.log('\n' + chalk.cyan('Get started with:') + ' ' + chalk.yellow('frontend-hamroun create my-app'));
1319
507
  } else {
1320
508
  program.parse(process.argv);
1321
509
  }