frontend-hamroun 1.2.16 → 1.2.17

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 (158) hide show
  1. package/README.md +4 -0
  2. package/bin/cli.js +673 -0
  3. package/dist/component.d.ts +1 -1
  4. package/dist/context.d.ts +4 -3
  5. package/dist/index.client.d.ts +11 -0
  6. package/dist/index.d.ts +9 -89
  7. package/dist/index.js +396 -67
  8. package/dist/index.js.map +1 -0
  9. package/dist/index.mjs +392 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/jsx-runtime/jsx-runtime.d.ts +0 -1
  12. package/dist/jsx-runtime.d.ts +1 -1
  13. package/dist/renderer.d.ts +0 -10
  14. package/dist/server-renderer.d.ts +0 -3
  15. package/dist/server-types.d.ts +42 -0
  16. package/package.json +69 -41
  17. package/templates/basic-app/index.html +6 -6
  18. package/templates/basic-app/package.json +18 -7
  19. package/templates/basic-app/postcss.config.js +0 -1
  20. package/templates/basic-app/src/main.tsx +1 -10
  21. package/templates/basic-app/tailwind.config.js +2 -23
  22. package/templates/basic-app/tsconfig.json +4 -17
  23. package/templates/basic-app/vite.config.ts +3 -54
  24. package/templates/fullstack-app/api/hello.ts +18 -0
  25. package/templates/fullstack-app/api/users/[id].ts +73 -0
  26. package/templates/fullstack-app/api/users/index.ts +32 -0
  27. package/templates/fullstack-app/package.json +31 -0
  28. package/templates/fullstack-app/server.ts +46 -0
  29. package/templates/fullstack-app/src/pages/index.tsx +59 -0
  30. package/templates/ssr-template/vite.config.ts +1 -11
  31. package/bin/cli.cjs +0 -16
  32. package/bin/cli.mjs +0 -237
  33. package/dist/backend/api-utils.d.ts +0 -38
  34. package/dist/backend/api-utils.js +0 -135
  35. package/dist/backend/auth.d.ts +0 -134
  36. package/dist/backend/auth.js +0 -387
  37. package/dist/backend/database.d.ts +0 -27
  38. package/dist/backend/database.js +0 -91
  39. package/dist/backend/model.d.ts +0 -43
  40. package/dist/backend/model.js +0 -178
  41. package/dist/backend/router.d.ts +0 -27
  42. package/dist/backend/router.js +0 -137
  43. package/dist/backend/server.d.ts +0 -19
  44. package/dist/backend/server.js +0 -268
  45. package/dist/backend/types.d.ts +0 -217
  46. package/dist/backend/types.js +0 -1
  47. package/dist/batch.js +0 -22
  48. package/dist/cli/index.d.ts +0 -2
  49. package/dist/cli/index.js +0 -215
  50. package/dist/component.js +0 -84
  51. package/dist/components/Counter.js +0 -2
  52. package/dist/context.js +0 -18
  53. package/dist/frontend-hamroun.es.js +0 -1378
  54. package/dist/frontend-hamroun.umd.js +0 -66
  55. package/dist/hooks.js +0 -164
  56. package/dist/jsx-runtime/index.d.ts +0 -11
  57. package/dist/jsx-runtime/index.js +0 -19
  58. package/dist/jsx-runtime/jsx-dev-runtime.js +0 -1
  59. package/dist/jsx-runtime/jsx-runtime.js +0 -95
  60. package/dist/jsx-runtime.js +0 -192
  61. package/dist/renderer.js +0 -51
  62. package/dist/server-renderer.js +0 -102
  63. package/dist/types.js +0 -1
  64. package/dist/vdom.js +0 -27
  65. package/scripts/build-cli.js +0 -1199
  66. package/scripts/generate.js +0 -134
  67. package/src/backend/api-utils.ts +0 -178
  68. package/src/backend/auth.ts +0 -544
  69. package/src/backend/database.ts +0 -104
  70. package/src/backend/model.ts +0 -198
  71. package/src/backend/router.ts +0 -176
  72. package/src/backend/server.ts +0 -330
  73. package/src/backend/types.ts +0 -257
  74. package/src/batch.ts +0 -24
  75. package/src/cli/index.js +0 -554
  76. package/src/cli/index.ts +0 -257
  77. package/src/component.ts +0 -98
  78. package/src/components/Counter.tsx +0 -4
  79. package/src/context.ts +0 -29
  80. package/src/hooks.ts +0 -211
  81. package/src/index.ts +0 -144
  82. package/src/jsx-runtime/index.ts +0 -27
  83. package/src/jsx-runtime/jsx-dev-runtime.ts +0 -0
  84. package/src/jsx-runtime/jsx-runtime.ts +0 -104
  85. package/src/jsx-runtime.ts +0 -226
  86. package/src/renderer.ts +0 -55
  87. package/src/server-renderer.ts +0 -114
  88. package/src/shims.d.ts +0 -20
  89. package/src/types/bcrypt.d.ts +0 -30
  90. package/src/types/jsonwebtoken.d.ts +0 -55
  91. package/src/types.d.ts +0 -26
  92. package/src/types.ts +0 -21
  93. package/src/vdom.ts +0 -34
  94. package/templates/basic/.eslintignore +0 -5
  95. package/templates/basic/.eslintrc.json +0 -25
  96. package/templates/basic/docs/rapport_pfe.aux +0 -27
  97. package/templates/basic/docs/rapport_pfe.log +0 -399
  98. package/templates/basic/docs/rapport_pfe.out +0 -10
  99. package/templates/basic/docs/rapport_pfe.pdf +0 -0
  100. package/templates/basic/docs/rapport_pfe.tex +0 -68
  101. package/templates/basic/docs/rapport_pfe.toc +0 -14
  102. package/templates/basic/index.html +0 -12
  103. package/templates/basic/jsconfig.json +0 -14
  104. package/templates/basic/package.json +0 -18
  105. package/templates/basic/postcss.config.js +0 -7
  106. package/templates/basic/src/App.js +0 -105
  107. package/templates/basic/src/App.tsx +0 -65
  108. package/templates/basic/src/api.ts +0 -58
  109. package/templates/basic/src/components/Counter.tsx +0 -26
  110. package/templates/basic/src/components/Header.tsx +0 -9
  111. package/templates/basic/src/components/TodoList.tsx +0 -90
  112. package/templates/basic/src/main.css +0 -3
  113. package/templates/basic/src/main.js +0 -11
  114. package/templates/basic/src/main.ts +0 -20
  115. package/templates/basic/src/main.tsx +0 -144
  116. package/templates/basic/src/server.ts +0 -99
  117. package/templates/basic/tailwind.config.js +0 -32
  118. package/templates/basic/tsconfig.json +0 -20
  119. package/templates/basic/tsconfig.node.json +0 -10
  120. package/templates/basic/vite.config.js +0 -18
  121. package/templates/basic/vite.config.ts +0 -86
  122. package/templates/basic-app/src/App.js +0 -105
  123. package/templates/basic-app/src/App.tsx +0 -143
  124. package/templates/basic-app/src/api.ts +0 -58
  125. package/templates/basic-app/src/components/Counter.tsx +0 -26
  126. package/templates/basic-app/src/components/Header.tsx +0 -9
  127. package/templates/basic-app/src/components/TodoList.tsx +0 -90
  128. package/templates/basic-app/src/main.js +0 -10
  129. package/templates/basic-app/src/main.ts +0 -21
  130. package/templates/basic-app/src/react/index.ts +0 -35
  131. package/templates/basic-app/src/react/jsx-dev-runtime.ts +0 -13
  132. package/templates/basic-app/src/react/jsx-runtime.ts +0 -12
  133. package/templates/basic-app/src/server.ts +0 -99
  134. package/templates/basic-app/src/shims.ts +0 -9
  135. package/templates/basic-app/tsconfig.node.json +0 -10
  136. package/templates/basic-app/vite.config.js +0 -22
  137. package/templates/full-stack/.env.example +0 -11
  138. package/templates/full-stack/README.md +0 -51
  139. package/templates/full-stack/index.html +0 -12
  140. package/templates/full-stack/jsconfig.json +0 -14
  141. package/templates/full-stack/package.json +0 -21
  142. package/templates/full-stack/src/App.js +0 -105
  143. package/templates/full-stack/src/client/App.tsx +0 -50
  144. package/templates/full-stack/src/client/components/Header.tsx +0 -42
  145. package/templates/full-stack/src/client/components/UserList.tsx +0 -29
  146. package/templates/full-stack/src/client/main.tsx +0 -5
  147. package/templates/full-stack/src/main.css +0 -3
  148. package/templates/full-stack/src/main.js +0 -11
  149. package/templates/full-stack/src/main.ts +0 -20
  150. package/templates/full-stack/src/server/index.ts +0 -99
  151. package/templates/full-stack/src/server/routes/auth.ts +0 -39
  152. package/templates/full-stack/src/server/routes/users.ts +0 -48
  153. package/templates/full-stack/src/shims.ts +0 -9
  154. package/templates/full-stack/tsconfig.json +0 -20
  155. package/templates/full-stack/tsconfig.node.json +0 -10
  156. package/templates/full-stack/tsconfig.server.json +0 -15
  157. package/templates/full-stack/vite.config.js +0 -18
  158. package/templates/full-stack/vite.config.ts +0 -85
@@ -1,1199 +0,0 @@
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 CLI entrypoint using ES modules
17
- const cliContent = `#!/usr/bin/env node
18
-
19
- import fs from 'fs';
20
- import path from 'path';
21
- import { fileURLToPath } from 'url';
22
- import { execSync } from 'child_process';
23
-
24
- const __filename = fileURLToPath(import.meta.url);
25
- const __dirname = path.dirname(__filename);
26
-
27
- // Templates available
28
- const TEMPLATES = {
29
- 'basic': 'Basic frontend only template',
30
- 'full-stack': 'Complete frontend and backend template'
31
- };
32
-
33
- // Colors for CLI output
34
- const colors = {
35
- reset: '\\x1b[0m',
36
- bright: '\\x1b[1m',
37
- green: '\\x1b[32m',
38
- blue: '\\x1b[34m',
39
- red: '\\x1b[31m',
40
- yellow: '\\x1b[33m'
41
- };
42
-
43
- // Get package.json to read version
44
- const packageJsonPath = path.resolve(__dirname, '../package.json');
45
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
46
-
47
- // Print banner
48
- function printBanner() {
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() {
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
- \`);
81
- }
82
-
83
- // Create project from template
84
- function createProject(projectName, options) {
85
- const template = options.template || 'basic';
86
-
87
- // Check if template exists
88
- if (!Object.keys(TEMPLATES).includes(template)) {
89
- console.error(\`\${colors.red}error:\${colors.reset} Template "\${template}" not found.\`);
90
- console.log(\`Available templates: \${Object.keys(TEMPLATES).join(', ')}\`);
91
- process.exit(1);
92
- }
93
-
94
- // Check if project directory already exists
95
- const projectPath = path.resolve(process.cwd(), projectName);
96
- if (fs.existsSync(projectPath)) {
97
- console.error(\`\${colors.red}error:\${colors.reset} Directory \${projectName} already exists.\`);
98
- process.exit(1);
99
- }
100
-
101
- console.log(\`
102
- \${colors.bright}Creating a new project with Frontend Hamroun...\${colors.reset}
103
- \${colors.blue}• Project name:\${colors.reset} \${projectName}
104
- \${colors.blue}• Template:\${colors.reset} \${template}
105
- \${colors.blue}• Directory:\${colors.reset} \${projectPath}
106
- \`);
107
-
108
- try {
109
- // Find templates directory
110
- const templateDir = path.resolve(__dirname, '../templates', template);
111
-
112
- if (!fs.existsSync(templateDir)) {
113
- console.error(\`\${colors.red}error:\${colors.reset} Template directory not found: \${templateDir}\`);
114
- // Try to find template with -app suffix as fallback
115
- const fallbackTemplateDir = path.resolve(__dirname, '../templates', \`\${template}-app\`);
116
- if (fs.existsSync(fallbackTemplateDir)) {
117
- console.log(\`\${colors.yellow}Using fallback template:\${colors.reset} \${template}-app\`);
118
- templateDir = fallbackTemplateDir;
119
- } else {
120
- process.exit(1);
121
- }
122
- }
123
-
124
- // Create project directory
125
- fs.mkdirSync(projectPath, { recursive: true });
126
-
127
- // Copy template files (recursive function)
128
- function copyDir(src, dest) {
129
- const entries = fs.readdirSync(src, { withFileTypes: true });
130
-
131
- for (const entry of entries) {
132
- const srcPath = path.join(src, entry.name);
133
- const destPath = path.join(dest, entry.name);
134
-
135
- if (entry.isDirectory()) {
136
- fs.mkdirSync(destPath, { recursive: true });
137
- copyDir(srcPath, destPath);
138
- } else {
139
- fs.copyFileSync(srcPath, destPath);
140
- }
141
- }
142
- }
143
-
144
- // Copy the files
145
- copyDir(templateDir, projectPath);
146
- console.log(\`\${colors.green}•\${colors.reset} Copied template files\`);
147
-
148
- // Update package.json with project name
149
- const projectPackageJsonPath = path.join(projectPath, 'package.json');
150
- if (fs.existsSync(projectPackageJsonPath)) {
151
- const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
152
- projectPackageJson.name = projectName;
153
- fs.writeFileSync(
154
- projectPackageJsonPath,
155
- JSON.stringify(projectPackageJson, null, 2)
156
- );
157
- }
158
-
159
- // Install dependencies
160
- if (!options.skipInstall) {
161
- console.log(\`\\n\${colors.blue}Installing dependencies...\${colors.reset}\`);
162
-
163
- try {
164
- execSync(\`npm install\`, {
165
- cwd: projectPath,
166
- stdio: 'inherit'
167
- });
168
- } catch (error) {
169
- console.error(\`\\n\${colors.red}Failed to install dependencies. You can install them manually:\${colors.reset}\`);
170
- console.log(\` cd \${projectName} && npm install\`);
171
- }
172
- }
173
-
174
- // Success message
175
- console.log(\`
176
- \${colors.green}\${colors.bright}Success!\${colors.reset} Created \${projectName} at \${projectPath}
177
-
178
- \${colors.blue}Inside that directory, you can run several commands:\${colors.reset}
179
-
180
- \${colors.bright}npm run dev\${colors.reset}
181
- Starts the development server.
182
-
183
- \${colors.bright}npm run build\${colors.reset}
184
- Builds the app for production.
185
-
186
- \${colors.bright}npm start\${colors.reset}
187
- Runs the built app in production mode.
188
-
189
- \${colors.blue}We suggest that you begin by typing:\${colors.reset}
190
-
191
- \${colors.bright}cd\${colors.reset} \${projectName}
192
- \${colors.bright}npm run dev\${colors.reset}
193
-
194
- \${colors.green}Happy coding!\${colors.reset}
195
- \`);
196
-
197
- } catch (error) {
198
- console.error(\`\${colors.red}Failed to create project:\${colors.reset}\`, error);
199
- process.exit(1);
200
- }
201
- }
202
-
203
- // Parse command line arguments
204
- function parseArgs() {
205
- const args = process.argv.slice(2);
206
- const command = args[0];
207
-
208
- if (!command || command === 'help') {
209
- printBanner();
210
- printHelp();
211
- process.exit(0);
212
- }
213
-
214
- if (command === 'version') {
215
- console.log(\`frontend-hamroun v\${packageJson.version}\`);
216
- process.exit(0);
217
- }
218
-
219
- if (command === 'create') {
220
- const projectName = args[1];
221
-
222
- if (!projectName) {
223
- console.error(\`\${colors.red}error:\${colors.reset} Project name is required.\`);
224
- console.log(\`Run \${colors.blue}npx frontend-hamroun help\${colors.reset} for usage information.\`);
225
- process.exit(1);
226
- }
227
-
228
- // Parse options
229
- const options = {
230
- template: 'basic',
231
- skipInstall: false
232
- };
233
-
234
- for (let i = 2; i < args.length; i++) {
235
- if (args[i] === '--template' || args[i] === '-t') {
236
- options.template = args[++i];
237
- } else if (args[i] === '--skip-install' || args[i] === '-s') {
238
- options.skipInstall = true;
239
- }
240
- }
241
-
242
- printBanner();
243
- createProject(projectName, options);
244
- return;
245
- }
246
-
247
- console.error(\`\${colors.red}error:\${colors.reset} Unknown command: \${command}\`);
248
- console.log(\`Run \${colors.blue}npx frontend-hamroun help\${colors.reset} for usage information.\`);
249
- process.exit(1);
250
- }
251
-
252
- // Run CLI
253
- parseArgs();
254
- `;
255
-
256
- // Write CLI file with .mjs extension for ES modules
257
- fs.writeFileSync(path.join(binDir, 'cli.mjs'), cliContent, 'utf8');
258
-
259
- // Make CLI executable
260
- try {
261
- fs.chmodSync(path.join(binDir, 'cli.mjs'), '755');
262
- console.log('✅ CLI built successfully: bin/cli.mjs');
263
- } catch (error) {
264
- console.warn('⚠️ Could not make CLI executable:', error);
265
- }
266
-
267
- // Let's make sure we also have template directories
268
- const templatesDir = path.resolve(rootDir, 'templates');
269
- const templateList = ['basic', 'full-stack'];
270
-
271
- console.log('🔍 Checking template directories...');
272
- for (const template of templateList) {
273
- const templateDir = path.join(templatesDir, template);
274
- const appTemplateDir = path.join(templatesDir, `${template}-app`);
275
-
276
- // Check if either directory exists
277
- if (!fs.existsSync(templateDir) && !fs.existsSync(appTemplateDir)) {
278
- console.log(`⚠️ Template directory "${template}" not found at: ${templateDir}`);
279
- console.log(`⚠️ Template directory "${template}-app" not found at: ${appTemplateDir}`);
280
-
281
- // Create the template directory
282
- console.log(`📁 Creating template directory: ${template}`);
283
- fs.mkdirSync(templateDir, { recursive: true });
284
-
285
- // Create a minimal template
286
- console.log(`📝 Creating minimal ${template} template`);
287
-
288
- // Create package.json
289
- const packageJson = {
290
- "name": "frontend-hamroun-app",
291
- "private": true,
292
- "version": "0.1.0",
293
- "type": "module",
294
- "scripts": {
295
- "dev": "node src/server.js",
296
- "build": "node src/build.js",
297
- "preview": "node src/preview.js"
298
- },
299
- "dependencies": {
300
- "frontend-hamroun": "latest"
301
- },
302
- "devDependencies": {
303
- "@types/node": "^20.10.0",
304
- "typescript": "^5.3.2"
305
- }
306
- };
307
-
308
- fs.writeFileSync(
309
- path.join(templateDir, 'package.json'),
310
- JSON.stringify(packageJson, null, 2)
311
- );
312
-
313
- // Create minimal files for the template
314
- fs.writeFileSync(
315
- path.join(templateDir, 'index.html'),
316
- `<!DOCTYPE html>
317
- <html lang="en">
318
- <head>
319
- <meta charset="UTF-8">
320
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
321
- <title>Frontend Hamroun App</title>
322
- </head>
323
- <body>
324
- <div id="app"></div>
325
- <script type="module" src="/src/main.ts"></script>
326
- </body>
327
- </html>`
328
- );
329
-
330
- // Create src directory
331
- const srcDir = path.join(templateDir, 'src');
332
- fs.mkdirSync(srcDir, { recursive: true });
333
-
334
- // Create basic files
335
- fs.writeFileSync(
336
- path.join(srcDir, 'main.ts'),
337
- `import { render } from 'frontend-hamroun';
338
- import { App } from './App';
339
-
340
- document.addEventListener('DOMContentLoaded', () => {
341
- const rootElement = document.getElementById('app');
342
- if (rootElement) {
343
- render(<App />, rootElement);
344
- }
345
- });`
346
- );
347
-
348
- fs.writeFileSync(
349
- path.join(srcDir, 'App.tsx'),
350
- `import { useState } from 'frontend-hamroun';
351
-
352
- export function App() {
353
- const [count, setCount] = useState(0);
354
-
355
- return (
356
- <div style={{ fontFamily: 'Arial, sans-serif', maxWidth: '600px', margin: '0 auto', padding: '2rem' }}>
357
- <h1 style={{ color: '#333', textAlign: 'center' }}>Frontend Hamroun App</h1>
358
- <div style={{
359
- display: 'flex',
360
- flexDirection: 'column',
361
- alignItems: 'center',
362
- marginTop: '2rem',
363
- padding: '1rem',
364
- border: '1px solid #ccc',
365
- borderRadius: '8px'
366
- }}>
367
- <h2>Counter Example</h2>
368
- <p>Count: {count}</p>
369
- <div style={{ display: 'flex', gap: '8px' }}>
370
- <button
371
- onClick={() => setCount(count - 1)}
372
- style={{
373
- padding: '8px 16px',
374
- background: '#ff4d4d',
375
- color: 'white',
376
- border: 'none',
377
- borderRadius: '4px',
378
- cursor: 'pointer'
379
- }}
380
- >
381
- Decrement
382
- </button>
383
- <button
384
- onClick={() => setCount(count + 1)}
385
- style={{
386
- padding: '8px 16px',
387
- background: '#4d79ff',
388
- color: 'white',
389
- border: 'none',
390
- borderRadius: '4px',
391
- cursor: 'pointer'
392
- }}
393
- >
394
- Increment
395
- </button>
396
- </div>
397
- </div>
398
- </div>
399
- );
400
- }`
401
- );
402
-
403
- // Create build.js
404
- fs.writeFileSync(
405
- path.join(srcDir, 'build.js'),
406
- `import { execSync } from 'child_process';
407
-
408
- console.log('Building the app...');
409
- try {
410
- execSync('tsc', { stdio: 'inherit' });
411
- console.log('Build completed successfully.');
412
- } catch (error) {
413
- console.error('Build failed:', error);
414
- }`
415
- );
416
-
417
- // Create preview.js
418
- fs.writeFileSync(
419
- path.join(srcDir, 'preview.js'),
420
- `import { execSync } from 'child_process';
421
-
422
- console.log('Starting preview server...');
423
- try {
424
- execSync('node dist/server.js', { stdio: 'inherit' });
425
- } catch (error) {
426
- console.error('Failed to start preview server:', error);
427
- }`
428
- );
429
-
430
- // Create tsconfig files
431
- fs.writeFileSync(
432
- path.join(templateDir, 'tsconfig.json'),
433
- `{
434
- "compilerOptions": {
435
- "target": "ES2020",
436
- "useDefineForClassFields": true,
437
- "module": "ESNext",
438
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
439
- "skipLibCheck": true,
440
- "moduleResolution": "bundler",
441
- "allowImportingTsExtensions": true,
442
- "resolveJsonModule": true,
443
- "isolatedModules": true,
444
- "noEmit": true,
445
- "jsx": "preserve",
446
- "strict": true,
447
- "noUnusedLocals": true,
448
- "noUnusedParameters": true,
449
- "noFallthroughCasesInSwitch": true
450
- },
451
- "include": ["src"],
452
- "references": [{ "path": "./tsconfig.node.json" }]
453
- }`
454
- );
455
-
456
- fs.writeFileSync(
457
- path.join(templateDir, 'tsconfig.node.json'),
458
- `{
459
- "compilerOptions": {
460
- "composite": true,
461
- "module": "ESNext",
462
- "moduleResolution": "bundler",
463
- "allowSyntheticDefaultImports": true
464
- },
465
- "include": ["src/build.js", "src/preview.js"]
466
- }`
467
- );
468
-
469
- console.log(`✅ Created minimal ${template} template`);
470
- } else {
471
- if (fs.existsSync(templateDir)) {
472
- console.log(`✅ Template found: ${template}`);
473
- } else {
474
- console.log(`✅ Template found: ${template}-app (will use as fallback)`);
475
- }
476
- }
477
- }
478
-
479
- // Create a CJS wrapper for environments that don't support ESM out of the box
480
- const cjsWrapper = `#!/usr/bin/env node
481
- // This file is a CommonJS wrapper for the ES module CLI
482
- // It loads the actual CLI implementation using dynamic import()
483
-
484
- async function main() {
485
- try {
486
- // Use dynamic import to load the ES module CLI
487
- const cliPath = new URL('../bin/cli.mjs', import.meta.url).href;
488
- await import(cliPath);
489
- } catch (error) {
490
- console.error('Error loading CLI:', error);
491
- process.exit(1);
492
- }
493
- }
494
-
495
- main();
496
- `;
497
-
498
- fs.writeFileSync(path.join(binDir, 'cli.cjs'), cjsWrapper, 'utf8');
499
- fs.chmodSync(path.join(binDir, 'cli.cjs'), '755');
500
- console.log('✅ Created CJS wrapper: bin/cli.cjs');
501
-
502
- console.log('✅ CLI build process completed');
503
-
504
- // Create a minimal basic template (update existing code)
505
- function createBasicTemplate(templateDir) {
506
- console.log(`📝 Creating minimal basic template at ${templateDir}`);
507
-
508
- // Create package.json
509
- const packageJson = {
510
- "name": "frontend-hamroun-app",
511
- "private": true,
512
- "version": "0.1.0",
513
- "type": "module",
514
- "scripts": {
515
- "dev": "node src/server.js",
516
- "build": "node src/build.js",
517
- "preview": "node src/preview.js"
518
- },
519
- "dependencies": {
520
- "frontend-hamroun": "latest"
521
- },
522
- "devDependencies": {
523
- "@types/node": "^20.10.0",
524
- "typescript": "^5.3.2"
525
- }
526
- };
527
-
528
- fs.writeFileSync(
529
- path.join(templateDir, 'package.json'),
530
- JSON.stringify(packageJson, null, 2)
531
- );
532
-
533
- // Create index.html
534
- fs.writeFileSync(
535
- path.join(templateDir, 'index.html'),
536
- `<!DOCTYPE html>
537
- <html lang="en">
538
- <head>
539
- <meta charset="UTF-8">
540
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
541
- <title>Frontend Hamroun App</title>
542
- </head>
543
- <body>
544
- <div id="app"></div>
545
- <script type="module" src="/src/main.ts"></script>
546
- </body>
547
- </html>`
548
- );
549
-
550
- // Create src directory
551
- const srcDir = path.join(templateDir, 'src');
552
- fs.mkdirSync(srcDir, { recursive: true });
553
-
554
- // Create main.ts
555
- fs.writeFileSync(
556
- path.join(srcDir, 'main.ts'),
557
- `import { render } from 'frontend-hamroun';
558
- import { App } from './App';
559
-
560
- document.addEventListener('DOMContentLoaded', () => {
561
- const rootElement = document.getElementById('app');
562
- if (rootElement) {
563
- render(App({}), rootElement);
564
- console.log('App rendered successfully');
565
- }
566
- });`
567
- );
568
-
569
- // Create App.ts (not App.tsx)
570
- fs.writeFileSync(
571
- path.join(srcDir, 'App.ts'),
572
- `import { useState, useRef } from 'frontend-hamroun';
573
-
574
- export function App(props) {
575
- const [count, setCount] = useState(0);
576
- const renderCount = useRef(0);
577
-
578
- renderCount.current++;
579
-
580
- return {
581
- type: 'div',
582
- props: {
583
- style: {
584
- fontFamily: 'Arial, sans-serif',
585
- maxWidth: '600px',
586
- margin: '0 auto',
587
- padding: '2rem'
588
- },
589
- children: [
590
- {
591
- type: 'h1',
592
- props: {
593
- style: { textAlign: 'center' },
594
- children: 'Frontend Hamroun App'
595
- }
596
- },
597
- {
598
- type: 'p',
599
- props: {
600
- style: { textAlign: 'center' },
601
- children: \`Render count: \${renderCount.current}\`
602
- }
603
- },
604
- {
605
- type: 'div',
606
- props: {
607
- style: {
608
- display: 'flex',
609
- flexDirection: 'column',
610
- alignItems: 'center',
611
- padding: '1rem',
612
- border: '1px solid #ccc',
613
- borderRadius: '8px'
614
- },
615
- children: [
616
- {
617
- type: 'h2',
618
- props: {
619
- children: 'Counter Example'
620
- }
621
- },
622
- {
623
- type: 'p',
624
- props: {
625
- children: \`Count: \${count}\`
626
- }
627
- },
628
- {
629
- type: 'div',
630
- props: {
631
- style: {
632
- display: 'flex',
633
- gap: '8px'
634
- },
635
- children: [
636
- {
637
- type: 'button',
638
- props: {
639
- onClick: () => setCount(count - 1),
640
- style: {
641
- padding: '8px 16px',
642
- backgroundColor: '#ff4d4d',
643
- color: 'white',
644
- border: 'none',
645
- borderRadius: '4px',
646
- cursor: 'pointer'
647
- },
648
- children: 'Decrement'
649
- }
650
- },
651
- {
652
- type: 'button',
653
- props: {
654
- onClick: () => setCount(count + 1),
655
- style: {
656
- padding: '8px 16px',
657
- backgroundColor: '#4d79ff',
658
- color: 'white',
659
- border: 'none',
660
- borderRadius: '4px',
661
- cursor: 'pointer'
662
- },
663
- children: 'Increment'
664
- }
665
- }
666
- ]
667
- }
668
- }
669
- ]
670
- }
671
- }
672
- ]
673
- }
674
- };
675
- }`
676
- );
677
-
678
- // Create build.js
679
- fs.writeFileSync(
680
- path.join(srcDir, 'build.js'),
681
- `import { execSync } from 'child_process';
682
-
683
- console.log('Building the app...');
684
- try {
685
- execSync('tsc', { stdio: 'inherit' });
686
- console.log('Build completed successfully.');
687
- } catch (error) {
688
- console.error('Build failed:', error);
689
- }`
690
- );
691
-
692
- // Create preview.js
693
- fs.writeFileSync(
694
- path.join(srcDir, 'preview.js'),
695
- `import { execSync } from 'child_process';
696
-
697
- console.log('Starting preview server...');
698
- try {
699
- execSync('node dist/server.js', { stdio: 'inherit' });
700
- } catch (error) {
701
- console.error('Failed to start preview server:', error);
702
- }`
703
- );
704
-
705
- // Create tsconfig.json
706
- fs.writeFileSync(
707
- path.join(templateDir, 'tsconfig.json'),
708
- `{
709
- "compilerOptions": {
710
- "target": "ES2020",
711
- "useDefineForClassFields": true,
712
- "module": "ESNext",
713
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
714
- "skipLibCheck": true,
715
- "moduleResolution": "bundler",
716
- "allowImportingTsExtensions": true,
717
- "resolveJsonModule": true,
718
- "isolatedModules": true,
719
- "noEmit": true,
720
- "strict": true,
721
- "noUnusedLocals": true,
722
- "noUnusedParameters": true,
723
- "noFallthroughCasesInSwitch": true
724
- },
725
- "include": ["src"],
726
- "references": [{ "path": "./tsconfig.node.json" }]
727
- }`
728
- );
729
-
730
- // Create tsconfig.node.json
731
- fs.writeFileSync(
732
- path.join(templateDir, 'tsconfig.node.json'),
733
- `{
734
- "compilerOptions": {
735
- "composite": true,
736
- "skipLibCheck": true,
737
- "module": "ESNext",
738
- "moduleResolution": "bundler",
739
- "allowSyntheticDefaultImports": true
740
- },
741
- "include": ["src/build.js", "src/preview.js"]
742
- }`
743
- );
744
-
745
- console.log(`✅ Created minimal basic template at ${templateDir}`);
746
-
747
- // Create React compatibility layer
748
- createReactCompatibilityLayer(templateDir);
749
- }
750
-
751
- // Create React compatibility layer
752
- function createReactCompatibilityLayer(templateDir) {
753
- // Create React compatibility directory
754
- const reactDir = path.join(templateDir, 'src/react');
755
- if (!fs.existsSync(reactDir)) {
756
- fs.mkdirSync(reactDir, { recursive: true });
757
- }
758
-
759
- // Create jsx-dev-runtime.ts
760
- fs.writeFileSync(
761
- path.join(reactDir, 'jsx-dev-runtime.ts'),
762
- `import { jsx } from 'frontend-hamroun';
763
-
764
- // Export jsx as jsxDEV for React compatibility
765
- export const jsxDEV = jsx;
766
- export const Fragment = Symbol('Fragment');
767
- export const jsxs = jsx;
768
-
769
- // Default export
770
- export default {
771
- jsxDEV,
772
- Fragment,
773
- jsxs
774
- };`
775
- );
776
-
777
- // Create jsx-runtime.ts
778
- fs.writeFileSync(
779
- path.join(reactDir, 'jsx-runtime.ts'),
780
- `import { jsx } from 'frontend-hamroun';
781
-
782
- // Export jsx functions for React compatibility
783
- export const jsxs = jsx;
784
- export const Fragment = Symbol('Fragment');
785
-
786
- // Default export
787
- export default {
788
- jsx,
789
- jsxs,
790
- Fragment
791
- };`
792
- );
793
-
794
- // Create index.ts
795
- fs.writeFileSync(
796
- path.join(reactDir, 'index.ts'),
797
- `import {
798
- useState,
799
- useEffect,
800
- useRef,
801
- useMemo,
802
- useContext,
803
- createContext,
804
- jsx
805
- } from 'frontend-hamroun';
806
-
807
- // Provide React compatibility layer
808
- const React = {
809
- createElement: jsx,
810
- Fragment: Symbol('Fragment'),
811
- useState,
812
- useEffect,
813
- useRef,
814
- useMemo,
815
- useContext,
816
- createContext
817
- };
818
-
819
- // Export hooks directly for named imports
820
- export {
821
- useState,
822
- useEffect,
823
- useRef,
824
- useMemo,
825
- useContext,
826
- createContext,
827
- jsx as createElement
828
- };
829
-
830
- // Default export
831
- export default React;`
832
- );
833
-
834
- console.log(`✅ Created React compatibility layer in ${templateDir}`);
835
- }
836
-
837
- // Create React compatibility shims
838
- function createTemplateShims(templateDir) {
839
- // Create src directory if it doesn't exist
840
- const srcDir = path.join(templateDir, 'src');
841
- if (!fs.existsSync(srcDir)) {
842
- fs.mkdirSync(srcDir, { recursive: true });
843
- }
844
-
845
- // Create shims.ts file for React JSX compatibility
846
- fs.writeFileSync(
847
- path.join(srcDir, 'shims.ts'),
848
- `// This file provides compatibility shims for React JSX imports
849
-
850
- import { jsx } from 'frontend-hamroun';
851
-
852
- // Export the jsx function as jsxDEV for React compatibility
853
- export const jsxDEV = jsx;
854
-
855
- // Export a Fragment symbol
856
- export const Fragment = Symbol('Fragment');
857
-
858
- // Default export as React compatibility layer
859
- export default {
860
- createElement: jsx,
861
- Fragment
862
- };
863
- `
864
- );
865
-
866
- console.log(`✅ Created React compatibility shims in ${templateDir}`);
867
- }
868
-
869
- // Create a function to create a pure non-JSX template
870
- function createPureTemplate(templateDir) {
871
- console.log(`📝 Creating pure JS template at ${templateDir}`);
872
-
873
- // Create package.json without TypeScript, React or any unnecessary dependencies
874
- const packageJson = {
875
- "name": "frontend-hamroun-app",
876
- "private": true,
877
- "version": "0.1.0",
878
- "type": "module",
879
- "scripts": {
880
- "dev": "node src/server.js",
881
- "build": "node src/build.js",
882
- "preview": "node src/preview.js"
883
- },
884
- "dependencies": {
885
- "frontend-hamroun": "latest"
886
- },
887
- "devDependencies": {
888
- "typescript": "^5.3.2"
889
- }
890
- };
891
-
892
- fs.writeFileSync(
893
- path.join(templateDir, 'package.json'),
894
- JSON.stringify(packageJson, null, 2)
895
- );
896
-
897
- // Create index.html
898
- fs.writeFileSync(
899
- path.join(templateDir, 'index.html'),
900
- `<!DOCTYPE html>
901
- <html lang="en">
902
- <head>
903
- <meta charset="UTF-8">
904
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
905
- <title>Frontend Hamroun App</title>
906
- </head>
907
- <body>
908
- <div id="app"></div>
909
- <script type="module" src="/src/main.js"></script>
910
- </body>
911
- </html>`
912
- );
913
-
914
- // Create src directory
915
- const srcDir = path.join(templateDir, 'src');
916
- fs.mkdirSync(srcDir, { recursive: true });
917
-
918
- // Create pure JS main.js without any JSX
919
- fs.writeFileSync(
920
- path.join(srcDir, 'main.js'),
921
- `import { render } from 'frontend-hamroun';
922
- import { App } from './App.js';
923
-
924
- document.addEventListener('DOMContentLoaded', () => {
925
- const rootElement = document.getElementById('app');
926
- if (rootElement) {
927
- // Call App as a function to create the VDOM structure
928
- render(App(), rootElement);
929
- console.log('App rendered successfully');
930
- }
931
- });`
932
- );
933
-
934
- // Create App.js with pure JS (no JSX or TS)
935
- fs.writeFileSync(
936
- path.join(srcDir, 'App.js'),
937
- `import { useState, useRef } from 'frontend-hamroun';
938
-
939
- export function App() {
940
- const [count, setCount] = useState(0);
941
- const renderCount = useRef(0);
942
-
943
- renderCount.current++;
944
-
945
- // Return a plain JavaScript object representation of the UI
946
- return {
947
- type: 'div',
948
- props: {
949
- style: {
950
- fontFamily: 'Arial, sans-serif',
951
- maxWidth: '600px',
952
- margin: '0 auto',
953
- padding: '2rem'
954
- },
955
- children: [
956
- {
957
- type: 'h1',
958
- props: {
959
- style: { textAlign: 'center' },
960
- children: 'Frontend Hamroun App'
961
- }
962
- },
963
- {
964
- type: 'p',
965
- props: {
966
- style: { textAlign: 'center' },
967
- children: \`Render count: \${renderCount.current}\`
968
- }
969
- },
970
- {
971
- type: 'div',
972
- props: {
973
- style: {
974
- display: 'flex',
975
- flexDirection: 'column',
976
- alignItems: 'center',
977
- padding: '1rem',
978
- border: '1px solid #ccc',
979
- borderRadius: '8px'
980
- },
981
- children: [
982
- {
983
- type: 'h2',
984
- props: {
985
- children: 'Counter Example'
986
- }
987
- },
988
- {
989
- type: 'p',
990
- props: {
991
- children: \`Count: \${count}\`
992
- }
993
- },
994
- {
995
- type: 'div',
996
- props: {
997
- style: {
998
- display: 'flex',
999
- gap: '8px'
1000
- },
1001
- children: [
1002
- {
1003
- type: 'button',
1004
- props: {
1005
- onClick: () => setCount(count - 1),
1006
- style: {
1007
- padding: '8px 16px',
1008
- backgroundColor: '#ff4d4d',
1009
- color: 'white',
1010
- border: 'none',
1011
- borderRadius: '4px',
1012
- cursor: 'pointer'
1013
- },
1014
- children: 'Decrement'
1015
- }
1016
- },
1017
- {
1018
- type: 'button',
1019
- props: {
1020
- onClick: () => setCount(count + 1),
1021
- style: {
1022
- padding: '8px 16px',
1023
- backgroundColor: '#4d79ff',
1024
- color: 'white',
1025
- border: 'none',
1026
- borderRadius: '4px',
1027
- cursor: 'pointer'
1028
- },
1029
- children: 'Increment'
1030
- }
1031
- }
1032
- ]
1033
- }
1034
- }
1035
- ]
1036
- }
1037
- }
1038
- ]
1039
- }
1040
- };
1041
- }`
1042
- );
1043
-
1044
- // Create build.js - No TypeScript, no JSX
1045
- fs.writeFileSync(
1046
- path.join(templateDir, 'src/build.js'),
1047
- `import { execSync } from 'child_process';
1048
-
1049
- console.log('Building the app...');
1050
- try {
1051
- execSync('node src/build.js', { stdio: 'inherit' });
1052
- console.log('Build completed successfully.');
1053
- } catch (error) {
1054
- console.error('Build failed:', error);
1055
- }`
1056
- );
1057
-
1058
- // Create jsconfig.json instead of tsconfig.json
1059
- fs.writeFileSync(
1060
- path.join(templateDir, 'jsconfig.json'),
1061
- `{
1062
- "compilerOptions": {
1063
- "target": "ES2020",
1064
- "useDefineForClassFields": true,
1065
- "module": "ESNext",
1066
- "moduleResolution": "node",
1067
- "allowSyntheticDefaultImports": true,
1068
- "resolveJsonModule": true,
1069
- "checkJs": false,
1070
- "strict": false
1071
- },
1072
- "include": ["src/**/*.js"],
1073
- "exclude": ["node_modules"]
1074
- }`
1075
- );
1076
-
1077
- console.log(`✅ Created pure JS template at ${templateDir}`);
1078
- }
1079
-
1080
- // Add a function for full-stack template
1081
- function createFullStackTemplate(templateDir) {
1082
- // Create the base template first
1083
- createPureTemplate(templateDir);
1084
-
1085
- // Update package.json with backend dependencies
1086
- const packageJsonPath = path.join(templateDir, 'package.json');
1087
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
1088
-
1089
- // Add backend dependencies
1090
- packageJson.dependencies = {
1091
- ...packageJson.dependencies,
1092
- "express": "^4.18.2",
1093
- "compression": "^1.7.4",
1094
- "helmet": "^7.1.0",
1095
- "morgan": "^1.10.0"
1096
- };
1097
-
1098
- // Add backend scripts
1099
- packageJson.scripts = {
1100
- ...packageJson.scripts,
1101
- "start": "node dist/server.js",
1102
- "dev:server": "node --experimental-specifier-resolution=node src/server.js",
1103
- "dev:full": "concurrently \"npm run dev\" \"npm run dev:server\""
1104
- };
1105
-
1106
- // Add development dependencies for backend
1107
- packageJson.devDependencies = {
1108
- ...packageJson.devDependencies,
1109
- "concurrently": "^8.2.2"
1110
- };
1111
-
1112
- fs.writeFileSync(
1113
- packageJsonPath,
1114
- JSON.stringify(packageJson, null, 2)
1115
- );
1116
-
1117
- // Create server file
1118
- const srcDir = path.join(templateDir, 'src');
1119
- fs.writeFileSync(
1120
- path.join(srcDir, 'server.js'),
1121
- `import express from 'express';
1122
- import { fileURLToPath } from 'url';
1123
- import { dirname, join } from 'path';
1124
- import compression from 'compression';
1125
- import morgan from 'morgan';
1126
-
1127
- const __filename = fileURLToPath(import.meta.url);
1128
- const __dirname = dirname(__filename);
1129
-
1130
- // Create the Express app
1131
- const app = express();
1132
- const PORT = process.env.PORT || 3001;
1133
-
1134
- // Apply middleware
1135
- app.use(compression());
1136
- app.use(morgan('dev'));
1137
- app.use(express.json());
1138
-
1139
- // Serve static files in production
1140
- if (process.env.NODE_ENV === 'production') {
1141
- const distPath = join(__dirname, '..');
1142
- app.use(express.static(distPath));
1143
- }
1144
-
1145
- // API routes
1146
- app.get('/api/hello', (req, res) => {
1147
- res.json({
1148
- message: 'Hello from Frontend Hamroun API!',
1149
- timestamp: new Date().toISOString()
1150
- });
1151
- });
1152
-
1153
- // Start the server
1154
- app.listen(PORT, () => {
1155
- console.log(\`Server running on port \${PORT}\`);
1156
- });
1157
- `
1158
- );
1159
-
1160
- console.log(`✅ Created full-stack template with server at ${templateDir}`);
1161
- }
1162
-
1163
- // Update how templates are checked and created
1164
- console.log('🔍 Checking template directories...');
1165
- for (const template of templateList) {
1166
- const templateDir = path.join(templatesDir, template);
1167
-
1168
- if (!fs.existsSync(templateDir)) {
1169
- console.log(`⚠️ Template directory "${template}" not found at: ${templateDir}`);
1170
- console.log(`📁 Creating template directory: ${template}`);
1171
- fs.mkdirSync(templateDir, { recursive: true });
1172
-
1173
- // Create appropriate template based on type
1174
- if (template === 'full-stack') {
1175
- createFullStackTemplate(templateDir);
1176
- } else {
1177
- createPureTemplate(templateDir);
1178
- }
1179
- } else {
1180
- console.log(`✅ Template found: ${template}`);
1181
-
1182
- // Update package.json in existing templates
1183
- const packageJsonPath = path.join(templateDir, 'package.json');
1184
- if (fs.existsSync(packageJsonPath)) {
1185
- try {
1186
- console.log(`📦 Updating package.json in ${template}`);
1187
- if (template === 'full-stack') {
1188
- createFullStackTemplate(templateDir);
1189
- } else {
1190
- createPureTemplate(templateDir);
1191
- }
1192
- } catch (error) {
1193
- console.error(`❌ Failed to update package.json in ${template}: ${error.message}`);
1194
- }
1195
- }
1196
- }
1197
- }
1198
-
1199
- console.log('✅ CLI build process completed');