frontend-hamroun 1.2.0 → 1.2.2

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.
package/bin/cli.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ try {
7
+ // Try to load the ESM version
8
+ import('../dist/cli/index.js')
9
+ .catch(err => {
10
+ console.error('Failed to load CLI:', err);
11
+ process.exit(1);
12
+ });
13
+ } catch (error) {
14
+ console.error('Error loading CLI:', error);
15
+ process.exit(1);
16
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli/index.js CHANGED
@@ -1 +1,215 @@
1
- "use strict";
1
+ #!/usr/bin/env node
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { execSync } from 'child_process';
6
+ import readline from 'readline';
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ // Get package.json to read version
10
+ const packageJsonPath = path.resolve(__dirname, '../../package.json');
11
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
12
+ // Available templates
13
+ const TEMPLATES = {
14
+ 'basic': 'Basic frontend only template',
15
+ 'full-stack': 'Complete frontend and backend template',
16
+ 'api-only': 'Backend API only template'
17
+ };
18
+ // CLI colors
19
+ const colors = {
20
+ reset: '\x1b[0m',
21
+ bright: '\x1b[1m',
22
+ green: '\x1b[32m',
23
+ blue: '\x1b[34m',
24
+ red: '\x1b[31m',
25
+ yellow: '\x1b[33m'
26
+ };
27
+ // Create readline interface
28
+ function createInterface() {
29
+ return readline.createInterface({
30
+ input: process.stdin,
31
+ output: process.stdout
32
+ });
33
+ }
34
+ // Print banner
35
+ function printBanner() {
36
+ console.log(`
37
+ ${colors.blue}${colors.bright}╔══════════════════════════════════════════════╗
38
+ ║ ║
39
+ ║ Frontend Hamroun v${packageJson.version.padEnd(25)}║
40
+ ║ A lightweight frontend & backend framework ║
41
+ ║ ║
42
+ ╚══════════════════════════════════════════════╝${colors.reset}
43
+ `);
44
+ }
45
+ // Print help
46
+ function printHelp() {
47
+ console.log(`
48
+ ${colors.bright}USAGE:${colors.reset}
49
+ ${colors.blue}npx frontend-hamroun${colors.reset} [command] [options]
50
+
51
+ ${colors.bright}COMMANDS:${colors.reset}
52
+ ${colors.blue}create${colors.reset} <project-name> [options] Create a new project
53
+ ${colors.blue}help${colors.reset} Display this help message
54
+ ${colors.blue}version${colors.reset} Display version information
55
+
56
+ ${colors.bright}OPTIONS:${colors.reset}
57
+ ${colors.blue}--template${colors.reset}, ${colors.blue}-t${colors.reset} <template> Specify template (default: basic)
58
+ ${colors.blue}--skip-install${colors.reset}, ${colors.blue}-s${colors.reset} Skip package installation
59
+
60
+ ${colors.bright}AVAILABLE TEMPLATES:${colors.reset}
61
+ ${Object.entries(TEMPLATES).map(([name, desc]) => ` ${colors.blue}${name.padEnd(12)}${colors.reset} ${desc}`).join('\n')}
62
+
63
+ ${colors.bright}EXAMPLES:${colors.reset}
64
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app
65
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app --template full-stack
66
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-api -t api-only --skip-install
67
+ `);
68
+ }
69
+ // Create project from template
70
+ async function createProject(projectName, options) {
71
+ const template = options.template || 'basic';
72
+ // Check if template exists
73
+ if (!Object.keys(TEMPLATES).includes(template)) {
74
+ console.error(`${colors.red}error:${colors.reset} Template "${template}" not found.`);
75
+ console.log(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`);
76
+ process.exit(1);
77
+ }
78
+ // Check if project directory already exists
79
+ const projectPath = path.resolve(process.cwd(), projectName);
80
+ if (fs.existsSync(projectPath)) {
81
+ console.error(`${colors.red}error:${colors.reset} Directory ${projectName} already exists.`);
82
+ process.exit(1);
83
+ }
84
+ console.log(`
85
+ ${colors.bright}Creating a new project with Frontend Hamroun...${colors.reset}
86
+ ${colors.blue}• Project name:${colors.reset} ${projectName}
87
+ ${colors.blue}• Template:${colors.reset} ${template}
88
+ ${colors.blue}• Directory:${colors.reset} ${projectPath}
89
+ `);
90
+ try {
91
+ // Find templates directory
92
+ const templateDir = path.resolve(__dirname, '../../templates', template);
93
+ // Create project directory
94
+ fs.mkdirSync(projectPath, { recursive: true });
95
+ // Copy template files
96
+ copyTemplateFiles(templateDir, projectPath);
97
+ // Update package.json with project name
98
+ const projectPackageJsonPath = path.join(projectPath, 'package.json');
99
+ if (fs.existsSync(projectPackageJsonPath)) {
100
+ const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
101
+ projectPackageJson.name = projectName;
102
+ fs.writeFileSync(projectPackageJsonPath, JSON.stringify(projectPackageJson, null, 2));
103
+ }
104
+ // Install dependencies
105
+ if (!options.skipInstall) {
106
+ console.log(`\n${colors.blue}Installing dependencies...${colors.reset}`);
107
+ const command = getPackageManager() === 'yarn'
108
+ ? 'yarn'
109
+ : 'npm install';
110
+ execSync(command, {
111
+ cwd: projectPath,
112
+ stdio: 'inherit'
113
+ });
114
+ }
115
+ // Success message
116
+ console.log(`
117
+ ${colors.green}${colors.bright}Success!${colors.reset} Created ${projectName} at ${projectPath}
118
+
119
+ ${colors.blue}Inside that directory, you can run several commands:${colors.reset}
120
+
121
+ ${colors.bright}npm run dev${colors.reset}
122
+ Starts the development server.
123
+
124
+ ${colors.bright}npm run build${colors.reset}
125
+ Builds the app for production.
126
+
127
+ ${colors.bright}npm start${colors.reset}
128
+ Runs the built app in production mode.
129
+
130
+ ${colors.blue}We suggest that you begin by typing:${colors.reset}
131
+
132
+ ${colors.bright}cd${colors.reset} ${projectName}
133
+ ${colors.bright}npm run dev${colors.reset}
134
+
135
+ ${colors.green}Happy coding!${colors.reset}
136
+ `);
137
+ }
138
+ catch (error) {
139
+ console.error(`${colors.red}Failed to create project:${colors.reset}`, error);
140
+ process.exit(1);
141
+ }
142
+ }
143
+ // Copy template files recursively
144
+ function copyTemplateFiles(source, destination) {
145
+ const files = fs.readdirSync(source);
146
+ for (const file of files) {
147
+ const sourcePath = path.join(source, file);
148
+ const destPath = path.join(destination, file);
149
+ const stats = fs.statSync(sourcePath);
150
+ if (stats.isDirectory()) {
151
+ fs.mkdirSync(destPath, { recursive: true });
152
+ copyTemplateFiles(sourcePath, destPath);
153
+ }
154
+ else {
155
+ fs.copyFileSync(sourcePath, destPath);
156
+ }
157
+ }
158
+ console.log(`${colors.green}•${colors.reset} Copied template files`);
159
+ }
160
+ // Detect package manager
161
+ function getPackageManager() {
162
+ try {
163
+ const userAgent = process.env.npm_config_user_agent;
164
+ if (userAgent && userAgent.startsWith('yarn')) {
165
+ return 'yarn';
166
+ }
167
+ return 'npm';
168
+ }
169
+ catch (error) {
170
+ return 'npm';
171
+ }
172
+ }
173
+ // Parse command line arguments
174
+ function parseArgs() {
175
+ const args = process.argv.slice(2);
176
+ const command = args[0];
177
+ if (!command || command === 'help') {
178
+ printBanner();
179
+ printHelp();
180
+ process.exit(0);
181
+ }
182
+ if (command === 'version') {
183
+ console.log(`frontend-hamroun v${packageJson.version}`);
184
+ process.exit(0);
185
+ }
186
+ if (command === 'create') {
187
+ const projectName = args[1];
188
+ if (!projectName) {
189
+ console.error(`${colors.red}error:${colors.reset} Project name is required.`);
190
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
191
+ process.exit(1);
192
+ }
193
+ // Parse options
194
+ const options = {
195
+ template: 'basic',
196
+ skipInstall: false
197
+ };
198
+ for (let i = 2; i < args.length; i++) {
199
+ if (args[i] === '--template' || args[i] === '-t') {
200
+ options.template = args[++i];
201
+ }
202
+ else if (args[i] === '--skip-install' || args[i] === '-s') {
203
+ options.skipInstall = true;
204
+ }
205
+ }
206
+ printBanner();
207
+ createProject(projectName, options);
208
+ return;
209
+ }
210
+ console.error(`${colors.red}error:${colors.reset} Unknown command: ${command}`);
211
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
212
+ process.exit(1);
213
+ }
214
+ // Run CLI
215
+ parseArgs();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontend-hamroun",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "A lightweight frontend and backend framework for building modern web applications",
5
5
  "type": "module",
6
6
  "main": "dist/frontend-hamroun.umd.js",
@@ -11,6 +11,7 @@
11
11
  "src",
12
12
  "templates",
13
13
  "scripts",
14
+ "bin",
14
15
  "LICENSE",
15
16
  "README.md"
16
17
  ],
@@ -22,16 +23,19 @@
22
23
  }
23
24
  },
24
25
  "bin": {
25
- "hamroun": "src/cli/index.js"
26
+ "hamroun": "./bin/cli.js",
27
+ "frontend-hamroun": "./bin/cli.js"
26
28
  },
27
29
  "scripts": {
28
30
  "dev": "vite",
29
- "build": "vite build && tsc",
31
+ "build": "vite build && tsc && npm run build:cli",
32
+ "build:cli": "node scripts/build-cli.js",
33
+ "prepublishOnly": "npm run build",
30
34
  "test": "jest",
31
- "clean": "rimraf dist",
35
+ "clean": "rimraf dist bin",
32
36
  "prebuild": "npm run clean",
33
- "prepublish": "npm run build",
34
- "generate": "node scripts/generate.js"
37
+ "generate": "node scripts/generate.js",
38
+ "publish:next": "npm publish --tag next"
35
39
  },
36
40
  "keywords": [
37
41
  "frontend",
@@ -0,0 +1,205 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { execSync } from 'child_process';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const rootDir = path.resolve(__dirname, '..');
9
+ const binDir = path.resolve(rootDir, 'bin');
10
+
11
+ // Ensure bin directory exists
12
+ if (!fs.existsSync(binDir)) {
13
+ fs.mkdirSync(binDir, { recursive: true });
14
+ }
15
+
16
+ // Create a simple CLI wrapper that doesn't rely on TypeScript
17
+ const cliContent = `#!/usr/bin/env node
18
+
19
+ const path = require('path');
20
+ const fs = require('fs');
21
+
22
+ try {
23
+ // Try to load the ESM version
24
+ import('../dist/cli/index.js')
25
+ .catch(err => {
26
+ console.error('Failed to load CLI:', err);
27
+ process.exit(1);
28
+ });
29
+ } catch (error) {
30
+ console.error('Error loading CLI:', error);
31
+ process.exit(1);
32
+ }
33
+ `;
34
+
35
+ // Write CLI file
36
+ fs.writeFileSync(path.join(binDir, 'cli.js'), cliContent, 'utf8');
37
+
38
+ // Make CLI executable
39
+ try {
40
+ fs.chmodSync(path.join(binDir, 'cli.js'), '755');
41
+ console.log('✅ CLI wrapper built successfully: bin/cli.js');
42
+ } catch (error) {
43
+ console.warn('⚠️ Could not make CLI executable:', error);
44
+ }
45
+
46
+ // Copy the CLI code to dist directory and compile it
47
+ console.log('🔨 Compiling CLI TypeScript...');
48
+ try {
49
+ // Ensure dist/cli directory exists
50
+ const distCliDir = path.resolve(rootDir, 'dist/cli');
51
+ if (!fs.existsSync(distCliDir)) {
52
+ fs.mkdirSync(distCliDir, { recursive: true });
53
+ }
54
+
55
+ // Extract TypeScript files needed for CLI
56
+ const tscCommand = `npx tsc src/cli/index.ts --outDir dist/cli --esModuleInterop --target ES2020 --module NodeNext --moduleResolution NodeNext`;
57
+
58
+ // Execute TypeScript compilation
59
+ execSync(tscCommand, { stdio: 'inherit' });
60
+
61
+ console.log('✅ CLI TypeScript compiled successfully');
62
+ } catch (error) {
63
+ console.error('❌ Failed to compile CLI TypeScript:', error);
64
+
65
+ // Create a fallback CLI if TypeScript compilation fails
66
+ console.log('⚠️ Creating fallback CommonJS CLI...');
67
+
68
+ const fallbackCli = `
69
+ // This is a fallback CLI implementation when TypeScript compilation fails
70
+ const fs = require('fs');
71
+ const path = require('path');
72
+ const { execSync } = require('child_process');
73
+
74
+ const packageJsonPath = path.resolve(__dirname, '../../package.json');
75
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
76
+
77
+ // Available templates
78
+ const TEMPLATES = {
79
+ 'basic': 'Basic frontend only template',
80
+ 'full-stack': 'Complete frontend and backend template'
81
+ };
82
+
83
+ // Colors for console output
84
+ const colors = {
85
+ reset: '\\x1b[0m',
86
+ bright: '\\x1b[1m',
87
+ green: '\\x1b[32m',
88
+ blue: '\\x1b[34m',
89
+ red: '\\x1b[31m'
90
+ };
91
+
92
+ console.log(\`
93
+ \${colors.blue}\${colors.bright}╔══════════════════════════════════════════════╗
94
+ ║ ║
95
+ ║ Frontend Hamroun v\${packageJson.version.padEnd(25)}║
96
+ ║ A lightweight frontend & backend framework ║
97
+ ║ ║
98
+ ╚══════════════════════════════════════════════╝\${colors.reset}
99
+ \`);
100
+
101
+ const args = process.argv.slice(2);
102
+ const command = args[0];
103
+
104
+ if (!command || command === 'help') {
105
+ console.log(\`
106
+ \${colors.bright}USAGE:\${colors.reset}
107
+ \${colors.blue}npx frontend-hamroun\${colors.reset} create <project-name> [--template <template>]
108
+
109
+ \${colors.bright}AVAILABLE TEMPLATES:\${colors.reset}
110
+ \${colors.blue}basic\${colors.reset} Basic frontend only template
111
+ \${colors.blue}full-stack\${colors.reset} Complete frontend and backend template
112
+ \`);
113
+ process.exit(0);
114
+ }
115
+
116
+ if (command === 'create') {
117
+ const projectName = args[1];
118
+
119
+ if (!projectName) {
120
+ console.error(\`\${colors.red}Error:\${colors.reset} Project name is required\`);
121
+ process.exit(1);
122
+ }
123
+
124
+ let template = 'basic';
125
+ for (let i = 2; i < args.length; i++) {
126
+ if (args[i] === '--template' || args[i] === '-t') {
127
+ template = args[++i] || 'basic';
128
+ }
129
+ }
130
+
131
+ if (!Object.keys(TEMPLATES).includes(template)) {
132
+ console.error(\`\${colors.red}Error:\${colors.reset} Template "\${template}" not found\`);
133
+ console.log(\`Available templates: \${Object.keys(TEMPLATES).join(', ')}\`);
134
+ process.exit(1);
135
+ }
136
+
137
+ console.log(\`Creating new \${template} project: \${projectName}...\`);
138
+
139
+ try {
140
+ // Create project directory
141
+ const projectPath = path.resolve(process.cwd(), projectName);
142
+ fs.mkdirSync(projectPath, { recursive: true });
143
+
144
+ // Create minimal package.json
145
+ const pkgJson = {
146
+ "name": projectName,
147
+ "version": "0.1.0",
148
+ "private": true,
149
+ "dependencies": {
150
+ "frontend-hamroun": packageJson.version
151
+ },
152
+ "scripts": {
153
+ "dev": "vite",
154
+ "build": "vite build"
155
+ }
156
+ };
157
+
158
+ fs.writeFileSync(
159
+ path.join(projectPath, 'package.json'),
160
+ JSON.stringify(pkgJson, null, 2)
161
+ );
162
+
163
+ console.log(\`
164
+ \${colors.green}\${colors.bright}Success!\${colors.reset} Created project at \${projectPath}
165
+
166
+ \${colors.blue}Next steps:\${colors.reset}
167
+ cd \${projectName}
168
+ npm install
169
+ npm run dev
170
+ \`);
171
+
172
+ } catch (error) {
173
+ console.error(\`\${colors.red}Failed to create project:\${colors.reset}\`, error);
174
+ process.exit(1);
175
+ }
176
+ } else {
177
+ console.error(\`\${colors.red}Unknown command:\${colors.reset} \${command}\`);
178
+ process.exit(1);
179
+ }
180
+ `;
181
+
182
+ const distCliDir = path.resolve(rootDir, 'dist/cli');
183
+ if (!fs.existsSync(distCliDir)) {
184
+ fs.mkdirSync(distCliDir, { recursive: true });
185
+ }
186
+
187
+ fs.writeFileSync(path.join(distCliDir, 'index.js'), fallbackCli, 'utf8');
188
+ console.log('✅ Fallback CLI created successfully');
189
+ }
190
+
191
+ // Let's make sure we also have template directories
192
+ const templatesDir = path.resolve(rootDir, 'templates');
193
+ const templateList = ['basic', 'full-stack'];
194
+
195
+ console.log('🔍 Checking template directories...');
196
+ for (const template of templateList) {
197
+ const templateDir = path.join(templatesDir, template);
198
+ if (!fs.existsSync(templateDir)) {
199
+ console.log(`⚠️ Template directory not found: ${templateDir}`);
200
+ } else {
201
+ console.log(`✅ Template found: ${template}`);
202
+ }
203
+ }
204
+
205
+ console.log('✅ CLI build process completed');
package/src/cli/index.ts CHANGED
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { execSync } from 'child_process';
7
+ import readline from 'readline';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ // Get package.json to read version
13
+ const packageJsonPath = path.resolve(__dirname, '../../package.json');
14
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
15
+
16
+ // Define interfaces for type safety
17
+ interface ProjectOptions {
18
+ template: string;
19
+ skipInstall: boolean;
20
+ }
21
+
22
+ // Available templates
23
+ const TEMPLATES: Record<string, string> = {
24
+ 'basic': 'Basic frontend only template',
25
+ 'full-stack': 'Complete frontend and backend template',
26
+ 'api-only': 'Backend API only template'
27
+ };
28
+
29
+ // CLI colors
30
+ const colors = {
31
+ reset: '\x1b[0m',
32
+ bright: '\x1b[1m',
33
+ green: '\x1b[32m',
34
+ blue: '\x1b[34m',
35
+ red: '\x1b[31m',
36
+ yellow: '\x1b[33m'
37
+ };
38
+
39
+ // Create readline interface
40
+ function createInterface(): readline.Interface {
41
+ return readline.createInterface({
42
+ input: process.stdin,
43
+ output: process.stdout
44
+ });
45
+ }
46
+
47
+ // Print banner
48
+ function printBanner(): void {
49
+ console.log(`
50
+ ${colors.blue}${colors.bright}╔══════════════════════════════════════════════╗
51
+ ║ ║
52
+ ║ Frontend Hamroun v${packageJson.version.padEnd(25)}║
53
+ ║ A lightweight frontend & backend framework ║
54
+ ║ ║
55
+ ╚══════════════════════════════════════════════╝${colors.reset}
56
+ `);
57
+ }
58
+
59
+ // Print help
60
+ function printHelp(): void {
61
+ console.log(`
62
+ ${colors.bright}USAGE:${colors.reset}
63
+ ${colors.blue}npx frontend-hamroun${colors.reset} [command] [options]
64
+
65
+ ${colors.bright}COMMANDS:${colors.reset}
66
+ ${colors.blue}create${colors.reset} <project-name> [options] Create a new project
67
+ ${colors.blue}help${colors.reset} Display this help message
68
+ ${colors.blue}version${colors.reset} Display version information
69
+
70
+ ${colors.bright}OPTIONS:${colors.reset}
71
+ ${colors.blue}--template${colors.reset}, ${colors.blue}-t${colors.reset} <template> Specify template (default: basic)
72
+ ${colors.blue}--skip-install${colors.reset}, ${colors.blue}-s${colors.reset} Skip package installation
73
+
74
+ ${colors.bright}AVAILABLE TEMPLATES:${colors.reset}
75
+ ${Object.entries(TEMPLATES).map(([name, desc]) => ` ${colors.blue}${name.padEnd(12)}${colors.reset} ${desc}`).join('\n')}
76
+
77
+ ${colors.bright}EXAMPLES:${colors.reset}
78
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app
79
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app --template full-stack
80
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-api -t api-only --skip-install
81
+ `);
82
+ }
83
+
84
+ // Create project from template
85
+ async function createProject(projectName: string, options: ProjectOptions): Promise<void> {
86
+ const template = options.template || 'basic';
87
+
88
+ // Check if template exists
89
+ if (!Object.keys(TEMPLATES).includes(template)) {
90
+ console.error(`${colors.red}error:${colors.reset} Template "${template}" not found.`);
91
+ console.log(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`);
92
+ process.exit(1);
93
+ }
94
+
95
+ // Check if project directory already exists
96
+ const projectPath = path.resolve(process.cwd(), projectName);
97
+ if (fs.existsSync(projectPath)) {
98
+ console.error(`${colors.red}error:${colors.reset} Directory ${projectName} already exists.`);
99
+ process.exit(1);
100
+ }
101
+
102
+ console.log(`
103
+ ${colors.bright}Creating a new project with Frontend Hamroun...${colors.reset}
104
+ ${colors.blue}• Project name:${colors.reset} ${projectName}
105
+ ${colors.blue}• Template:${colors.reset} ${template}
106
+ ${colors.blue}• Directory:${colors.reset} ${projectPath}
107
+ `);
108
+
109
+ try {
110
+ // Find templates directory
111
+ const templateDir = path.resolve(__dirname, '../../templates', template);
112
+
113
+ // Create project directory
114
+ fs.mkdirSync(projectPath, { recursive: true });
115
+
116
+ // Copy template files
117
+ copyTemplateFiles(templateDir, projectPath);
118
+
119
+ // Update package.json with project name
120
+ const projectPackageJsonPath = path.join(projectPath, 'package.json');
121
+ if (fs.existsSync(projectPackageJsonPath)) {
122
+ const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
123
+ projectPackageJson.name = projectName;
124
+ fs.writeFileSync(
125
+ projectPackageJsonPath,
126
+ JSON.stringify(projectPackageJson, null, 2)
127
+ );
128
+ }
129
+
130
+ // Install dependencies
131
+ if (!options.skipInstall) {
132
+ console.log(`\n${colors.blue}Installing dependencies...${colors.reset}`);
133
+
134
+ const command = getPackageManager() === 'yarn'
135
+ ? 'yarn'
136
+ : 'npm install';
137
+
138
+ execSync(command, {
139
+ cwd: projectPath,
140
+ stdio: 'inherit'
141
+ });
142
+ }
143
+
144
+ // Success message
145
+ console.log(`
146
+ ${colors.green}${colors.bright}Success!${colors.reset} Created ${projectName} at ${projectPath}
147
+
148
+ ${colors.blue}Inside that directory, you can run several commands:${colors.reset}
149
+
150
+ ${colors.bright}npm run dev${colors.reset}
151
+ Starts the development server.
152
+
153
+ ${colors.bright}npm run build${colors.reset}
154
+ Builds the app for production.
155
+
156
+ ${colors.bright}npm start${colors.reset}
157
+ Runs the built app in production mode.
158
+
159
+ ${colors.blue}We suggest that you begin by typing:${colors.reset}
160
+
161
+ ${colors.bright}cd${colors.reset} ${projectName}
162
+ ${colors.bright}npm run dev${colors.reset}
163
+
164
+ ${colors.green}Happy coding!${colors.reset}
165
+ `);
166
+
167
+ } catch (error) {
168
+ console.error(`${colors.red}Failed to create project:${colors.reset}`, error);
169
+ process.exit(1);
170
+ }
171
+ }
172
+
173
+ // Copy template files recursively
174
+ function copyTemplateFiles(source: string, destination: string): void {
175
+ const files = fs.readdirSync(source);
176
+
177
+ for (const file of files) {
178
+ const sourcePath = path.join(source, file);
179
+ const destPath = path.join(destination, file);
180
+
181
+ const stats = fs.statSync(sourcePath);
182
+
183
+ if (stats.isDirectory()) {
184
+ fs.mkdirSync(destPath, { recursive: true });
185
+ copyTemplateFiles(sourcePath, destPath);
186
+ } else {
187
+ fs.copyFileSync(sourcePath, destPath);
188
+ }
189
+ }
190
+
191
+ console.log(`${colors.green}•${colors.reset} Copied template files`);
192
+ }
193
+
194
+ // Detect package manager
195
+ function getPackageManager(): string {
196
+ try {
197
+ const userAgent = process.env.npm_config_user_agent;
198
+ if (userAgent && userAgent.startsWith('yarn')) {
199
+ return 'yarn';
200
+ }
201
+ return 'npm';
202
+ } catch (error) {
203
+ return 'npm';
204
+ }
205
+ }
206
+
207
+ // Parse command line arguments
208
+ function parseArgs(): void {
209
+ const args = process.argv.slice(2);
210
+ const command = args[0];
211
+
212
+ if (!command || command === 'help') {
213
+ printBanner();
214
+ printHelp();
215
+ process.exit(0);
216
+ }
217
+
218
+ if (command === 'version') {
219
+ console.log(`frontend-hamroun v${packageJson.version}`);
220
+ process.exit(0);
221
+ }
222
+
223
+ if (command === 'create') {
224
+ const projectName = args[1];
225
+
226
+ if (!projectName) {
227
+ console.error(`${colors.red}error:${colors.reset} Project name is required.`);
228
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
229
+ process.exit(1);
230
+ }
231
+
232
+ // Parse options
233
+ const options: ProjectOptions = {
234
+ template: 'basic',
235
+ skipInstall: false
236
+ };
237
+
238
+ for (let i = 2; i < args.length; i++) {
239
+ if (args[i] === '--template' || args[i] === '-t') {
240
+ options.template = args[++i];
241
+ } else if (args[i] === '--skip-install' || args[i] === '-s') {
242
+ options.skipInstall = true;
243
+ }
244
+ }
245
+
246
+ printBanner();
247
+ createProject(projectName, options);
248
+ return;
249
+ }
250
+
251
+ console.error(`${colors.red}error:${colors.reset} Unknown command: ${command}`);
252
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
253
+ process.exit(1);
254
+ }
255
+
256
+ // Run CLI
257
+ parseArgs();
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Frontend Hamroun App</title>
7
+ <link rel="stylesheet" href="/src/main.css">
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ <script type="module" src="/src/main.ts"></script>
12
+ </body>
13
+ </html>
@@ -1,43 +1,50 @@
1
1
  {
2
- "name": "{{projectName}}",
2
+ "name": "frontend-hamroun-app",
3
+ "private": true,
3
4
  "version": "0.1.0",
4
5
  "description": "{{description}}",
5
6
  "author": "{{author}}",
6
7
  "license": "MIT",
7
8
  "type": "module",
8
9
  "scripts": {
9
- "dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
10
- "dev:server": "nodemon --watch src/server --exec \"ts-node src/server/index.ts\"",
11
- "dev:client": "vite",
12
- "build": "vite build && tsc --project tsconfig.server.json",
13
- "start": "node dist/server/index.js",
14
- "test": "jest"
10
+ "dev": "vite",
11
+ "build": "tsc && vite build",
12
+ "preview": "vite preview",
13
+ "start": "node dist/server.js",
14
+ "dev:server": "ts-node-esm --transpile-only src/server.ts",
15
+ "dev:full": "concurrently \"npm run dev\" \"npm run dev:server\""
15
16
  },
16
17
  "dependencies": {
18
+ "frontend-hamroun": "latest",
17
19
  "express": "^4.18.2",
18
- "frontend-hamroun": "^1.0.0",
20
+ "compression": "^1.7.4",
21
+ "helmet": "^7.0.0",
22
+ "morgan": "^1.10.0",
19
23
  "mongoose": "^7.0.0",
20
24
  "bcrypt": "^5.1.0",
21
25
  "jsonwebtoken": "^9.0.0",
22
- "compression": "^1.7.4",
23
26
  "cookie-parser": "^1.4.6",
24
- "dotenv": "^16.0.3",
25
- "helmet": "^6.0.1"
27
+ "dotenv": "^16.0.3"
26
28
  },
27
29
  "devDependencies": {
30
+ "@tailwindcss/forms": "^0.5.7",
31
+ "@tailwindcss/typography": "^0.5.10",
32
+ "@types/express": "^4.17.21",
33
+ "@types/node": "^20.10.0",
34
+ "autoprefixer": "^10.4.16",
35
+ "concurrently": "^8.2.2",
36
+ "postcss": "^8.4.31",
37
+ "tailwindcss": "^3.3.5",
38
+ "ts-node": "^10.9.1",
39
+ "typescript": "^5.3.2",
40
+ "vite": "^5.0.0",
28
41
  "@types/bcrypt": "^5.0.0",
29
42
  "@types/compression": "^1.7.2",
30
43
  "@types/cookie-parser": "^1.4.3",
31
- "@types/express": "^4.17.17",
32
44
  "@types/jest": "^29.5.0",
33
45
  "@types/jsonwebtoken": "^9.0.1",
34
- "@types/node": "^18.15.0",
35
- "concurrently": "^7.6.0",
36
46
  "jest": "^29.5.0",
37
47
  "nodemon": "^2.0.21",
38
- "ts-jest": "^29.0.5",
39
- "ts-node": "^10.9.1",
40
- "typescript": "^4.9.5",
41
- "vite": "^4.1.4"
48
+ "ts-jest": "^29.0.5"
42
49
  }
43
50
  }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,20 @@
1
+ import './main.css';
2
+ import { render } from 'frontend-hamroun';
3
+ import { App } from './App';
4
+ import { createApiClient } from './api';
5
+
6
+ // Initialize API client
7
+ const api = createApiClient({
8
+ baseUrl: '/api'
9
+ });
10
+
11
+ // Render the app into the DOM
12
+ document.addEventListener('DOMContentLoaded', () => {
13
+ const rootElement = document.getElementById('app');
14
+ if (rootElement) {
15
+ render(<App api={api} />, rootElement);
16
+ console.log('App rendered successfully');
17
+ } else {
18
+ console.error('Root element #app not found');
19
+ }
20
+ });