frontend-hamroun 1.2.2 → 1.2.4

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 (35) hide show
  1. package/bin/cli.cjs +16 -0
  2. package/bin/cli.mjs +237 -0
  3. package/dist/frontend-hamroun.es.js +16 -32
  4. package/dist/frontend-hamroun.es.js.map +1 -1
  5. package/dist/frontend-hamroun.umd.js.map +1 -1
  6. package/package.json +5 -4
  7. package/scripts/build-cli.js +409 -121
  8. package/templates/basic/.eslintignore +5 -0
  9. package/templates/basic/.eslintrc.json +25 -0
  10. package/templates/basic/docs/rapport_pfe.aux +27 -0
  11. package/templates/basic/docs/rapport_pfe.log +399 -0
  12. package/templates/basic/docs/rapport_pfe.out +10 -0
  13. package/templates/basic/docs/rapport_pfe.pdf +0 -0
  14. package/templates/basic/docs/rapport_pfe.tex +68 -0
  15. package/templates/basic/docs/rapport_pfe.toc +14 -0
  16. package/templates/basic/index.html +12 -0
  17. package/templates/basic/package.json +30 -0
  18. package/templates/basic/postcss.config.js +7 -0
  19. package/templates/basic/src/App.tsx +65 -0
  20. package/templates/basic/src/api.ts +58 -0
  21. package/templates/basic/src/components/Counter.tsx +26 -0
  22. package/templates/basic/src/components/Header.tsx +9 -0
  23. package/templates/basic/src/components/TodoList.tsx +90 -0
  24. package/templates/basic/src/main.css +3 -0
  25. package/templates/basic/src/main.ts +20 -0
  26. package/templates/basic/src/main.tsx +144 -0
  27. package/templates/basic/src/server.ts +99 -0
  28. package/templates/basic/tailwind.config.js +32 -0
  29. package/templates/basic/tsconfig.json +13 -0
  30. package/templates/basic/vite.config.ts +86 -0
  31. package/templates/basic-app/package.json +5 -15
  32. package/templates/basic-app/vite.config.ts +66 -2
  33. package/templates/full-stack/package.json +2 -19
  34. package/templates/full-stack/vite.config.ts +79 -0
  35. package/bin/cli.js +0 -16
package/bin/cli.cjs ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ // This file is a CommonJS wrapper for the ES module CLI
3
+ // It loads the actual CLI implementation using dynamic import()
4
+
5
+ async function main() {
6
+ try {
7
+ // Use dynamic import to load the ES module CLI
8
+ const cliPath = new URL('../bin/cli.mjs', import.meta.url).href;
9
+ await import(cliPath);
10
+ } catch (error) {
11
+ console.error('Error loading CLI:', error);
12
+ process.exit(1);
13
+ }
14
+ }
15
+
16
+ main();
package/bin/cli.mjs ADDED
@@ -0,0 +1,237 @@
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
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ // Templates available
12
+ const TEMPLATES = {
13
+ 'basic': 'Basic frontend only template',
14
+ 'full-stack': 'Complete frontend and backend template'
15
+ };
16
+
17
+ // Colors for CLI output
18
+ const colors = {
19
+ reset: '\x1b[0m',
20
+ bright: '\x1b[1m',
21
+ green: '\x1b[32m',
22
+ blue: '\x1b[34m',
23
+ red: '\x1b[31m',
24
+ yellow: '\x1b[33m'
25
+ };
26
+
27
+ // Get package.json to read version
28
+ const packageJsonPath = path.resolve(__dirname, '../package.json');
29
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
30
+
31
+ // Print banner
32
+ function printBanner() {
33
+ console.log(`
34
+ ${colors.blue}${colors.bright}╔══════════════════════════════════════════════╗
35
+ ║ ║
36
+ ║ Frontend Hamroun v${packageJson.version.padEnd(25)}║
37
+ ║ A lightweight frontend & backend framework ║
38
+ ║ ║
39
+ ╚══════════════════════════════════════════════╝${colors.reset}
40
+ `);
41
+ }
42
+
43
+ // Print help
44
+ function printHelp() {
45
+ console.log(`
46
+ ${colors.bright}USAGE:${colors.reset}
47
+ ${colors.blue}npx frontend-hamroun${colors.reset} [command] [options]
48
+
49
+ ${colors.bright}COMMANDS:${colors.reset}
50
+ ${colors.blue}create${colors.reset} <project-name> [options] Create a new project
51
+ ${colors.blue}help${colors.reset} Display this help message
52
+ ${colors.blue}version${colors.reset} Display version information
53
+
54
+ ${colors.bright}OPTIONS:${colors.reset}
55
+ ${colors.blue}--template${colors.reset}, ${colors.blue}-t${colors.reset} <template> Specify template (default: basic)
56
+ ${colors.blue}--skip-install${colors.reset}, ${colors.blue}-s${colors.reset} Skip package installation
57
+
58
+ ${colors.bright}AVAILABLE TEMPLATES:${colors.reset}
59
+ ${Object.entries(TEMPLATES).map(([name, desc]) => ` ${colors.blue}${name.padEnd(12)}${colors.reset} ${desc}`).join('\n')}
60
+
61
+ ${colors.bright}EXAMPLES:${colors.reset}
62
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app
63
+ ${colors.blue}npx frontend-hamroun create${colors.reset} my-app --template full-stack
64
+ `);
65
+ }
66
+
67
+ // Create project from template
68
+ function createProject(projectName, options) {
69
+ const template = options.template || 'basic';
70
+
71
+ // Check if template exists
72
+ if (!Object.keys(TEMPLATES).includes(template)) {
73
+ console.error(`${colors.red}error:${colors.reset} Template "${template}" not found.`);
74
+ console.log(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`);
75
+ process.exit(1);
76
+ }
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
+
85
+ console.log(`
86
+ ${colors.bright}Creating a new project with Frontend Hamroun...${colors.reset}
87
+ ${colors.blue}• Project name:${colors.reset} ${projectName}
88
+ ${colors.blue}• Template:${colors.reset} ${template}
89
+ ${colors.blue}• Directory:${colors.reset} ${projectPath}
90
+ `);
91
+
92
+ try {
93
+ // Find templates directory
94
+ const templateDir = path.resolve(__dirname, '../templates', template);
95
+
96
+ if (!fs.existsSync(templateDir)) {
97
+ console.error(`${colors.red}error:${colors.reset} Template directory not found: ${templateDir}`);
98
+ // Try to find template with -app suffix as fallback
99
+ const fallbackTemplateDir = path.resolve(__dirname, '../templates', `${template}-app`);
100
+ if (fs.existsSync(fallbackTemplateDir)) {
101
+ console.log(`${colors.yellow}Using fallback template:${colors.reset} ${template}-app`);
102
+ templateDir = fallbackTemplateDir;
103
+ } else {
104
+ process.exit(1);
105
+ }
106
+ }
107
+
108
+ // Create project directory
109
+ fs.mkdirSync(projectPath, { recursive: true });
110
+
111
+ // Copy template files (recursive function)
112
+ function copyDir(src, dest) {
113
+ const entries = fs.readdirSync(src, { withFileTypes: true });
114
+
115
+ for (const entry of entries) {
116
+ const srcPath = path.join(src, entry.name);
117
+ const destPath = path.join(dest, entry.name);
118
+
119
+ if (entry.isDirectory()) {
120
+ fs.mkdirSync(destPath, { recursive: true });
121
+ copyDir(srcPath, destPath);
122
+ } else {
123
+ fs.copyFileSync(srcPath, destPath);
124
+ }
125
+ }
126
+ }
127
+
128
+ // Copy the files
129
+ copyDir(templateDir, projectPath);
130
+ console.log(`${colors.green}•${colors.reset} Copied template files`);
131
+
132
+ // Update package.json with project name
133
+ const projectPackageJsonPath = path.join(projectPath, 'package.json');
134
+ if (fs.existsSync(projectPackageJsonPath)) {
135
+ const projectPackageJson = JSON.parse(fs.readFileSync(projectPackageJsonPath, 'utf8'));
136
+ projectPackageJson.name = projectName;
137
+ fs.writeFileSync(
138
+ projectPackageJsonPath,
139
+ JSON.stringify(projectPackageJson, null, 2)
140
+ );
141
+ }
142
+
143
+ // Install dependencies
144
+ if (!options.skipInstall) {
145
+ console.log(`\n${colors.blue}Installing dependencies...${colors.reset}`);
146
+
147
+ try {
148
+ execSync(`npm install`, {
149
+ cwd: projectPath,
150
+ stdio: 'inherit'
151
+ });
152
+ } catch (error) {
153
+ console.error(`\n${colors.red}Failed to install dependencies. You can install them manually:${colors.reset}`);
154
+ console.log(` cd ${projectName} && npm install`);
155
+ }
156
+ }
157
+
158
+ // Success message
159
+ console.log(`
160
+ ${colors.green}${colors.bright}Success!${colors.reset} Created ${projectName} at ${projectPath}
161
+
162
+ ${colors.blue}Inside that directory, you can run several commands:${colors.reset}
163
+
164
+ ${colors.bright}npm run dev${colors.reset}
165
+ Starts the development server.
166
+
167
+ ${colors.bright}npm run build${colors.reset}
168
+ Builds the app for production.
169
+
170
+ ${colors.bright}npm start${colors.reset}
171
+ Runs the built app in production mode.
172
+
173
+ ${colors.blue}We suggest that you begin by typing:${colors.reset}
174
+
175
+ ${colors.bright}cd${colors.reset} ${projectName}
176
+ ${colors.bright}npm run dev${colors.reset}
177
+
178
+ ${colors.green}Happy coding!${colors.reset}
179
+ `);
180
+
181
+ } catch (error) {
182
+ console.error(`${colors.red}Failed to create project:${colors.reset}`, error);
183
+ process.exit(1);
184
+ }
185
+ }
186
+
187
+ // Parse command line arguments
188
+ function parseArgs() {
189
+ const args = process.argv.slice(2);
190
+ const command = args[0];
191
+
192
+ if (!command || command === 'help') {
193
+ printBanner();
194
+ printHelp();
195
+ process.exit(0);
196
+ }
197
+
198
+ if (command === 'version') {
199
+ console.log(`frontend-hamroun v${packageJson.version}`);
200
+ process.exit(0);
201
+ }
202
+
203
+ if (command === 'create') {
204
+ const projectName = args[1];
205
+
206
+ if (!projectName) {
207
+ console.error(`${colors.red}error:${colors.reset} Project name is required.`);
208
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
209
+ process.exit(1);
210
+ }
211
+
212
+ // Parse options
213
+ const options = {
214
+ template: 'basic',
215
+ skipInstall: false
216
+ };
217
+
218
+ for (let i = 2; i < args.length; i++) {
219
+ if (args[i] === '--template' || args[i] === '-t') {
220
+ options.template = args[++i];
221
+ } else if (args[i] === '--skip-install' || args[i] === '-s') {
222
+ options.skipInstall = true;
223
+ }
224
+ }
225
+
226
+ printBanner();
227
+ createProject(projectName, options);
228
+ return;
229
+ }
230
+
231
+ console.error(`${colors.red}error:${colors.reset} Unknown command: ${command}`);
232
+ console.log(`Run ${colors.blue}npx frontend-hamroun help${colors.reset} for usage information.`);
233
+ process.exit(1);
234
+ }
235
+
236
+ // Run CLI
237
+ parseArgs();
@@ -137,8 +137,7 @@ async function createElement(vnode) {
137
137
  }
138
138
  };
139
139
  for (const [key, value] of Object.entries(props || {})) {
140
- if (key === "children")
141
- continue;
140
+ if (key === "children") continue;
142
141
  if (key.startsWith("on") && typeof value === "function") {
143
142
  const eventName = key.toLowerCase().slice(2);
144
143
  if (!element.__events) {
@@ -199,8 +198,7 @@ async function createElement(vnode) {
199
198
  }
200
199
  const element = document.createElement(type);
201
200
  for (const [key, value] of Object.entries(props || {})) {
202
- if (key === "children")
203
- continue;
201
+ if (key === "children") continue;
204
202
  if (key.startsWith("on") && typeof value === "function") {
205
203
  const eventName = key.toLowerCase().slice(2);
206
204
  const existingHandler = (_a = element.__events) == null ? void 0 : _a[eventName];
@@ -280,8 +278,7 @@ class Component {
280
278
  }
281
279
  async update() {
282
280
  const vdom = this.render();
283
- if (!vdom)
284
- return document.createTextNode("");
281
+ if (!vdom) return document.createTextNode("");
285
282
  const rendered = await createElement(vdom);
286
283
  if (rendered instanceof HTMLElement) {
287
284
  return this._updateElement(rendered);
@@ -384,8 +381,7 @@ function useState(initial) {
384
381
  const state = componentStates[index2];
385
382
  const setState = (newValue) => {
386
383
  const nextValue = typeof newValue === "function" ? newValue(componentStates[index2]) : newValue;
387
- if (componentStates[index2] === nextValue)
388
- return;
384
+ if (componentStates[index2] === nextValue) return;
389
385
  componentStates[index2] = nextValue;
390
386
  if (isBatching) {
391
387
  batchUpdates(() => rerender(currentRender));
@@ -397,8 +393,7 @@ function useState(initial) {
397
393
  return [state, setState];
398
394
  }
399
395
  function useEffect(callback, deps) {
400
- if (!currentRender)
401
- throw new Error("useEffect must be called within a render");
396
+ if (!currentRender) throw new Error("useEffect must be called within a render");
402
397
  const effectIndex = stateIndices.get(currentRender);
403
398
  if (!effects.has(currentRender)) {
404
399
  effects.set(currentRender, []);
@@ -417,8 +412,7 @@ function useEffect(callback, deps) {
417
412
  stateIndices.set(currentRender, effectIndex + 1);
418
413
  }
419
414
  function useMemo(factory, deps) {
420
- if (!currentRender)
421
- throw new Error("useMemo must be called within a render");
415
+ if (!currentRender) throw new Error("useMemo must be called within a render");
422
416
  const memoIndex = stateIndices.get(currentRender);
423
417
  if (!memos.has(currentRender)) {
424
418
  memos.set(currentRender, []);
@@ -435,8 +429,7 @@ function useMemo(factory, deps) {
435
429
  return prevMemo.value;
436
430
  }
437
431
  function useRef(initial) {
438
- if (!currentRender)
439
- throw new Error("useRef must be called within a render");
432
+ if (!currentRender) throw new Error("useRef must be called within a render");
440
433
  const refIndex = stateIndices.get(currentRender);
441
434
  if (!refs.has(currentRender)) {
442
435
  refs.set(currentRender, []);
@@ -457,8 +450,7 @@ async function rerender(rendererId) {
457
450
  const componentEffects = effects.get(rendererId);
458
451
  if (componentEffects) {
459
452
  componentEffects.forEach((effect) => {
460
- if (effect.cleanup)
461
- effect.cleanup();
453
+ if (effect.cleanup) effect.cleanup();
462
454
  });
463
455
  effects.set(rendererId, []);
464
456
  }
@@ -507,10 +499,8 @@ async function renderToString(element) {
507
499
  setRenderCallback(() => {
508
500
  }, element, null);
509
501
  try {
510
- if (element == null)
511
- return "";
512
- if (typeof element === "boolean")
513
- return "";
502
+ if (element == null) return "";
503
+ if (typeof element === "boolean") return "";
514
504
  if (typeof element === "number" || typeof element === "string") {
515
505
  return escapeHtml(String(element));
516
506
  }
@@ -542,8 +532,7 @@ async function renderToString(element) {
542
532
  }
543
533
  let html = `<${type}`;
544
534
  for (const [key, value] of Object.entries(props || {})) {
545
- if (key === "children" || key === "key")
546
- continue;
535
+ if (key === "children" || key === "key") continue;
547
536
  if (key === "className") {
548
537
  html += ` class="${escapeHtml(String(value))}"`;
549
538
  } else if (key === "style" && typeof value === "object") {
@@ -884,8 +873,7 @@ ${Object.keys(ssrRoutes).length > 0 ? `
884
873
  🖥️ Registered SSR Routes:
885
874
  ${Object.keys(ssrRoutes).map((route) => ` ${route}`).join("\n")}` : ""}
886
875
  `);
887
- if (callback)
888
- callback();
876
+ if (callback) callback();
889
877
  });
890
878
  const gracefulShutdown = async (signal) => {
891
879
  console.log(`${signal} signal received: closing HTTP server and cleaning up`);
@@ -1020,14 +1008,10 @@ function createApiRouter$1(routeConfig, options = {}) {
1020
1008
  }
1021
1009
  function apiResponse(success, data, message, error, meta) {
1022
1010
  const response = { success };
1023
- if (data !== void 0)
1024
- response.data = data;
1025
- if (message)
1026
- response.message = message;
1027
- if (error)
1028
- response.error = error;
1029
- if (meta)
1030
- response.meta = meta;
1011
+ if (data !== void 0) response.data = data;
1012
+ if (message) response.message = message;
1013
+ if (error) response.error = error;
1014
+ if (meta) response.meta = meta;
1031
1015
  return response;
1032
1016
  }
1033
1017
  function sendSuccess(res, data, message, statusCode = 200, meta) {