baraqex 1.0.19 → 1.0.21
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/README.md +595 -0
- package/bin/baraqex.js +612 -0
- package/dist/server/api-router.d.ts.map +1 -1
- package/dist/server/api-router.js +42 -14
- package/dist/server/api-router.js.map +1 -1
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/wasm.d.ts.map +1 -1
- package/dist/server/wasm.js +41 -14
- package/dist/server/wasm.js.map +1 -1
- package/package.json +22 -5
package/bin/baraqex.js
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import gradient from 'gradient-string';
|
|
7
|
+
import { createSpinner } from 'nanospinner';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import fs from 'fs-extra';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { exec } from 'child_process';
|
|
12
|
+
import { promisify } from 'util';
|
|
13
|
+
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
|
+
|
|
19
|
+
// Convert to ESM-friendly __dirname equivalent
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = path.dirname(__filename);
|
|
22
|
+
const execAsync = promisify(exec);
|
|
23
|
+
|
|
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 baraqex')} 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
|
+
// CLI instance
|
|
47
|
+
const program = new Command();
|
|
48
|
+
|
|
49
|
+
// Create beautiful ASCII art banner with gradient colors
|
|
50
|
+
const displayBanner = () => {
|
|
51
|
+
const titleText = figlet.textSync('Baraqex', {
|
|
52
|
+
font: 'Standard',
|
|
53
|
+
horizontalLayout: 'default',
|
|
54
|
+
verticalLayout: 'default'
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
console.log('\n' + gradient.pastel.multiline(titleText));
|
|
58
|
+
|
|
59
|
+
console.log(boxen(
|
|
60
|
+
`${chalk.bold('A powerful full-stack framework with WebAssembly integration')}\n\n` +
|
|
61
|
+
`${chalk.dim('Version:')} ${chalk.cyan(JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')).version)}\n` +
|
|
62
|
+
`${chalk.dim('Website:')} ${terminalLink('www.baraqex.tech', 'https://www.baraqex.tech')}`,
|
|
63
|
+
{
|
|
64
|
+
padding: 1,
|
|
65
|
+
margin: { top: 1, bottom: 1 },
|
|
66
|
+
borderStyle: 'round',
|
|
67
|
+
borderColor: 'cyan'
|
|
68
|
+
}
|
|
69
|
+
));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Version and description
|
|
73
|
+
program
|
|
74
|
+
.name('baraqex')
|
|
75
|
+
.description('CLI for Baraqex - A powerful full-stack JavaScript/TypeScript framework with WebAssembly integration')
|
|
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
|
+
// Check for Go (optional, for WASM features)
|
|
116
|
+
try {
|
|
117
|
+
const goVersionOutput = await execAsync('go version');
|
|
118
|
+
const goVersion = goVersionOutput.stdout.match(/go(\d+\.\d+\.\d+)/)?.[1] || 'unknown';
|
|
119
|
+
spinner.succeed(`Environment ready: Node ${chalk.green(nodeVersion)}, npm ${chalk.green(npmVersion)}, Go ${chalk.green(goVersion)}`);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
spinner.succeed(`Environment ready: Node ${chalk.green(nodeVersion)}, npm ${chalk.green(npmVersion)} ${chalk.yellow('(Go not found - WebAssembly features limited)')}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return true;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
spinner.fail('Environment check failed');
|
|
127
|
+
console.log(chalk.red('Error: Node.js and npm are required to use this tool.'));
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Compare versions helper
|
|
133
|
+
function compareVersions(a, b) {
|
|
134
|
+
const aParts = a.split('.').map(Number);
|
|
135
|
+
const bParts = b.split('.').map(Number);
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
138
|
+
const aVal = aParts[i] || 0;
|
|
139
|
+
const bVal = bParts[i] || 0;
|
|
140
|
+
|
|
141
|
+
if (aVal > bVal) return 1;
|
|
142
|
+
if (aVal < bVal) return -1;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Choose template interactively with improved visualization
|
|
149
|
+
async function chooseTemplate() {
|
|
150
|
+
const templatesPath = path.join(__dirname, '..', 'templates');
|
|
151
|
+
|
|
152
|
+
// Create templates directory if it doesn't exist
|
|
153
|
+
if (!fs.existsSync(templatesPath)) {
|
|
154
|
+
fs.mkdirSync(templatesPath, { recursive: true });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const templates = fs.readdirSync(templatesPath).filter(file =>
|
|
158
|
+
fs.statSync(path.join(templatesPath, file)).isDirectory()
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// If no templates exist, create default ones
|
|
162
|
+
if (templates.length === 0) {
|
|
163
|
+
await createDefaultTemplates(templatesPath);
|
|
164
|
+
const newTemplates = fs.readdirSync(templatesPath).filter(file =>
|
|
165
|
+
fs.statSync(path.join(templatesPath, file)).isDirectory()
|
|
166
|
+
);
|
|
167
|
+
templates.push(...newTemplates);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Emoji indicators for templates
|
|
171
|
+
const templateIcons = {
|
|
172
|
+
'basic-app': '🚀',
|
|
173
|
+
'ssr-template': '🌐',
|
|
174
|
+
'fullstack-app': '⚡',
|
|
175
|
+
'go-wasm-app': '🔄',
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Detailed descriptions
|
|
179
|
+
const templateDescriptions = {
|
|
180
|
+
'basic-app': 'Single-page application with just the essentials. Perfect for learning the framework or building simple apps.',
|
|
181
|
+
'ssr-template': 'Server-side rendered application with hydration. Optimized for SEO and fast initial load.',
|
|
182
|
+
'fullstack-app': 'Complete solution with API routes, authentication, and database integration ready to go.',
|
|
183
|
+
'go-wasm-app': 'WebAssembly integration with Go for high-performance computing in the browser and Node.js.'
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
console.log(boxen(
|
|
187
|
+
`${chalk.bold('Available Project Templates')}\n\n` +
|
|
188
|
+
templates.map(template => {
|
|
189
|
+
const icon = templateIcons[template] || '📦';
|
|
190
|
+
const shortDesc = {
|
|
191
|
+
'basic-app': 'Simple client-side application',
|
|
192
|
+
'ssr-template': 'Server-side rendering with hydration',
|
|
193
|
+
'fullstack-app': 'Complete fullstack application with API',
|
|
194
|
+
'go-wasm-app': 'WebAssembly integration with Go'
|
|
195
|
+
}[template] || 'Application template';
|
|
196
|
+
|
|
197
|
+
return `${icon} ${chalk.cyan(template)}\n ${chalk.dim(shortDesc)}`;
|
|
198
|
+
}).join('\n\n'),
|
|
199
|
+
{
|
|
200
|
+
padding: 1,
|
|
201
|
+
margin: 1,
|
|
202
|
+
borderStyle: 'round',
|
|
203
|
+
borderColor: 'cyan'
|
|
204
|
+
}
|
|
205
|
+
));
|
|
206
|
+
|
|
207
|
+
const templateChoices = templates.map(template => ({
|
|
208
|
+
name: `${templateIcons[template] || '📦'} ${chalk.bold(template)}`,
|
|
209
|
+
value: template,
|
|
210
|
+
description: templateDescriptions[template] || 'An application template'
|
|
211
|
+
}));
|
|
212
|
+
|
|
213
|
+
const answers = await inquirer.prompt([
|
|
214
|
+
{
|
|
215
|
+
type: 'list',
|
|
216
|
+
name: 'template',
|
|
217
|
+
message: chalk.green('Select a project template:'),
|
|
218
|
+
choices: templateChoices,
|
|
219
|
+
loop: false,
|
|
220
|
+
pageSize: 10
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
type: 'confirm',
|
|
224
|
+
name: 'viewDetails',
|
|
225
|
+
message: 'Would you like to see template details before proceeding?',
|
|
226
|
+
default: false
|
|
227
|
+
}
|
|
228
|
+
]);
|
|
229
|
+
|
|
230
|
+
if (answers.viewDetails) {
|
|
231
|
+
const detailedDescription = {
|
|
232
|
+
'basic-app': [
|
|
233
|
+
`${chalk.bold('Basic App Template')} ${templateIcons['basic-app']}`,
|
|
234
|
+
'',
|
|
235
|
+
`${chalk.dim('A lightweight client-side application template.')}`,
|
|
236
|
+
'',
|
|
237
|
+
`${chalk.yellow('Features:')}`,
|
|
238
|
+
'• Modern JSX components without dependencies',
|
|
239
|
+
'• Built-in state management with hooks',
|
|
240
|
+
'• Component-based architecture',
|
|
241
|
+
'• Zero-config development setup',
|
|
242
|
+
'',
|
|
243
|
+
`${chalk.yellow('Best for:')}`,
|
|
244
|
+
'• Simple web applications',
|
|
245
|
+
'• Learning the framework',
|
|
246
|
+
'• Quick prototyping',
|
|
247
|
+
],
|
|
248
|
+
'ssr-template': [
|
|
249
|
+
`${chalk.bold('SSR Template')} ${templateIcons['ssr-template']}`,
|
|
250
|
+
'',
|
|
251
|
+
`${chalk.dim('Server-side rendering with client hydration.')}`,
|
|
252
|
+
'',
|
|
253
|
+
`${chalk.yellow('Features:')}`,
|
|
254
|
+
'• SEO-friendly rendered HTML',
|
|
255
|
+
'• Fast initial page load',
|
|
256
|
+
'• Smooth client-side transitions',
|
|
257
|
+
'• Built-in dynamic meta tag generation',
|
|
258
|
+
'• Express.js integration',
|
|
259
|
+
'',
|
|
260
|
+
`${chalk.yellow('Best for:')}`,
|
|
261
|
+
'• Production websites needing SEO',
|
|
262
|
+
'• Content-focused applications',
|
|
263
|
+
'• Sites requiring social sharing previews'
|
|
264
|
+
],
|
|
265
|
+
'fullstack-app': [
|
|
266
|
+
`${chalk.bold('Fullstack App Template')} ${templateIcons['fullstack-app']}`,
|
|
267
|
+
'',
|
|
268
|
+
`${chalk.dim('Complete solution with frontend and backend.')}`,
|
|
269
|
+
'',
|
|
270
|
+
`${chalk.yellow('Features:')}`,
|
|
271
|
+
'• API routes with Express integration',
|
|
272
|
+
'• File-based routing system',
|
|
273
|
+
'• Authentication system with JWT',
|
|
274
|
+
'• Database connectors (MongoDB, MySQL, PostgreSQL)',
|
|
275
|
+
'• Server-side rendering with hydration',
|
|
276
|
+
'• WebSocket support',
|
|
277
|
+
'',
|
|
278
|
+
`${chalk.yellow('Best for:')}`,
|
|
279
|
+
'• Full production applications',
|
|
280
|
+
'• Apps needing authentication',
|
|
281
|
+
'• Projects requiring database integration'
|
|
282
|
+
],
|
|
283
|
+
'go-wasm-app': [
|
|
284
|
+
`${chalk.bold('Go WASM App Template')} ${templateIcons['go-wasm-app'] || '🔄'}`,
|
|
285
|
+
'',
|
|
286
|
+
`${chalk.dim('WebAssembly integration with Go programming language.')}`,
|
|
287
|
+
'',
|
|
288
|
+
`${chalk.yellow('Features:')}`,
|
|
289
|
+
'• Go + WebAssembly integration',
|
|
290
|
+
'• High-performance computation in browser',
|
|
291
|
+
'• Server-side WASM processing',
|
|
292
|
+
'• Shared code between Go and JavaScript',
|
|
293
|
+
'• Optimized build pipeline',
|
|
294
|
+
'',
|
|
295
|
+
`${chalk.yellow('Best for:')}`,
|
|
296
|
+
'• Computation-heavy applications',
|
|
297
|
+
'• Projects requiring Go libraries',
|
|
298
|
+
'• Performance-critical features'
|
|
299
|
+
]
|
|
300
|
+
}[answers.template] || ['No detailed information available for this template'];
|
|
301
|
+
|
|
302
|
+
console.log(boxen(detailedDescription.join('\n'), {
|
|
303
|
+
padding: 1,
|
|
304
|
+
margin: 1,
|
|
305
|
+
title: answers.template,
|
|
306
|
+
titleAlignment: 'center',
|
|
307
|
+
borderStyle: 'round',
|
|
308
|
+
borderColor: 'yellow'
|
|
309
|
+
}));
|
|
310
|
+
|
|
311
|
+
const proceed = await inquirer.prompt([{
|
|
312
|
+
type: 'confirm',
|
|
313
|
+
name: 'continue',
|
|
314
|
+
message: 'Continue with this template?',
|
|
315
|
+
default: true
|
|
316
|
+
}]);
|
|
317
|
+
|
|
318
|
+
if (!proceed.continue) {
|
|
319
|
+
return chooseTemplate();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return answers.template;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Create default templates if they don't exist
|
|
327
|
+
async function createDefaultTemplates(templatesPath) {
|
|
328
|
+
const templates = {
|
|
329
|
+
'basic-app': {
|
|
330
|
+
'package.json': {
|
|
331
|
+
name: 'baraqex-basic-app',
|
|
332
|
+
version: '1.0.0',
|
|
333
|
+
scripts: {
|
|
334
|
+
dev: 'baraqex dev',
|
|
335
|
+
build: 'baraqex build',
|
|
336
|
+
start: 'baraqex start'
|
|
337
|
+
},
|
|
338
|
+
dependencies: {
|
|
339
|
+
baraqex: '^1.0.0'
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
'src/App.jsx': `import { jsx, useState } from 'baraqex';
|
|
343
|
+
|
|
344
|
+
export default function App() {
|
|
345
|
+
const [count, setCount] = useState(0);
|
|
346
|
+
|
|
347
|
+
return (
|
|
348
|
+
<div>
|
|
349
|
+
<h1>Welcome to Baraqex!</h1>
|
|
350
|
+
<p>Count: {count}</p>
|
|
351
|
+
<button onClick={() => setCount(count + 1)}>
|
|
352
|
+
Increment
|
|
353
|
+
</button>
|
|
354
|
+
</div>
|
|
355
|
+
);
|
|
356
|
+
}`,
|
|
357
|
+
'public/index.html': `<!DOCTYPE html>
|
|
358
|
+
<html lang="en">
|
|
359
|
+
<head>
|
|
360
|
+
<meta charset="UTF-8">
|
|
361
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
362
|
+
<title>Baraqex App</title>
|
|
363
|
+
</head>
|
|
364
|
+
<body>
|
|
365
|
+
<div id="root"></div>
|
|
366
|
+
<script src="/src/App.jsx" type="module"></script>
|
|
367
|
+
</body>
|
|
368
|
+
</html>`
|
|
369
|
+
},
|
|
370
|
+
'fullstack-app': {
|
|
371
|
+
'package.json': {
|
|
372
|
+
name: 'baraqex-fullstack-app',
|
|
373
|
+
version: '1.0.0',
|
|
374
|
+
scripts: {
|
|
375
|
+
dev: 'baraqex dev',
|
|
376
|
+
build: 'baraqex build',
|
|
377
|
+
start: 'baraqex start',
|
|
378
|
+
test: 'baraqex test'
|
|
379
|
+
},
|
|
380
|
+
dependencies: {
|
|
381
|
+
baraqex: '^1.0.0'
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
'src/pages/index.jsx': `import { jsx } from 'baraqex';
|
|
385
|
+
|
|
386
|
+
export default function HomePage(props) {
|
|
387
|
+
return (
|
|
388
|
+
<html>
|
|
389
|
+
<head>
|
|
390
|
+
<title>Baraqex Fullstack App</title>
|
|
391
|
+
</head>
|
|
392
|
+
<body>
|
|
393
|
+
<h1>Welcome to Baraqex!</h1>
|
|
394
|
+
<p>Server time: {props.api.serverTime}</p>
|
|
395
|
+
</body>
|
|
396
|
+
</html>
|
|
397
|
+
);
|
|
398
|
+
}`,
|
|
399
|
+
'src/api/hello.js': `export async function get(req, res) {
|
|
400
|
+
res.json({ message: 'Hello from Baraqex API!' });
|
|
401
|
+
}`
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
for (const [templateName, files] of Object.entries(templates)) {
|
|
406
|
+
const templatePath = path.join(templatesPath, templateName);
|
|
407
|
+
await fs.ensureDir(templatePath);
|
|
408
|
+
|
|
409
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
410
|
+
const fullPath = path.join(templatePath, filePath);
|
|
411
|
+
await fs.ensureDir(path.dirname(fullPath));
|
|
412
|
+
|
|
413
|
+
if (typeof content === 'object') {
|
|
414
|
+
await fs.writeJson(fullPath, content, { spaces: 2 });
|
|
415
|
+
} else {
|
|
416
|
+
await fs.writeFile(fullPath, content);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Create a new project with enhanced visuals and status updates
|
|
423
|
+
async function createProject(projectName, options) {
|
|
424
|
+
displayBanner();
|
|
425
|
+
createSection('Project Setup');
|
|
426
|
+
|
|
427
|
+
if (!projectName) {
|
|
428
|
+
const answers = await inquirer.prompt([
|
|
429
|
+
{
|
|
430
|
+
type: 'input',
|
|
431
|
+
name: 'projectName',
|
|
432
|
+
message: chalk.green('What is your project name?'),
|
|
433
|
+
default: 'my-baraqex-app',
|
|
434
|
+
validate: input =>
|
|
435
|
+
/^[a-z0-9-_]+$/.test(input)
|
|
436
|
+
? true
|
|
437
|
+
: 'Project name can only contain lowercase letters, numbers, hyphens, and underscores'
|
|
438
|
+
}
|
|
439
|
+
]);
|
|
440
|
+
projectName = answers.projectName;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (!await checkDependencies()) return;
|
|
444
|
+
|
|
445
|
+
let template = options.template || await chooseTemplate();
|
|
446
|
+
|
|
447
|
+
const targetDir = path.resolve(projectName);
|
|
448
|
+
const templateDir = path.join(__dirname, '..', 'templates', template);
|
|
449
|
+
|
|
450
|
+
if (fs.existsSync(targetDir)) {
|
|
451
|
+
const answers = await inquirer.prompt([
|
|
452
|
+
{
|
|
453
|
+
type: 'confirm',
|
|
454
|
+
name: 'overwrite',
|
|
455
|
+
message: chalk.yellow(`Directory ${projectName} already exists. Overwrite?`),
|
|
456
|
+
default: false
|
|
457
|
+
}
|
|
458
|
+
]);
|
|
459
|
+
if (!answers.overwrite) {
|
|
460
|
+
console.log(chalk.red('✖ Operation cancelled'));
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Multi-step execution with progress reporting
|
|
466
|
+
console.log(chalk.dim('\nCreating your new Baraqex project...'));
|
|
467
|
+
|
|
468
|
+
// Step 1: Create directory
|
|
469
|
+
const step1 = ora({text: 'Creating project directory', color: 'cyan'}).start();
|
|
470
|
+
try {
|
|
471
|
+
await fs.ensureDir(targetDir);
|
|
472
|
+
step1.succeed();
|
|
473
|
+
} catch (error) {
|
|
474
|
+
step1.fail();
|
|
475
|
+
console.error(chalk.red(`Error creating directory: ${error.message}`));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Step 2: Copy template files
|
|
480
|
+
const step2 = ora({text: 'Copying template files', color: 'cyan'}).start();
|
|
481
|
+
try {
|
|
482
|
+
await fs.copy(templateDir, targetDir, { overwrite: true });
|
|
483
|
+
step2.succeed();
|
|
484
|
+
} catch (error) {
|
|
485
|
+
step2.fail();
|
|
486
|
+
console.error(chalk.red(`Error copying files: ${error.message}`));
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Step 3: Update package.json
|
|
491
|
+
const step3 = ora({text: 'Configuring package.json', color: 'cyan'}).start();
|
|
492
|
+
try {
|
|
493
|
+
const pkgJsonPath = path.join(targetDir, 'package.json');
|
|
494
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
495
|
+
const pkgJson = await fs.readJson(pkgJsonPath);
|
|
496
|
+
pkgJson.name = projectName;
|
|
497
|
+
await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
498
|
+
step3.succeed();
|
|
499
|
+
} else {
|
|
500
|
+
step3.warn('No package.json found in template');
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
step3.fail();
|
|
504
|
+
console.error(chalk.red(`Error updating package.json: ${error.message}`));
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Final success message with helpful instructions
|
|
509
|
+
console.log('\n' + boxen(
|
|
510
|
+
`${chalk.bold.green('Project created successfully!')}\n\n` +
|
|
511
|
+
`${chalk.bold('Project:')} ${chalk.cyan(projectName)}\n` +
|
|
512
|
+
`${chalk.bold('Template:')} ${chalk.cyan(template)}\n` +
|
|
513
|
+
`${chalk.bold('Location:')} ${chalk.cyan(targetDir)}\n\n` +
|
|
514
|
+
`${chalk.bold.yellow('Next steps:')}\n\n` +
|
|
515
|
+
` ${chalk.dim('1.')} ${chalk.cyan(`cd ${projectName}`)}\n` +
|
|
516
|
+
` ${chalk.dim('2.')} ${chalk.cyan('npm install')}\n` +
|
|
517
|
+
` ${chalk.dim('3.')} ${chalk.cyan('npm run dev')}\n\n` +
|
|
518
|
+
`${chalk.dim('For help and documentation:')} ${terminalLink('www.baraqex.tech', 'https://www.baraqex.tech')}`,
|
|
519
|
+
{
|
|
520
|
+
padding: 1,
|
|
521
|
+
margin: 1,
|
|
522
|
+
borderStyle: 'round',
|
|
523
|
+
borderColor: 'green'
|
|
524
|
+
}
|
|
525
|
+
));
|
|
526
|
+
|
|
527
|
+
// Suggest next command
|
|
528
|
+
console.log(`\n${chalk.cyan('Tip:')} Run ${chalk.bold.green(`cd ${projectName} && npm install`)} to get started right away.\n`);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ...existing code... (add:component, dev:tools, and all other functions remain the same but update references)
|
|
532
|
+
|
|
533
|
+
// Dashboard when no commands are specified
|
|
534
|
+
function showDashboard() {
|
|
535
|
+
displayBanner();
|
|
536
|
+
|
|
537
|
+
const commands = [
|
|
538
|
+
{ name: 'create', description: 'Create a new project', command: 'baraqex create my-app' },
|
|
539
|
+
{ name: 'add:component', description: 'Add a new UI component', command: 'baraqex add:component Button' },
|
|
540
|
+
{ name: 'add:page', description: 'Create a new page', command: 'baraqex add:page home' },
|
|
541
|
+
{ name: 'add:api', description: 'Create a new API endpoint', command: 'baraqex add:api users' },
|
|
542
|
+
{ name: 'dev:tools', description: 'Show development tools', command: 'baraqex dev:tools' },
|
|
543
|
+
{ name: 'test:server', description: 'Test server functions', command: 'baraqex test:server' }
|
|
544
|
+
];
|
|
545
|
+
|
|
546
|
+
console.log(boxen(
|
|
547
|
+
`${chalk.bold.cyan('Welcome to Baraqex CLI!')}\n\n` +
|
|
548
|
+
`Select a command to get started or run ${chalk.yellow('baraqex <command> --help')} for more info.\n`,
|
|
549
|
+
{
|
|
550
|
+
padding: 1,
|
|
551
|
+
margin: { top: 1, bottom: 1 },
|
|
552
|
+
borderStyle: 'round',
|
|
553
|
+
borderColor: 'cyan'
|
|
554
|
+
}
|
|
555
|
+
));
|
|
556
|
+
|
|
557
|
+
console.log(`${chalk.bold.cyan('Available Commands:')}\n`);
|
|
558
|
+
commands.forEach((cmd, i) => {
|
|
559
|
+
console.log(` ${chalk.green((i+1) + '.')} ${chalk.bold(cmd.name.padEnd(15))} ${chalk.dim(cmd.description)}`);
|
|
560
|
+
console.log(` ${chalk.yellow(cmd.command)}\n`);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
console.log(boxen(
|
|
564
|
+
`${chalk.bold('Quick Start:')} ${chalk.yellow('baraqex create my-app')}\n` +
|
|
565
|
+
`${chalk.dim('More info:')} ${terminalLink('www.baraqex.tech', 'https://www.baraqex.tech')}`,
|
|
566
|
+
{
|
|
567
|
+
padding: 0.5,
|
|
568
|
+
margin: { top: 1 },
|
|
569
|
+
borderStyle: 'round',
|
|
570
|
+
borderColor: 'blue'
|
|
571
|
+
}
|
|
572
|
+
));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Register commands with improved descriptions
|
|
576
|
+
program
|
|
577
|
+
.command('create [name]')
|
|
578
|
+
.description('Create a new Baraqex project')
|
|
579
|
+
.option('-t, --template <template>', 'Specify template (basic-app, ssr-template, fullstack-app, go-wasm-app)')
|
|
580
|
+
.action(createProject);
|
|
581
|
+
|
|
582
|
+
program
|
|
583
|
+
.command('test:server')
|
|
584
|
+
.description('Run server function tests')
|
|
585
|
+
.action(async () => {
|
|
586
|
+
displayBanner();
|
|
587
|
+
createSection('Server Function Testing');
|
|
588
|
+
|
|
589
|
+
const spinner = ora('Running server tests...').start();
|
|
590
|
+
|
|
591
|
+
try {
|
|
592
|
+
// Import and run the test-server.js file
|
|
593
|
+
const { runAllTests } = await import('../test-server.js');
|
|
594
|
+
const success = await runAllTests();
|
|
595
|
+
|
|
596
|
+
if (success) {
|
|
597
|
+
spinner.succeed('All server tests passed!');
|
|
598
|
+
} else {
|
|
599
|
+
spinner.fail('Some server tests failed');
|
|
600
|
+
}
|
|
601
|
+
} catch (error) {
|
|
602
|
+
spinner.fail('Failed to run server tests');
|
|
603
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// Default command when no arguments
|
|
608
|
+
if (process.argv.length <= 2) {
|
|
609
|
+
showDashboard();
|
|
610
|
+
} else {
|
|
611
|
+
program.parse(process.argv);
|
|
612
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-router.d.ts","sourceRoot":"","sources":["../../src/server/api-router.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"api-router.d.ts","sourceRoot":"","sources":["../../src/server/api-router.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAmBxC,qBAAa,SAAS;IACb,MAAM,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAqB;gBAErB,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,WAAW,GAAG,IAAW;IAQ3D,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;YAiBN,aAAa;IAuE3B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
4
5
|
export class ApiRouter {
|
|
5
6
|
constructor(apiDir, auth = null) {
|
|
6
7
|
this.router = express.Router();
|
|
@@ -50,21 +51,48 @@ export class ApiRouter {
|
|
|
50
51
|
}
|
|
51
52
|
async registerRoute(filePath, routePath) {
|
|
52
53
|
try {
|
|
53
|
-
//
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
// Ensure we have an absolute path and normalize it
|
|
55
|
+
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
|
|
56
|
+
// Convert to proper file:// URL for Windows
|
|
57
|
+
const fileUrl = pathToFileURL(absolutePath).href;
|
|
58
|
+
if (process.platform === 'win32') {
|
|
59
|
+
// Add timestamp to force reload on Windows
|
|
60
|
+
const urlWithTimestamp = `${fileUrl}?t=${Date.now()}`;
|
|
61
|
+
// Dynamic import the route file
|
|
62
|
+
const routeModule = await import(urlWithTimestamp);
|
|
63
|
+
if (!this.isValidRouteModule(routeModule)) {
|
|
64
|
+
console.warn(`Invalid route module: ${filePath}`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(`Registering API route: ${routePath}`);
|
|
68
|
+
// Register middleware if any
|
|
69
|
+
const middleware = routeModule.middleware || [];
|
|
70
|
+
// Register HTTP methods
|
|
71
|
+
for (const method of ['get', 'post', 'put', 'delete', 'patch', 'options']) {
|
|
72
|
+
const handler = routeModule[method];
|
|
73
|
+
if (typeof handler === 'function') {
|
|
74
|
+
const routerMethod = this.router[method];
|
|
75
|
+
routerMethod.call(this.router, routePath, ...middleware, this.wrapHandler(handler));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
58
78
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
else {
|
|
80
|
+
// Non-Windows platforms
|
|
81
|
+
const routeModule = await import(fileUrl);
|
|
82
|
+
if (!this.isValidRouteModule(routeModule)) {
|
|
83
|
+
console.warn(`Invalid route module: ${filePath}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log(`Registering API route: ${routePath}`);
|
|
87
|
+
// Register middleware if any
|
|
88
|
+
const middleware = routeModule.middleware || [];
|
|
89
|
+
// Register HTTP methods
|
|
90
|
+
for (const method of ['get', 'post', 'put', 'delete', 'patch', 'options']) {
|
|
91
|
+
const handler = routeModule[method];
|
|
92
|
+
if (typeof handler === 'function') {
|
|
93
|
+
const routerMethod = this.router[method];
|
|
94
|
+
routerMethod.call(this.router, routePath, ...middleware, this.wrapHandler(handler));
|
|
95
|
+
}
|
|
68
96
|
}
|
|
69
97
|
}
|
|
70
98
|
}
|