@coherent.js/cli 1.0.0-beta.3 → 1.0.0-beta.6
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 +4 -12
- package/dist/index.js +1336 -502
- package/package.json +3 -2
- package/dist/index.cjs +0 -2456
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.js
|
|
2
2
|
import { Command as Command6 } from "commander";
|
|
3
|
-
import { readFileSync as
|
|
3
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
4
4
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5
5
|
import { dirname as dirname3, join as join8 } from "path";
|
|
6
6
|
import picocolors6 from "picocolors";
|
|
@@ -12,9 +12,10 @@ import ora from "ora";
|
|
|
12
12
|
import picocolors from "picocolors";
|
|
13
13
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
14
14
|
import { resolve as resolve2 } from "path";
|
|
15
|
+
import { spawn } from "child_process";
|
|
15
16
|
|
|
16
17
|
// src/generators/project-scaffold.js
|
|
17
|
-
import { writeFileSync, mkdirSync } from "node:fs";
|
|
18
|
+
import { writeFileSync, mkdirSync, copyFileSync, constants, readFileSync as readFileSync2, appendFileSync } from "node:fs";
|
|
18
19
|
import { join as join2, dirname as dirname2 } from "node:path";
|
|
19
20
|
import { execSync } from "node:child_process";
|
|
20
21
|
|
|
@@ -22,6 +23,7 @@ import { execSync } from "node:child_process";
|
|
|
22
23
|
import { readFileSync } from "fs";
|
|
23
24
|
import { join, dirname } from "path";
|
|
24
25
|
import { fileURLToPath } from "url";
|
|
26
|
+
import { env } from "node:process";
|
|
25
27
|
var cachedVersion = null;
|
|
26
28
|
function getCLIVersion() {
|
|
27
29
|
if (cachedVersion) {
|
|
@@ -35,7 +37,7 @@ function getCLIVersion() {
|
|
|
35
37
|
cachedVersion = packageJson.version;
|
|
36
38
|
return cachedVersion;
|
|
37
39
|
} catch {
|
|
38
|
-
cachedVersion =
|
|
40
|
+
cachedVersion = env.COHERENT_CLI_VERSION || "1.0.0-beta.5";
|
|
39
41
|
return cachedVersion;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -43,13 +45,16 @@ function getCLIVersion() {
|
|
|
43
45
|
// src/generators/runtime-scaffold.js
|
|
44
46
|
var cliVersion = getCLIVersion();
|
|
45
47
|
function generateBuiltInServer(options = {}) {
|
|
46
|
-
const { port = 3e3, hasApi = false, hasDatabase = false } = options;
|
|
48
|
+
const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
|
|
47
49
|
const imports = [
|
|
48
|
-
`import http from 'http';`,
|
|
50
|
+
`import http from 'node:http';`,
|
|
51
|
+
`import fs from 'node:fs';`,
|
|
52
|
+
`import path from 'node:path';`,
|
|
49
53
|
`import { render } from '@coherent.js/core';`
|
|
50
54
|
];
|
|
51
55
|
if (hasApi) imports.push(`import { setupRoutes } from './api/routes.js';`);
|
|
52
56
|
if (hasDatabase) imports.push(`import { initDatabase } from './db/index.js';`);
|
|
57
|
+
if (hasAuth) imports.push(`import { setupAuthRoutes } from './api/auth.js';`);
|
|
53
58
|
const server = `
|
|
54
59
|
${imports.join("\n")}
|
|
55
60
|
import { HomePage } from './components/HomePage.js';
|
|
@@ -60,23 +65,60 @@ ${hasDatabase ? `// Initialize database
|
|
|
60
65
|
await initDatabase();
|
|
61
66
|
` : ""}${hasApi ? `// Setup API routes
|
|
62
67
|
const apiRoutes = setupRoutes();
|
|
68
|
+
` : ""}${hasAuth ? `// Setup auth routes
|
|
69
|
+
const authRoutes = setupAuthRoutes();
|
|
63
70
|
` : ""}
|
|
64
71
|
const server = http.createServer(async (req, res) => {
|
|
65
72
|
const url = new URL(req.url, \`http://\${req.headers.host}\`);
|
|
66
73
|
|
|
67
|
-
${hasApi ? ` // Handle API routes
|
|
74
|
+
${hasApi || hasAuth ? ` // Handle API routes
|
|
68
75
|
if (url.pathname.startsWith('/api')) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
const allRoutes = [...${hasApi ? "apiRoutes" : "[]"}, ...${hasAuth ? "authRoutes" : "[]"}];
|
|
77
|
+
for (const route of allRoutes) {
|
|
78
|
+
const match = matchRoute(route.path, url.pathname, req.method, route.method);
|
|
79
|
+
if (match) {
|
|
80
|
+
req.params = match.params;
|
|
81
|
+
return route.handler(req, res);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
` : ""} // Serve components for hydration
|
|
87
|
+
if (url.pathname.startsWith('/components/')) {
|
|
88
|
+
const filePath = path.join(process.cwd(), 'src', url.pathname);
|
|
89
|
+
try {
|
|
90
|
+
const content = await fs.promises.readFile(filePath);
|
|
91
|
+
res.writeHead(200, { 'Content-Type': 'text/javascript' });
|
|
92
|
+
return res.end(content);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
res.writeHead(404);
|
|
95
|
+
return res.end('Not Found');
|
|
72
96
|
}
|
|
73
97
|
}
|
|
74
98
|
|
|
75
|
-
|
|
99
|
+
// Serve static files
|
|
76
100
|
if (url.pathname.startsWith('/public')) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
101
|
+
const filePath = path.join(process.cwd(), url.pathname);
|
|
102
|
+
try {
|
|
103
|
+
const content = await fs.promises.readFile(filePath);
|
|
104
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
105
|
+
const contentTypes = {
|
|
106
|
+
'.html': 'text/html',
|
|
107
|
+
'.js': 'text/javascript',
|
|
108
|
+
'.css': 'text/css',
|
|
109
|
+
'.json': 'application/json',
|
|
110
|
+
'.png': 'image/png',
|
|
111
|
+
'.jpg': 'image/jpeg',
|
|
112
|
+
'.gif': 'image/gif',
|
|
113
|
+
'.svg': 'image/svg+xml',
|
|
114
|
+
'.ico': 'image/x-icon'
|
|
115
|
+
};
|
|
116
|
+
res.writeHead(200, { 'Content-Type': contentTypes[ext] || 'application/octet-stream' });
|
|
117
|
+
return res.end(content);
|
|
118
|
+
} catch (err) {
|
|
119
|
+
res.writeHead(404);
|
|
120
|
+
return res.end('Not Found');
|
|
121
|
+
}
|
|
80
122
|
}
|
|
81
123
|
|
|
82
124
|
// Render page
|
|
@@ -101,6 +143,42 @@ ${hasApi ? ` // Handle API routes
|
|
|
101
143
|
}
|
|
102
144
|
});
|
|
103
145
|
|
|
146
|
+
// Route matching helper
|
|
147
|
+
function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
|
|
148
|
+
// Check HTTP method
|
|
149
|
+
if (requestMethod !== routeMethod) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Split paths into segments
|
|
154
|
+
const routeSegments = routePattern.split('/').filter(Boolean);
|
|
155
|
+
const urlSegments = urlPath.split('/').filter(Boolean);
|
|
156
|
+
|
|
157
|
+
// Check if lengths match
|
|
158
|
+
if (routeSegments.length !== urlSegments.length) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const params = {};
|
|
163
|
+
|
|
164
|
+
// Match each segment
|
|
165
|
+
for (let i = 0; i < routeSegments.length; i++) {
|
|
166
|
+
const routeSegment = routeSegments[i];
|
|
167
|
+
const urlSegment = urlSegments[i];
|
|
168
|
+
|
|
169
|
+
// Check for parameter (e.g., :id)
|
|
170
|
+
if (routeSegment.startsWith(':')) {
|
|
171
|
+
const paramName = routeSegment.substring(1);
|
|
172
|
+
params[paramName] = urlSegment;
|
|
173
|
+
} else if (routeSegment !== urlSegment) {
|
|
174
|
+
// Literal segment doesn't match
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return { params };
|
|
180
|
+
}
|
|
181
|
+
|
|
104
182
|
server.listen(PORT, () => {
|
|
105
183
|
console.log(\`Server running at http://localhost:\${PORT}\`);
|
|
106
184
|
});
|
|
@@ -111,7 +189,7 @@ function generateExpressServer(options = {}) {
|
|
|
111
189
|
const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
|
|
112
190
|
const imports = [
|
|
113
191
|
`import express from 'express';`,
|
|
114
|
-
`import {
|
|
192
|
+
`import { render } from '@coherent.js/core';`
|
|
115
193
|
];
|
|
116
194
|
if (hasApi) imports.push(`import apiRoutes from './api/routes.js';`);
|
|
117
195
|
if (hasDatabase) imports.push(`import { initDatabase } from './db/index.js';`);
|
|
@@ -132,15 +210,25 @@ ${hasDatabase ? `// Initialize database
|
|
|
132
210
|
await initDatabase();
|
|
133
211
|
` : ""}${hasAuth ? `// Setup authentication
|
|
134
212
|
app.use(authMiddleware);
|
|
135
|
-
` : ""}// Setup Coherent.js
|
|
136
|
-
setupCoherent(app);
|
|
137
|
-
|
|
138
|
-
${hasApi ? `// API routes
|
|
139
|
-
app.use('/api', apiRoutes);
|
|
140
213
|
` : ""}
|
|
141
|
-
|
|
214
|
+
${hasApi ? `// API routes - convert Coherent.js router to Express middleware
|
|
215
|
+
app.use('/api', apiRoutes.toExpressRouter(express));
|
|
216
|
+
` : ""}
|
|
217
|
+
// Main route - render Coherent.js component to HTML
|
|
142
218
|
app.get('/', (req, res) => {
|
|
143
|
-
|
|
219
|
+
const content = render(HomePage({}));
|
|
220
|
+
const html = \`<!DOCTYPE html>
|
|
221
|
+
<html lang="en">
|
|
222
|
+
<head>
|
|
223
|
+
<meta charset="UTF-8">
|
|
224
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
225
|
+
<title>Coherent.js App</title>
|
|
226
|
+
</head>
|
|
227
|
+
<body>
|
|
228
|
+
\${content}
|
|
229
|
+
</body>
|
|
230
|
+
</html>\`;
|
|
231
|
+
res.type('html').send(html);
|
|
144
232
|
});
|
|
145
233
|
|
|
146
234
|
// Error handling
|
|
@@ -189,9 +277,9 @@ await fastify.register(import('@fastify/static'), {
|
|
|
189
277
|
${hasApi ? `// API routes
|
|
190
278
|
await fastify.register(apiRoutes, { prefix: '/api' });
|
|
191
279
|
` : ""}
|
|
192
|
-
// Main route
|
|
280
|
+
// Main route - return Coherent.js component (auto-rendered by plugin)
|
|
193
281
|
fastify.get('/', async (request, reply) => {
|
|
194
|
-
return
|
|
282
|
+
return HomePage({});
|
|
195
283
|
});
|
|
196
284
|
|
|
197
285
|
// Start server
|
|
@@ -239,9 +327,9 @@ setupCoherent(app);
|
|
|
239
327
|
${hasApi ? `// API routes
|
|
240
328
|
apiRoutes(router);
|
|
241
329
|
` : ""}
|
|
242
|
-
// Main route
|
|
330
|
+
// Main route - set body to Coherent.js component (auto-rendered by middleware)
|
|
243
331
|
router.get('/', async (ctx) => {
|
|
244
|
-
ctx.
|
|
332
|
+
ctx.body = HomePage({});
|
|
245
333
|
});
|
|
246
334
|
|
|
247
335
|
app.use(router.routes());
|
|
@@ -307,9 +395,12 @@ export const dbConfig = {
|
|
|
307
395
|
user: process.env.DB_USER || 'postgres',
|
|
308
396
|
password: process.env.DB_PASSWORD || 'postgres',
|
|
309
397
|
// Connection pool settings
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
398
|
+
pool: {
|
|
399
|
+
min: 2,
|
|
400
|
+
max: 20,
|
|
401
|
+
idleTimeoutMillis: 30000,
|
|
402
|
+
connectionTimeoutMillis: 2000,
|
|
403
|
+
}
|
|
313
404
|
};
|
|
314
405
|
`,
|
|
315
406
|
mysql: `
|
|
@@ -320,9 +411,12 @@ export const dbConfig = {
|
|
|
320
411
|
user: process.env.DB_USER || 'root',
|
|
321
412
|
password: process.env.DB_PASSWORD || 'password',
|
|
322
413
|
// Connection pool settings
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
414
|
+
pool: {
|
|
415
|
+
max: 10,
|
|
416
|
+
min: 0,
|
|
417
|
+
waitForConnections: true,
|
|
418
|
+
queueLimit: 0
|
|
419
|
+
}
|
|
326
420
|
};
|
|
327
421
|
`,
|
|
328
422
|
sqlite: `
|
|
@@ -346,22 +440,33 @@ export const dbConfig = {
|
|
|
346
440
|
};
|
|
347
441
|
return configs[dbType] || "";
|
|
348
442
|
}
|
|
349
|
-
function generateDatabaseInit(dbType) {
|
|
443
|
+
function generateDatabaseInit(dbType, language = "javascript") {
|
|
444
|
+
const isTypeScript = language === "typescript";
|
|
445
|
+
const typeAnnotation = isTypeScript ? ": any" : "";
|
|
446
|
+
const returnType = isTypeScript ? ": Promise<any>" : "";
|
|
350
447
|
const inits = {
|
|
351
448
|
postgres: `
|
|
352
449
|
import { setupDatabase } from '@coherent.js/database';
|
|
353
450
|
import { dbConfig } from './config.js';
|
|
354
451
|
|
|
355
|
-
let db;
|
|
452
|
+
let db${typeAnnotation};
|
|
356
453
|
|
|
357
|
-
export async function initDatabase() {
|
|
454
|
+
export async function initDatabase()${returnType} {
|
|
358
455
|
try {
|
|
359
456
|
// Setup database with Coherent.js
|
|
360
457
|
db = setupDatabase({
|
|
361
|
-
type: '
|
|
362
|
-
|
|
458
|
+
type: 'postgresql',
|
|
459
|
+
host: dbConfig.host,
|
|
460
|
+
port: dbConfig.port,
|
|
461
|
+
database: dbConfig.database,
|
|
462
|
+
username: dbConfig.user,
|
|
463
|
+
password: dbConfig.password,
|
|
464
|
+
pool: dbConfig.pool
|
|
363
465
|
});
|
|
364
466
|
|
|
467
|
+
// Wait for connection
|
|
468
|
+
await db.connect();
|
|
469
|
+
|
|
365
470
|
console.log('\u2713 Connected to PostgreSQL database');
|
|
366
471
|
|
|
367
472
|
return db;
|
|
@@ -371,7 +476,7 @@ export async function initDatabase() {
|
|
|
371
476
|
}
|
|
372
477
|
}
|
|
373
478
|
|
|
374
|
-
export function getDatabase() {
|
|
479
|
+
export function getDatabase()${typeAnnotation} {
|
|
375
480
|
if (!db) {
|
|
376
481
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
377
482
|
}
|
|
@@ -391,16 +496,24 @@ process.on('SIGINT', async () => {
|
|
|
391
496
|
import { setupDatabase } from '@coherent.js/database';
|
|
392
497
|
import { dbConfig } from './config.js';
|
|
393
498
|
|
|
394
|
-
let db;
|
|
499
|
+
let db${typeAnnotation};
|
|
395
500
|
|
|
396
|
-
export async function initDatabase() {
|
|
501
|
+
export async function initDatabase()${returnType} {
|
|
397
502
|
try {
|
|
398
503
|
// Setup database with Coherent.js
|
|
399
504
|
db = setupDatabase({
|
|
400
505
|
type: 'mysql',
|
|
401
|
-
|
|
506
|
+
host: dbConfig.host,
|
|
507
|
+
port: dbConfig.port,
|
|
508
|
+
database: dbConfig.database,
|
|
509
|
+
username: dbConfig.user,
|
|
510
|
+
password: dbConfig.password,
|
|
511
|
+
pool: dbConfig.pool
|
|
402
512
|
});
|
|
403
513
|
|
|
514
|
+
// Wait for connection
|
|
515
|
+
await db.connect();
|
|
516
|
+
|
|
404
517
|
console.log('\u2713 Connected to MySQL database');
|
|
405
518
|
|
|
406
519
|
return db;
|
|
@@ -410,7 +523,7 @@ export async function initDatabase() {
|
|
|
410
523
|
}
|
|
411
524
|
}
|
|
412
525
|
|
|
413
|
-
export function getDatabase() {
|
|
526
|
+
export function getDatabase()${typeAnnotation} {
|
|
414
527
|
if (!db) {
|
|
415
528
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
416
529
|
}
|
|
@@ -432,21 +545,24 @@ import { dbConfig } from './config.js';
|
|
|
432
545
|
import { mkdirSync } from 'fs';
|
|
433
546
|
import { dirname } from 'path';
|
|
434
547
|
|
|
435
|
-
let db;
|
|
548
|
+
let db${typeAnnotation};
|
|
436
549
|
|
|
437
|
-
export async function initDatabase() {
|
|
550
|
+
export async function initDatabase()${returnType} {
|
|
438
551
|
try {
|
|
439
|
-
// Ensure directory exists
|
|
440
|
-
if (dbConfig.filename) {
|
|
552
|
+
// Ensure directory exists for SQLite file
|
|
553
|
+
if (dbConfig.filename && dbConfig.filename !== ':memory:') {
|
|
441
554
|
mkdirSync(dirname(dbConfig.filename), { recursive: true });
|
|
442
555
|
}
|
|
443
556
|
|
|
444
557
|
// Setup database with Coherent.js
|
|
445
558
|
db = setupDatabase({
|
|
446
559
|
type: 'sqlite',
|
|
447
|
-
|
|
560
|
+
database: dbConfig.filename || ':memory:'
|
|
448
561
|
});
|
|
449
562
|
|
|
563
|
+
// Wait for connection
|
|
564
|
+
await db.connect();
|
|
565
|
+
|
|
450
566
|
console.log('\u2713 Connected to SQLite database');
|
|
451
567
|
|
|
452
568
|
return db;
|
|
@@ -456,7 +572,7 @@ export async function initDatabase() {
|
|
|
456
572
|
}
|
|
457
573
|
}
|
|
458
574
|
|
|
459
|
-
export function getDatabase() {
|
|
575
|
+
export function getDatabase()${typeAnnotation} {
|
|
460
576
|
if (!db) {
|
|
461
577
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
462
578
|
}
|
|
@@ -464,9 +580,9 @@ export function getDatabase() {
|
|
|
464
580
|
}
|
|
465
581
|
|
|
466
582
|
// Graceful shutdown
|
|
467
|
-
process.on('SIGINT', () => {
|
|
583
|
+
process.on('SIGINT', async () => {
|
|
468
584
|
if (db) {
|
|
469
|
-
db.
|
|
585
|
+
await db.disconnect();
|
|
470
586
|
console.log('Database closed');
|
|
471
587
|
}
|
|
472
588
|
process.exit(0);
|
|
@@ -476,16 +592,20 @@ process.on('SIGINT', () => {
|
|
|
476
592
|
import { setupDatabase } from '@coherent.js/database';
|
|
477
593
|
import { dbConfig } from './config.js';
|
|
478
594
|
|
|
479
|
-
let db;
|
|
595
|
+
let db${typeAnnotation};
|
|
480
596
|
|
|
481
|
-
export async function initDatabase() {
|
|
597
|
+
export async function initDatabase()${returnType} {
|
|
482
598
|
try {
|
|
483
599
|
// Setup database with Coherent.js
|
|
484
600
|
db = setupDatabase({
|
|
485
601
|
type: 'mongodb',
|
|
486
|
-
|
|
602
|
+
database: dbConfig.uri,
|
|
603
|
+
...dbConfig.options
|
|
487
604
|
});
|
|
488
605
|
|
|
606
|
+
// Wait for connection
|
|
607
|
+
await db.connect();
|
|
608
|
+
|
|
489
609
|
console.log('\u2713 Connected to MongoDB database');
|
|
490
610
|
|
|
491
611
|
return db;
|
|
@@ -495,7 +615,7 @@ export async function initDatabase() {
|
|
|
495
615
|
}
|
|
496
616
|
}
|
|
497
617
|
|
|
498
|
-
export function getDatabase() {
|
|
618
|
+
export function getDatabase()${typeAnnotation} {
|
|
499
619
|
if (!db) {
|
|
500
620
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
501
621
|
}
|
|
@@ -514,47 +634,57 @@ process.on('SIGINT', async () => {
|
|
|
514
634
|
};
|
|
515
635
|
return inits[dbType] || "";
|
|
516
636
|
}
|
|
517
|
-
function generateExampleModel(dbType) {
|
|
637
|
+
function generateExampleModel(dbType, language = "javascript") {
|
|
638
|
+
const isTypeScript = language === "typescript";
|
|
639
|
+
const typeAnnotation = isTypeScript ? ": Promise<any>" : "";
|
|
640
|
+
const interfaceDef = isTypeScript ? `
|
|
641
|
+
interface UserData {
|
|
642
|
+
email: string;
|
|
643
|
+
name: string;
|
|
644
|
+
}` : "";
|
|
518
645
|
const models = {
|
|
519
646
|
postgres: `
|
|
520
|
-
import { getDatabase } from '
|
|
647
|
+
import { getDatabase } from '../index.js';
|
|
648
|
+
|
|
649
|
+
${interfaceDef}
|
|
521
650
|
|
|
522
651
|
export class UserModel {
|
|
523
|
-
static async createTable() {
|
|
652
|
+
static async createTable()${typeAnnotation} {
|
|
524
653
|
const db = getDatabase();
|
|
525
654
|
await db.query(\`
|
|
526
655
|
CREATE TABLE IF NOT EXISTS users (
|
|
527
656
|
id SERIAL PRIMARY KEY,
|
|
528
657
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
529
658
|
name VARCHAR(255) NOT NULL,
|
|
659
|
+
password_hash VARCHAR(255),
|
|
530
660
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
531
661
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
532
662
|
)
|
|
533
663
|
\`);
|
|
534
664
|
}
|
|
535
665
|
|
|
536
|
-
static async create(
|
|
666
|
+
static async create(userData)${typeAnnotation} {
|
|
537
667
|
const db = getDatabase();
|
|
538
668
|
const result = await db.query(
|
|
539
669
|
'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
|
|
540
|
-
[
|
|
670
|
+
[userData.email, userData.name]
|
|
541
671
|
);
|
|
542
672
|
return result.rows[0];
|
|
543
673
|
}
|
|
544
674
|
|
|
545
|
-
static async findById(id) {
|
|
675
|
+
static async findById(id)${typeAnnotation} {
|
|
546
676
|
const db = getDatabase();
|
|
547
677
|
const result = await db.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
548
678
|
return result.rows[0];
|
|
549
679
|
}
|
|
550
680
|
|
|
551
|
-
static async findByEmail(email) {
|
|
681
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
552
682
|
const db = getDatabase();
|
|
553
683
|
const result = await db.query('SELECT * FROM users WHERE email = $1', [email]);
|
|
554
684
|
return result.rows[0];
|
|
555
685
|
}
|
|
556
686
|
|
|
557
|
-
static async update(id, data) {
|
|
687
|
+
static async update(id, data)${typeAnnotation} {
|
|
558
688
|
const db = getDatabase();
|
|
559
689
|
const result = await db.query(
|
|
560
690
|
'UPDATE users SET email = $1, name = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3 RETURNING *',
|
|
@@ -563,70 +693,75 @@ export class UserModel {
|
|
|
563
693
|
return result.rows[0];
|
|
564
694
|
}
|
|
565
695
|
|
|
566
|
-
static async delete(id) {
|
|
696
|
+
static async delete(id)${typeAnnotation} {
|
|
567
697
|
const db = getDatabase();
|
|
568
698
|
await db.query('DELETE FROM users WHERE id = $1', [id]);
|
|
569
699
|
}
|
|
570
700
|
}
|
|
571
701
|
`,
|
|
572
702
|
mysql: `
|
|
573
|
-
import { getDatabase } from '
|
|
703
|
+
import { getDatabase } from '../index.js';
|
|
704
|
+
|
|
705
|
+
${interfaceDef}
|
|
574
706
|
|
|
575
707
|
export class UserModel {
|
|
576
|
-
static async createTable() {
|
|
708
|
+
static async createTable()${typeAnnotation} {
|
|
577
709
|
const db = getDatabase();
|
|
578
|
-
await db.
|
|
710
|
+
await db.query(\`
|
|
579
711
|
CREATE TABLE IF NOT EXISTS users (
|
|
580
712
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
581
713
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
582
714
|
name VARCHAR(255) NOT NULL,
|
|
715
|
+
password_hash VARCHAR(255),
|
|
583
716
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
584
717
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
585
718
|
)
|
|
586
719
|
\`);
|
|
587
720
|
}
|
|
588
721
|
|
|
589
|
-
static async create(
|
|
722
|
+
static async create(userData)${typeAnnotation} {
|
|
590
723
|
const db = getDatabase();
|
|
591
|
-
const
|
|
724
|
+
const result = await db.query(
|
|
592
725
|
'INSERT INTO users (email, name) VALUES (?, ?)',
|
|
593
|
-
[
|
|
726
|
+
[userData.email, userData.name]
|
|
594
727
|
);
|
|
595
|
-
return
|
|
728
|
+
return result[0];
|
|
596
729
|
}
|
|
597
730
|
|
|
598
|
-
static async findById(id) {
|
|
731
|
+
static async findById(id)${typeAnnotation} {
|
|
599
732
|
const db = getDatabase();
|
|
600
|
-
const
|
|
601
|
-
return
|
|
733
|
+
const result = await db.query('SELECT * FROM users WHERE id = ?', [id]);
|
|
734
|
+
return result[0];
|
|
602
735
|
}
|
|
603
736
|
|
|
604
|
-
static async findByEmail(email) {
|
|
737
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
605
738
|
const db = getDatabase();
|
|
606
|
-
const
|
|
607
|
-
return
|
|
739
|
+
const result = await db.query('SELECT * FROM users WHERE email = ?', [email]);
|
|
740
|
+
return result[0];
|
|
608
741
|
}
|
|
609
742
|
|
|
610
|
-
static async update(id, data) {
|
|
743
|
+
static async update(id, data)${typeAnnotation} {
|
|
611
744
|
const db = getDatabase();
|
|
612
|
-
await db.
|
|
613
|
-
'UPDATE users SET email = ?, name =
|
|
745
|
+
const result = await db.query(
|
|
746
|
+
'UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
|
|
614
747
|
[data.email, data.name, id]
|
|
615
748
|
);
|
|
616
|
-
return
|
|
749
|
+
return result[0];
|
|
617
750
|
}
|
|
618
751
|
|
|
619
|
-
static async delete(id) {
|
|
752
|
+
static async delete(id)${typeAnnotation} {
|
|
620
753
|
const db = getDatabase();
|
|
621
|
-
await db.
|
|
754
|
+
await db.query('DELETE FROM users WHERE id = ?', [id]);
|
|
622
755
|
}
|
|
623
756
|
}
|
|
624
757
|
`,
|
|
625
758
|
sqlite: `
|
|
626
|
-
import { getDatabase } from '
|
|
759
|
+
import { getDatabase } from '../index.js';
|
|
760
|
+
|
|
761
|
+
${interfaceDef}
|
|
627
762
|
|
|
628
763
|
export class UserModel {
|
|
629
|
-
static createTable() {
|
|
764
|
+
static createTable()${typeAnnotation} {
|
|
630
765
|
const db = getDatabase();
|
|
631
766
|
db.exec(\`
|
|
632
767
|
CREATE TABLE IF NOT EXISTS users (
|
|
@@ -639,94 +774,82 @@ export class UserModel {
|
|
|
639
774
|
\`);
|
|
640
775
|
}
|
|
641
776
|
|
|
642
|
-
static create(data) {
|
|
777
|
+
static create(data)${typeAnnotation} {
|
|
643
778
|
const db = getDatabase();
|
|
644
779
|
const stmt = db.prepare('INSERT INTO users (email, name) VALUES (?, ?)');
|
|
645
780
|
const result = stmt.run(data.email, data.name);
|
|
646
781
|
return { id: result.lastInsertRowid, ...data };
|
|
647
782
|
}
|
|
648
783
|
|
|
649
|
-
static findById(id) {
|
|
784
|
+
static findById(id)${typeAnnotation} {
|
|
650
785
|
const db = getDatabase();
|
|
651
786
|
const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
|
|
652
787
|
return stmt.get(id);
|
|
653
788
|
}
|
|
654
789
|
|
|
655
|
-
static findByEmail(email) {
|
|
790
|
+
static findByEmail(email)${typeAnnotation} {
|
|
656
791
|
const db = getDatabase();
|
|
657
792
|
const stmt = db.prepare('SELECT * FROM users WHERE email = ?');
|
|
658
793
|
return stmt.get(email);
|
|
659
794
|
}
|
|
660
795
|
|
|
661
|
-
static update(id, data) {
|
|
796
|
+
static update(id, data)${typeAnnotation} {
|
|
662
797
|
const db = getDatabase();
|
|
663
798
|
const stmt = db.prepare('UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
|
|
664
799
|
stmt.run(data.email, data.name, id);
|
|
665
|
-
return
|
|
800
|
+
return this.findById(id);
|
|
666
801
|
}
|
|
667
802
|
|
|
668
|
-
static delete(id) {
|
|
803
|
+
static delete(id)${typeAnnotation} {
|
|
669
804
|
const db = getDatabase();
|
|
670
805
|
const stmt = db.prepare('DELETE FROM users WHERE id = ?');
|
|
671
|
-
stmt.run(id);
|
|
806
|
+
return stmt.run(id);
|
|
672
807
|
}
|
|
673
808
|
}
|
|
674
809
|
`,
|
|
675
810
|
mongodb: `
|
|
676
|
-
import { getDatabase } from '
|
|
811
|
+
import { getDatabase } from '../index.js';
|
|
677
812
|
|
|
678
|
-
|
|
679
|
-
static collectionName = 'users';
|
|
813
|
+
${interfaceDef}
|
|
680
814
|
|
|
681
|
-
|
|
815
|
+
export class UserModel {
|
|
816
|
+
static async createCollection()${typeAnnotation} {
|
|
682
817
|
const db = getDatabase();
|
|
683
|
-
|
|
818
|
+
await db.createCollection('users');
|
|
819
|
+
|
|
820
|
+
// Create index for email uniqueness
|
|
821
|
+
await db.collection('users').createIndex({ email: 1 }, { unique: true });
|
|
684
822
|
}
|
|
685
823
|
|
|
686
|
-
static async create(
|
|
687
|
-
const
|
|
688
|
-
const result = await collection.insertOne(
|
|
689
|
-
|
|
690
|
-
name: data.name,
|
|
691
|
-
createdAt: new Date(),
|
|
692
|
-
updatedAt: new Date()
|
|
693
|
-
});
|
|
694
|
-
return { _id: result.insertedId, ...data };
|
|
824
|
+
static async create(userData)${typeAnnotation} {
|
|
825
|
+
const db = getDatabase();
|
|
826
|
+
const result = await db.collection('users').insertOne(userData);
|
|
827
|
+
return { _id: result.insertedId, ...userData };
|
|
695
828
|
}
|
|
696
829
|
|
|
697
|
-
static async findById(id) {
|
|
698
|
-
const
|
|
699
|
-
return await collection.findOne({ _id: id });
|
|
830
|
+
static async findById(id)${typeAnnotation} {
|
|
831
|
+
const db = getDatabase();
|
|
832
|
+
return await db.collection('users').findOne({ _id: id });
|
|
700
833
|
}
|
|
701
834
|
|
|
702
|
-
static async findByEmail(email) {
|
|
703
|
-
const
|
|
704
|
-
return await collection.findOne({ email });
|
|
835
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
836
|
+
const db = getDatabase();
|
|
837
|
+
return await db.collection('users').findOne({ email });
|
|
705
838
|
}
|
|
706
839
|
|
|
707
|
-
static async update(id, data) {
|
|
708
|
-
const
|
|
709
|
-
await collection.updateOne(
|
|
840
|
+
static async update(id, data)${typeAnnotation} {
|
|
841
|
+
const db = getDatabase();
|
|
842
|
+
const result = await db.collection('users').updateOne(
|
|
710
843
|
{ _id: id },
|
|
711
|
-
{
|
|
712
|
-
$set: {
|
|
713
|
-
email: data.email,
|
|
714
|
-
name: data.name,
|
|
715
|
-
updatedAt: new Date()
|
|
716
|
-
}
|
|
717
|
-
}
|
|
844
|
+
{ $set: { ...data, updatedAt: new Date() } }
|
|
718
845
|
);
|
|
719
|
-
return
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
static async delete(id) {
|
|
723
|
-
const collection = this.getCollection();
|
|
724
|
-
await collection.deleteOne({ _id: id });
|
|
846
|
+
return result.modifiedCount > 0 ? this.findById(id) : null;
|
|
725
847
|
}
|
|
726
848
|
|
|
727
|
-
static async
|
|
728
|
-
const
|
|
729
|
-
await collection.
|
|
849
|
+
static async delete(id)${typeAnnotation} {
|
|
850
|
+
const db = getDatabase();
|
|
851
|
+
const result = await db.collection('users').deleteOne({ _id: id });
|
|
852
|
+
return result.deletedCount > 0;
|
|
730
853
|
}
|
|
731
854
|
}
|
|
732
855
|
`
|
|
@@ -779,11 +902,11 @@ function getDatabaseDependencies(dbType) {
|
|
|
779
902
|
};
|
|
780
903
|
return deps[dbType] || {};
|
|
781
904
|
}
|
|
782
|
-
function generateDatabaseScaffolding(dbType) {
|
|
905
|
+
function generateDatabaseScaffolding(dbType, language = "javascript") {
|
|
783
906
|
return {
|
|
784
907
|
config: generateDatabaseConfig(dbType),
|
|
785
|
-
init: generateDatabaseInit(dbType),
|
|
786
|
-
model: generateExampleModel(dbType),
|
|
908
|
+
init: generateDatabaseInit(dbType, language),
|
|
909
|
+
model: generateExampleModel(dbType, language),
|
|
787
910
|
env: generateEnvExample(dbType),
|
|
788
911
|
dependencies: getDatabaseDependencies(dbType)
|
|
789
912
|
};
|
|
@@ -1079,7 +1202,7 @@ function generateAuthRoutes(runtime, authType) {
|
|
|
1079
1202
|
const jwtRoutes = {
|
|
1080
1203
|
express: `
|
|
1081
1204
|
import express from 'express';
|
|
1082
|
-
import { generateToken } from '../middleware/auth.js';
|
|
1205
|
+
import { generateToken, authMiddleware } from '../middleware/auth.js';
|
|
1083
1206
|
import { UserModel } from '../db/models/User.js';
|
|
1084
1207
|
|
|
1085
1208
|
const router = express.Router();
|
|
@@ -1156,6 +1279,158 @@ router.get('/me', authMiddleware, async (req, res) => {
|
|
|
1156
1279
|
});
|
|
1157
1280
|
|
|
1158
1281
|
export default router;
|
|
1282
|
+
`,
|
|
1283
|
+
"built-in": `
|
|
1284
|
+
// Auth routes for built-in HTTP server
|
|
1285
|
+
import { generateToken, verifyToken } from '../middleware/auth.js';
|
|
1286
|
+
import { UserModel } from '../db/models/User.js';
|
|
1287
|
+
|
|
1288
|
+
// Register handler
|
|
1289
|
+
export async function registerHandler(req, res) {
|
|
1290
|
+
try {
|
|
1291
|
+
// Parse JSON body
|
|
1292
|
+
let body = '';
|
|
1293
|
+
req.on('data', chunk => {
|
|
1294
|
+
body += chunk.toString();
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
req.on('end', async () => {
|
|
1298
|
+
try {
|
|
1299
|
+
const { email, name, password } = JSON.parse(body);
|
|
1300
|
+
|
|
1301
|
+
// Validate input
|
|
1302
|
+
if (!email || !name || !password) {
|
|
1303
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1304
|
+
return res.end(JSON.stringify({ error: 'Missing required fields' }));
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// Check if user exists
|
|
1308
|
+
const existingUser = await UserModel.findByEmail(email);
|
|
1309
|
+
if (existingUser) {
|
|
1310
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1311
|
+
return res.end(JSON.stringify({ error: 'User already exists' }));
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// Create user (you should hash the password!)
|
|
1315
|
+
const user = await UserModel.create({ email, name });
|
|
1316
|
+
|
|
1317
|
+
// Generate token
|
|
1318
|
+
const token = generateToken({ id: user.id, email: user.email });
|
|
1319
|
+
|
|
1320
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1321
|
+
res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name }, token }));
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
console.error('Register error:', error);
|
|
1324
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1325
|
+
res.end(JSON.stringify({ error: 'Registration failed' }));
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
} catch (error) {
|
|
1329
|
+
console.error('Register error:', error);
|
|
1330
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1331
|
+
res.end(JSON.stringify({ error: 'Registration failed' }));
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Login handler
|
|
1336
|
+
export async function loginHandler(req, res) {
|
|
1337
|
+
try {
|
|
1338
|
+
// Parse JSON body
|
|
1339
|
+
let body = '';
|
|
1340
|
+
req.on('data', chunk => {
|
|
1341
|
+
body += chunk.toString();
|
|
1342
|
+
});
|
|
1343
|
+
|
|
1344
|
+
req.on('end', async () => {
|
|
1345
|
+
try {
|
|
1346
|
+
const { email, password } = JSON.parse(body);
|
|
1347
|
+
|
|
1348
|
+
// Validate input
|
|
1349
|
+
if (!email || !password) {
|
|
1350
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
1351
|
+
return res.end(JSON.stringify({ error: 'Missing required fields' }));
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
// Find user
|
|
1355
|
+
const user = await UserModel.findByEmail(email);
|
|
1356
|
+
if (!user) {
|
|
1357
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
1358
|
+
return res.end(JSON.stringify({ error: 'Invalid credentials' }));
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// Verify password (you should implement proper password checking!)
|
|
1362
|
+
|
|
1363
|
+
// Generate token
|
|
1364
|
+
const token = generateToken({ id: user.id, email: user.email });
|
|
1365
|
+
|
|
1366
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1367
|
+
res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name }, token }));
|
|
1368
|
+
} catch (error) {
|
|
1369
|
+
console.error('Login error:', error);
|
|
1370
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1371
|
+
res.end(JSON.stringify({ error: 'Login failed' }));
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
} catch (error) {
|
|
1375
|
+
console.error('Login error:', error);
|
|
1376
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1377
|
+
res.end(JSON.stringify({ error: 'Login failed' }));
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
// Get current user handler
|
|
1382
|
+
export async function meHandler(req, res) {
|
|
1383
|
+
try {
|
|
1384
|
+
// Verify token from Authorization header
|
|
1385
|
+
const authHeader = req.headers.authorization;
|
|
1386
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
1387
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
1388
|
+
return res.end(JSON.stringify({ error: 'No token provided' }));
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
const token = authHeader.substring(7);
|
|
1392
|
+
const decoded = verifyToken(token);
|
|
1393
|
+
|
|
1394
|
+
if (!decoded) {
|
|
1395
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
1396
|
+
return res.end(JSON.stringify({ error: 'Invalid or expired token' }));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
const user = await UserModel.findById(decoded.id);
|
|
1400
|
+
if (!user) {
|
|
1401
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1402
|
+
return res.end(JSON.stringify({ error: 'User not found' }));
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1406
|
+
res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name } }));
|
|
1407
|
+
} catch (error) {
|
|
1408
|
+
console.error('Get user error:', error);
|
|
1409
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1410
|
+
res.end(JSON.stringify({ error: 'Failed to get user' }));
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// For built-in HTTP server compatibility
|
|
1415
|
+
export function setupAuthRoutes() {
|
|
1416
|
+
return [
|
|
1417
|
+
{
|
|
1418
|
+
path: '/api/auth/register',
|
|
1419
|
+
method: 'POST',
|
|
1420
|
+
handler: registerHandler
|
|
1421
|
+
},
|
|
1422
|
+
{
|
|
1423
|
+
path: '/api/auth/login',
|
|
1424
|
+
method: 'POST',
|
|
1425
|
+
handler: loginHandler
|
|
1426
|
+
},
|
|
1427
|
+
{
|
|
1428
|
+
path: '/api/auth/me',
|
|
1429
|
+
method: 'GET',
|
|
1430
|
+
handler: meHandler
|
|
1431
|
+
}
|
|
1432
|
+
];
|
|
1433
|
+
}
|
|
1159
1434
|
`,
|
|
1160
1435
|
fastify: `
|
|
1161
1436
|
import { generateToken } from '../plugins/auth.js';
|
|
@@ -1327,11 +1602,7 @@ router.get('/me', authMiddleware, async (ctx) => {
|
|
|
1327
1602
|
}
|
|
1328
1603
|
});
|
|
1329
1604
|
|
|
1330
|
-
export default
|
|
1331
|
-
router.post('/auth/register', registerHandler);
|
|
1332
|
-
router.post('/auth/login', loginHandler);
|
|
1333
|
-
router.get('/auth/me', authMiddleware, meHandler);
|
|
1334
|
-
}
|
|
1605
|
+
export default router;
|
|
1335
1606
|
`
|
|
1336
1607
|
};
|
|
1337
1608
|
const sessionRoutes = {
|
|
@@ -1471,6 +1742,312 @@ function generateAuthScaffolding(authType, runtime) {
|
|
|
1471
1742
|
};
|
|
1472
1743
|
}
|
|
1473
1744
|
|
|
1745
|
+
// src/generators/docker-scaffold.js
|
|
1746
|
+
var _cliVersion = getCLIVersion();
|
|
1747
|
+
function generateDockerScaffolding(dbType, dockerConfig) {
|
|
1748
|
+
const { port, name, user, password } = dockerConfig;
|
|
1749
|
+
const dockerCompose = generateDockerCompose(dbType, port, name, user, password);
|
|
1750
|
+
const dockerfile = generateDockerfile();
|
|
1751
|
+
const dockerignore = generateDockerignore();
|
|
1752
|
+
const envConfig = generateDockerEnvConfig(dbType, port, name, user, password);
|
|
1753
|
+
return {
|
|
1754
|
+
"docker-compose.yml": dockerCompose,
|
|
1755
|
+
"Dockerfile": dockerfile,
|
|
1756
|
+
".dockerignore": dockerignore,
|
|
1757
|
+
envConfig
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
function generateDockerCompose(dbType, port, dbName, dbUser, dbPassword) {
|
|
1761
|
+
const configs = {
|
|
1762
|
+
postgres: `version: '3.8'
|
|
1763
|
+
|
|
1764
|
+
services:
|
|
1765
|
+
postgres:
|
|
1766
|
+
image: postgres:16-alpine
|
|
1767
|
+
container_name: coherent-postgres
|
|
1768
|
+
restart: unless-stopped
|
|
1769
|
+
environment:
|
|
1770
|
+
POSTGRES_DB: ${dbName}
|
|
1771
|
+
POSTGRES_USER: ${dbUser}
|
|
1772
|
+
POSTGRES_PASSWORD: ${dbPassword}
|
|
1773
|
+
ports:
|
|
1774
|
+
- "${port}:5432"
|
|
1775
|
+
volumes:
|
|
1776
|
+
- postgres_data:/var/lib/postgresql/data
|
|
1777
|
+
networks:
|
|
1778
|
+
- coherent-network
|
|
1779
|
+
|
|
1780
|
+
volumes:
|
|
1781
|
+
postgres_data:
|
|
1782
|
+
|
|
1783
|
+
networks:
|
|
1784
|
+
coherent-network:
|
|
1785
|
+
driver: bridge`,
|
|
1786
|
+
mysql: `version: '3.8'
|
|
1787
|
+
|
|
1788
|
+
services:
|
|
1789
|
+
mysql:
|
|
1790
|
+
image: mysql:8
|
|
1791
|
+
container_name: coherent-mysql
|
|
1792
|
+
restart: unless-stopped
|
|
1793
|
+
environment:
|
|
1794
|
+
MYSQL_DATABASE: ${dbName}
|
|
1795
|
+
MYSQL_USER: ${dbUser}
|
|
1796
|
+
MYSQL_PASSWORD: ${dbPassword}
|
|
1797
|
+
MYSQL_ROOT_PASSWORD: ${dbPassword}_root
|
|
1798
|
+
ports:
|
|
1799
|
+
- "${port}:3306"
|
|
1800
|
+
volumes:
|
|
1801
|
+
- mysql_data:/var/lib/mysql
|
|
1802
|
+
networks:
|
|
1803
|
+
- coherent-network
|
|
1804
|
+
|
|
1805
|
+
volumes:
|
|
1806
|
+
mysql_data:
|
|
1807
|
+
|
|
1808
|
+
networks:
|
|
1809
|
+
coherent-network:
|
|
1810
|
+
driver: bridge`,
|
|
1811
|
+
mongodb: `version: '3.8'
|
|
1812
|
+
|
|
1813
|
+
services:
|
|
1814
|
+
mongodb:
|
|
1815
|
+
image: mongo:7
|
|
1816
|
+
container_name: coherent-mongodb
|
|
1817
|
+
restart: unless-stopped
|
|
1818
|
+
environment:
|
|
1819
|
+
MONGO_INITDB_ROOT_USERNAME: ${dbUser}
|
|
1820
|
+
MONGO_INITDB_ROOT_PASSWORD: ${dbPassword}
|
|
1821
|
+
MONGO_INITDB_DATABASE: ${dbName}
|
|
1822
|
+
ports:
|
|
1823
|
+
- "${port}:27017"
|
|
1824
|
+
volumes:
|
|
1825
|
+
- mongodb_data:/data/db
|
|
1826
|
+
networks:
|
|
1827
|
+
- coherent-network
|
|
1828
|
+
|
|
1829
|
+
volumes:
|
|
1830
|
+
mongodb_data:
|
|
1831
|
+
|
|
1832
|
+
networks:
|
|
1833
|
+
coherent-network:
|
|
1834
|
+
driver: bridge`
|
|
1835
|
+
};
|
|
1836
|
+
return configs[dbType] || configs.postgres;
|
|
1837
|
+
}
|
|
1838
|
+
function generateDockerfile() {
|
|
1839
|
+
return `# Use Node.js 18 Alpine as base image
|
|
1840
|
+
FROM node:18-alpine
|
|
1841
|
+
|
|
1842
|
+
# Set working directory
|
|
1843
|
+
WORKDIR /app
|
|
1844
|
+
|
|
1845
|
+
# Copy package files
|
|
1846
|
+
COPY package*.json ./
|
|
1847
|
+
|
|
1848
|
+
# Install dependencies
|
|
1849
|
+
RUN npm ci --only=production
|
|
1850
|
+
|
|
1851
|
+
# Copy application code
|
|
1852
|
+
COPY . .
|
|
1853
|
+
|
|
1854
|
+
# Create non-root user
|
|
1855
|
+
RUN addgroup -g 1001 -S nodejs
|
|
1856
|
+
RUN adduser -S nodejs -u 1001
|
|
1857
|
+
|
|
1858
|
+
# Change ownership of the app directory
|
|
1859
|
+
RUN chown -R nodejs:nodejs /app
|
|
1860
|
+
USER nodejs
|
|
1861
|
+
|
|
1862
|
+
# Expose port
|
|
1863
|
+
EXPOSE 3000
|
|
1864
|
+
|
|
1865
|
+
# Health check
|
|
1866
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
|
|
1867
|
+
CMD node healthcheck.js || exit 1
|
|
1868
|
+
|
|
1869
|
+
# Start the application
|
|
1870
|
+
CMD ["npm", "start"]`;
|
|
1871
|
+
}
|
|
1872
|
+
function generateDockerignore() {
|
|
1873
|
+
return `# Dependencies
|
|
1874
|
+
node_modules
|
|
1875
|
+
npm-debug.log*
|
|
1876
|
+
yarn-debug.log*
|
|
1877
|
+
yarn-error.log*
|
|
1878
|
+
|
|
1879
|
+
# Runtime data
|
|
1880
|
+
pids
|
|
1881
|
+
*.pid
|
|
1882
|
+
*.seed
|
|
1883
|
+
*.pid.lock
|
|
1884
|
+
|
|
1885
|
+
# Coverage directory used by tools like istanbul
|
|
1886
|
+
coverage
|
|
1887
|
+
|
|
1888
|
+
# nyc test coverage
|
|
1889
|
+
.nyc_output
|
|
1890
|
+
|
|
1891
|
+
# Grunt intermediate storage
|
|
1892
|
+
.grunt
|
|
1893
|
+
|
|
1894
|
+
# Bower dependency directory
|
|
1895
|
+
bower_components
|
|
1896
|
+
|
|
1897
|
+
# node-waf configuration
|
|
1898
|
+
.lock-wscript
|
|
1899
|
+
|
|
1900
|
+
# Compiled binary addons
|
|
1901
|
+
build/Release
|
|
1902
|
+
|
|
1903
|
+
# Dependency directories
|
|
1904
|
+
jspm_packages/
|
|
1905
|
+
|
|
1906
|
+
# TypeScript cache
|
|
1907
|
+
*.tsbuildinfo
|
|
1908
|
+
|
|
1909
|
+
# Optional npm cache directory
|
|
1910
|
+
.npm
|
|
1911
|
+
|
|
1912
|
+
# Optional eslint cache
|
|
1913
|
+
.eslintcache
|
|
1914
|
+
|
|
1915
|
+
# Microbundle cache
|
|
1916
|
+
.rpt2_cache/
|
|
1917
|
+
.rts2_cache_cjs/
|
|
1918
|
+
.rts2_cache_es/
|
|
1919
|
+
.rts2_cache_umd/
|
|
1920
|
+
|
|
1921
|
+
# Optional REPL history
|
|
1922
|
+
.node_repl_history
|
|
1923
|
+
|
|
1924
|
+
# Output of 'npm pack'
|
|
1925
|
+
*.tgz
|
|
1926
|
+
|
|
1927
|
+
# Yarn Integrity file
|
|
1928
|
+
.yarn-integrity
|
|
1929
|
+
|
|
1930
|
+
# dotenv environment variables file
|
|
1931
|
+
.env
|
|
1932
|
+
.env.test
|
|
1933
|
+
.env.local
|
|
1934
|
+
.env.production
|
|
1935
|
+
|
|
1936
|
+
# parcel-bundler cache
|
|
1937
|
+
.cache
|
|
1938
|
+
.parcel-cache
|
|
1939
|
+
|
|
1940
|
+
# Next.js build output
|
|
1941
|
+
.next
|
|
1942
|
+
|
|
1943
|
+
# Nuxt.js build / generate output
|
|
1944
|
+
.nuxt
|
|
1945
|
+
dist
|
|
1946
|
+
|
|
1947
|
+
# Gatsby files
|
|
1948
|
+
.cache/
|
|
1949
|
+
public
|
|
1950
|
+
|
|
1951
|
+
# Storybook build outputs
|
|
1952
|
+
.out
|
|
1953
|
+
.storybook-out
|
|
1954
|
+
|
|
1955
|
+
# Temporary folders
|
|
1956
|
+
tmp/
|
|
1957
|
+
temp/
|
|
1958
|
+
|
|
1959
|
+
# Logs
|
|
1960
|
+
logs
|
|
1961
|
+
*.log
|
|
1962
|
+
|
|
1963
|
+
# Runtime data
|
|
1964
|
+
pids
|
|
1965
|
+
*.pid
|
|
1966
|
+
*.seed
|
|
1967
|
+
|
|
1968
|
+
# Coverage directory used by tools like istanbul
|
|
1969
|
+
coverage
|
|
1970
|
+
|
|
1971
|
+
# Grunt intermediate storage
|
|
1972
|
+
.grunt
|
|
1973
|
+
|
|
1974
|
+
# Compiled binary addons
|
|
1975
|
+
build/Release
|
|
1976
|
+
|
|
1977
|
+
# Users Environment Variables
|
|
1978
|
+
.lock-wscript
|
|
1979
|
+
|
|
1980
|
+
# IDE files
|
|
1981
|
+
.vscode/
|
|
1982
|
+
.idea/
|
|
1983
|
+
*.swp
|
|
1984
|
+
*.swo
|
|
1985
|
+
|
|
1986
|
+
# OS generated files
|
|
1987
|
+
.DS_Store
|
|
1988
|
+
.DS_Store?
|
|
1989
|
+
._*
|
|
1990
|
+
.Spotlight-V100
|
|
1991
|
+
.Trashes
|
|
1992
|
+
ehthumbs.db
|
|
1993
|
+
Thumbs.db`;
|
|
1994
|
+
}
|
|
1995
|
+
function generateDockerEnvConfig(dbType, port, dbName, dbUser, dbPassword) {
|
|
1996
|
+
const configs = {
|
|
1997
|
+
postgres: {
|
|
1998
|
+
DB_HOST: "postgres",
|
|
1999
|
+
DB_PORT: port,
|
|
2000
|
+
DB_NAME: dbName,
|
|
2001
|
+
DB_USER: dbUser,
|
|
2002
|
+
DB_PASSWORD: dbPassword,
|
|
2003
|
+
DATABASE_URL: `postgresql://${dbUser}:${dbPassword}@postgres:${port}/${dbName}`
|
|
2004
|
+
},
|
|
2005
|
+
mysql: {
|
|
2006
|
+
DB_HOST: "mysql",
|
|
2007
|
+
DB_PORT: port,
|
|
2008
|
+
DB_NAME: dbName,
|
|
2009
|
+
DB_USER: dbUser,
|
|
2010
|
+
DB_PASSWORD: dbPassword,
|
|
2011
|
+
DATABASE_URL: `mysql://${dbUser}:${dbPassword}@mysql:${port}/${dbName}`
|
|
2012
|
+
},
|
|
2013
|
+
mongodb: {
|
|
2014
|
+
DB_HOST: "mongodb",
|
|
2015
|
+
DB_PORT: port,
|
|
2016
|
+
DB_NAME: dbName,
|
|
2017
|
+
DB_USER: dbUser,
|
|
2018
|
+
DB_PASSWORD: dbPassword,
|
|
2019
|
+
DATABASE_URL: `mongodb://${dbUser}:${dbPassword}@mongodb:${port}/${dbName}`
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
return configs[dbType] || configs.postgres;
|
|
2023
|
+
}
|
|
2024
|
+
function generateHealthCheck() {
|
|
2025
|
+
return `import http from 'http';
|
|
2026
|
+
|
|
2027
|
+
const options = {
|
|
2028
|
+
host: 'localhost',
|
|
2029
|
+
port: process.env.PORT || 3000,
|
|
2030
|
+
path: '/health',
|
|
2031
|
+
timeout: 2000
|
|
2032
|
+
};
|
|
2033
|
+
|
|
2034
|
+
const request = http.request(options, (res) => {
|
|
2035
|
+
console.log(\`Health check status: \${res.statusCode}\`);
|
|
2036
|
+
if (res.statusCode === 200) {
|
|
2037
|
+
process.exit(0);
|
|
2038
|
+
} else {
|
|
2039
|
+
process.exit(1);
|
|
2040
|
+
}
|
|
2041
|
+
});
|
|
2042
|
+
|
|
2043
|
+
request.on('error', (err) => {
|
|
2044
|
+
console.log('Health check failed:', err.message);
|
|
2045
|
+
process.exit(1);
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
request.end();`;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
1474
2051
|
// src/generators/package-scaffold.js
|
|
1475
2052
|
var cliVersion3 = getCLIVersion();
|
|
1476
2053
|
function generateApiScaffolding() {
|
|
@@ -1479,31 +2056,95 @@ import { createRouter } from '@coherent.js/api';
|
|
|
1479
2056
|
|
|
1480
2057
|
const router = createRouter();
|
|
1481
2058
|
|
|
1482
|
-
//
|
|
2059
|
+
// Business Logic
|
|
2060
|
+
async function getUserById(id) {
|
|
2061
|
+
return { id, name: 'Example User', email: 'user@example.com' };
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
async function createUser(data) {
|
|
2065
|
+
return { id: 1, ...data };
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
// Router Definitions (for Express/Fastify/Koa usage)
|
|
1483
2069
|
router.get('/users/:id', {
|
|
1484
2070
|
params: {
|
|
1485
2071
|
id: { type: 'number', required: true }
|
|
1486
2072
|
},
|
|
1487
2073
|
handler: async (req, res) => {
|
|
1488
2074
|
const { id } = req.params;
|
|
1489
|
-
|
|
1490
|
-
return { id, name: 'Example User', email: 'user@example.com' };
|
|
2075
|
+
return getUserById(id);
|
|
1491
2076
|
}
|
|
1492
2077
|
});
|
|
1493
2078
|
|
|
1494
|
-
// Example POST route with body validation
|
|
1495
2079
|
router.post('/users', {
|
|
1496
2080
|
body: {
|
|
1497
2081
|
name: { type: 'string', required: true, minLength: 2 },
|
|
1498
2082
|
email: { type: 'string', required: true, pattern: /^[^@]+@[^@]+\\.[^@]+$/ }
|
|
1499
2083
|
},
|
|
1500
2084
|
handler: async (req, res) => {
|
|
1501
|
-
|
|
1502
|
-
// Create user logic here
|
|
1503
|
-
return { id: 1, name, email };
|
|
2085
|
+
return createUser(req.body);
|
|
1504
2086
|
}
|
|
1505
2087
|
});
|
|
1506
2088
|
|
|
2089
|
+
// Handler for GET /api/users/:id (Built-in Server)
|
|
2090
|
+
export async function getUsersByIdHandler(req, res) {
|
|
2091
|
+
try {
|
|
2092
|
+
const { id } = req.params;
|
|
2093
|
+
const result = await getUserById(id);
|
|
2094
|
+
|
|
2095
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2096
|
+
res.end(JSON.stringify(result));
|
|
2097
|
+
} catch (error) {
|
|
2098
|
+
console.error('API Error:', error);
|
|
2099
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
2100
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
// Handler for POST /api/users (Built-in Server)
|
|
2105
|
+
export async function postUsersHandler(req, res) {
|
|
2106
|
+
try {
|
|
2107
|
+
let body = '';
|
|
2108
|
+
req.on('data', chunk => {
|
|
2109
|
+
body += chunk.toString();
|
|
2110
|
+
});
|
|
2111
|
+
|
|
2112
|
+
req.on('end', async () => {
|
|
2113
|
+
try {
|
|
2114
|
+
const parsedBody = JSON.parse(body);
|
|
2115
|
+
const result = await createUser(parsedBody);
|
|
2116
|
+
|
|
2117
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2118
|
+
res.end(JSON.stringify(result));
|
|
2119
|
+
} catch (error) {
|
|
2120
|
+
console.error('API Error:', error);
|
|
2121
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
2122
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
2123
|
+
}
|
|
2124
|
+
});
|
|
2125
|
+
} catch (error) {
|
|
2126
|
+
console.error('API Error:', error);
|
|
2127
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
2128
|
+
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
// For built-in HTTP server compatibility
|
|
2133
|
+
export function setupRoutes() {
|
|
2134
|
+
return [
|
|
2135
|
+
{
|
|
2136
|
+
path: '/api/users/:id',
|
|
2137
|
+
method: 'GET',
|
|
2138
|
+
handler: getUsersByIdHandler
|
|
2139
|
+
},
|
|
2140
|
+
{
|
|
2141
|
+
path: '/api/users',
|
|
2142
|
+
method: 'POST',
|
|
2143
|
+
handler: postUsersHandler
|
|
2144
|
+
}
|
|
2145
|
+
];
|
|
2146
|
+
}
|
|
2147
|
+
|
|
1507
2148
|
export default router;
|
|
1508
2149
|
`;
|
|
1509
2150
|
return {
|
|
@@ -1527,7 +2168,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1527
2168
|
|
|
1528
2169
|
try {
|
|
1529
2170
|
// Dynamically import component
|
|
1530
|
-
const module = await import(
|
|
2171
|
+
const module = await import(\`/components/\${componentName}.js\`);
|
|
1531
2172
|
const Component = module.default || module[componentName];
|
|
1532
2173
|
|
|
1533
2174
|
// Hydrate component
|
|
@@ -2009,7 +2650,9 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2009
2650
|
auth = null,
|
|
2010
2651
|
packages = [],
|
|
2011
2652
|
language = "javascript",
|
|
2012
|
-
packageManager = "npm"
|
|
2653
|
+
packageManager = "npm",
|
|
2654
|
+
onProgress = () => {
|
|
2655
|
+
}
|
|
2013
2656
|
} = options;
|
|
2014
2657
|
const isTypeScript = language === "typescript";
|
|
2015
2658
|
const fileExtension = isTypeScript ? ".ts" : ".js";
|
|
@@ -2040,8 +2683,10 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2040
2683
|
dirs.forEach((dir) => {
|
|
2041
2684
|
mkdirSync(join2(projectPath, dir), { recursive: true });
|
|
2042
2685
|
});
|
|
2686
|
+
onProgress("Created project structure");
|
|
2043
2687
|
const packageJson = generatePackageJson(name, { template, runtime, database, auth, packages, language, packageManager });
|
|
2044
2688
|
writeFileSync(join2(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
2689
|
+
onProgress("Generated package.json");
|
|
2045
2690
|
if (isTypeScript) {
|
|
2046
2691
|
const tsConfig = generateTsConfig();
|
|
2047
2692
|
writeFileSync(join2(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
|
|
@@ -2049,6 +2694,7 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2049
2694
|
const jsConfig = generateJsConfig();
|
|
2050
2695
|
writeFileSync(join2(projectPath, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
|
|
2051
2696
|
}
|
|
2697
|
+
onProgress("Created configuration files");
|
|
2052
2698
|
const serverContent = generateServerFile(runtime, {
|
|
2053
2699
|
port: 3e3,
|
|
2054
2700
|
hasApi: packages.includes("api") || auth,
|
|
@@ -2056,23 +2702,54 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2056
2702
|
hasAuth: !!auth
|
|
2057
2703
|
});
|
|
2058
2704
|
writeFileSync(join2(projectPath, `src/index${fileExtension}`), serverContent);
|
|
2705
|
+
onProgress("Set up server");
|
|
2059
2706
|
await generateHomePageComponent(projectPath, name, isTypeScript, fileExtension);
|
|
2707
|
+
onProgress("Created components");
|
|
2060
2708
|
if (database) {
|
|
2061
|
-
const dbScaffolding = generateDatabaseScaffolding(database);
|
|
2062
|
-
writeFileSync(join2(projectPath,
|
|
2063
|
-
writeFileSync(join2(projectPath,
|
|
2064
|
-
writeFileSync(join2(projectPath,
|
|
2065
|
-
|
|
2066
|
-
|
|
2709
|
+
const dbScaffolding = generateDatabaseScaffolding(database, language);
|
|
2710
|
+
writeFileSync(join2(projectPath, `src/db/config${fileExtension}`), dbScaffolding.config);
|
|
2711
|
+
writeFileSync(join2(projectPath, `src/db/index${fileExtension}`), dbScaffolding.init);
|
|
2712
|
+
writeFileSync(join2(projectPath, `src/db/models/User${fileExtension}`), dbScaffolding.model);
|
|
2713
|
+
if (options.dockerConfig && database !== "sqlite") {
|
|
2714
|
+
const dockerScaffolding = generateDockerScaffolding(database, options.dockerConfig);
|
|
2715
|
+
writeFileSync(join2(projectPath, "docker-compose.yml"), dockerScaffolding["docker-compose.yml"]);
|
|
2716
|
+
writeFileSync(join2(projectPath, "Dockerfile"), dockerScaffolding["Dockerfile"]);
|
|
2717
|
+
writeFileSync(join2(projectPath, ".dockerignore"), dockerScaffolding[".dockerignore"]);
|
|
2718
|
+
writeFileSync(join2(projectPath, `healthcheck${fileExtension}`), generateHealthCheck());
|
|
2719
|
+
let envContent = "";
|
|
2720
|
+
for (const [key, value] of Object.entries(dockerScaffolding.envConfig)) {
|
|
2721
|
+
envContent += `${key}=${value}
|
|
2722
|
+
`;
|
|
2723
|
+
}
|
|
2724
|
+
writeFileSync(join2(projectPath, ".env.example"), envContent);
|
|
2725
|
+
onProgress("Created Docker configuration");
|
|
2726
|
+
} else {
|
|
2727
|
+
const existingEnv = "";
|
|
2728
|
+
writeFileSync(join2(projectPath, ".env.example"), existingEnv + dbScaffolding.env);
|
|
2729
|
+
}
|
|
2730
|
+
try {
|
|
2731
|
+
copyFileSync(join2(projectPath, ".env.example"), join2(projectPath, ".env"), constants.COPYFILE_EXCL);
|
|
2732
|
+
} catch {
|
|
2733
|
+
}
|
|
2734
|
+
onProgress("Configured database");
|
|
2067
2735
|
}
|
|
2068
2736
|
if (auth) {
|
|
2069
2737
|
const authScaffolding = generateAuthScaffolding(auth, runtime);
|
|
2070
2738
|
const authDir = runtime === "fastify" ? "plugins" : "middleware";
|
|
2071
|
-
writeFileSync(join2(projectPath, `src/${authDir}/auth
|
|
2072
|
-
writeFileSync(join2(projectPath,
|
|
2739
|
+
writeFileSync(join2(projectPath, `src/${authDir}/auth${fileExtension}`), authScaffolding.middleware);
|
|
2740
|
+
writeFileSync(join2(projectPath, `src/api/auth${fileExtension}`), authScaffolding.routes);
|
|
2073
2741
|
const envPath = join2(projectPath, ".env.example");
|
|
2074
2742
|
const existingEnv = "";
|
|
2075
2743
|
writeFileSync(envPath, existingEnv + authScaffolding.env);
|
|
2744
|
+
try {
|
|
2745
|
+
const envContent = readFileSync2(join2(projectPath, ".env"), "utf8");
|
|
2746
|
+
if (!envContent.includes("JWT_SECRET") && !envContent.includes("SESSION_SECRET")) {
|
|
2747
|
+
appendFileSync(join2(projectPath, ".env"), authScaffolding.env);
|
|
2748
|
+
}
|
|
2749
|
+
} catch {
|
|
2750
|
+
writeFileSync(join2(projectPath, ".env"), authScaffolding.env);
|
|
2751
|
+
}
|
|
2752
|
+
onProgress("Set up authentication");
|
|
2076
2753
|
}
|
|
2077
2754
|
if (packages.length > 0) {
|
|
2078
2755
|
const { files } = generatePackageScaffolding(packages);
|
|
@@ -2143,6 +2820,9 @@ function generatePackageJson(name, options) {
|
|
|
2143
2820
|
const tsDeps = getTypeScriptDependencies();
|
|
2144
2821
|
Object.assign(base.devDependencies, tsDeps);
|
|
2145
2822
|
base.devDependencies.tsx = "^4.19.2";
|
|
2823
|
+
if (auth) {
|
|
2824
|
+
base.devDependencies["@types/jsonwebtoken"] = "^9.0.7";
|
|
2825
|
+
}
|
|
2146
2826
|
}
|
|
2147
2827
|
if (packageManager === "pnpm") {
|
|
2148
2828
|
base.packageManager = "pnpm@9.0.0";
|
|
@@ -2152,7 +2832,7 @@ function generatePackageJson(name, options) {
|
|
|
2152
2832
|
const runtimeDeps = getRuntimeDependencies(runtime);
|
|
2153
2833
|
Object.assign(base.dependencies, runtimeDeps);
|
|
2154
2834
|
if (database) {
|
|
2155
|
-
const { dependencies: dbDeps } = generateDatabaseScaffolding(database);
|
|
2835
|
+
const { dependencies: dbDeps } = generateDatabaseScaffolding(database, language);
|
|
2156
2836
|
Object.assign(base.dependencies, dbDeps);
|
|
2157
2837
|
}
|
|
2158
2838
|
if (auth) {
|
|
@@ -2295,16 +2975,16 @@ A Coherent.js application built with pure JavaScript objects.
|
|
|
2295
2975
|
|
|
2296
2976
|
\`\`\`bash
|
|
2297
2977
|
# Install dependencies
|
|
2298
|
-
|
|
2978
|
+
pnpm install
|
|
2299
2979
|
|
|
2300
2980
|
# Start development server
|
|
2301
|
-
|
|
2981
|
+
pnpm run dev
|
|
2302
2982
|
|
|
2303
2983
|
# Build for production
|
|
2304
|
-
|
|
2984
|
+
pnpm run build
|
|
2305
2985
|
|
|
2306
2986
|
# Run tests
|
|
2307
|
-
|
|
2987
|
+
pnpm test
|
|
2308
2988
|
\`\`\`
|
|
2309
2989
|
|
|
2310
2990
|
## Project Structure
|
|
@@ -2323,7 +3003,7 @@ tests/ # Test files
|
|
|
2323
3003
|
## Learn More
|
|
2324
3004
|
|
|
2325
3005
|
- [Coherent.js Documentation](https://github.com/Tomdrouv1/coherent.js)
|
|
2326
|
-
- [API Reference](https://github.com/Tomdrouv1/coherent.js/docs/api-reference.md)
|
|
3006
|
+
- [API Reference](https://github.com/Tomdrouv1/coherent.js/tree/main/docs/api-reference.md)
|
|
2327
3007
|
|
|
2328
3008
|
## License
|
|
2329
3009
|
|
|
@@ -2387,21 +3067,21 @@ logs
|
|
|
2387
3067
|
.node_repl_history
|
|
2388
3068
|
`;
|
|
2389
3069
|
writeFileSync(join2(projectPath, ".gitignore"), gitignore);
|
|
2390
|
-
const testFile = `import {
|
|
2391
|
-
import assert from 'node:assert';
|
|
3070
|
+
const testFile = `import { describe, it, expect } from 'vitest';
|
|
2392
3071
|
import { render } from '@coherent.js/core';
|
|
2393
3072
|
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
3073
|
+
describe('Basic Component Rendering', () => {
|
|
3074
|
+
it('renders basic component', () => {
|
|
3075
|
+
const component = {
|
|
3076
|
+
div: {
|
|
3077
|
+
text: 'Hello, World!'
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
2400
3080
|
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
});
|
|
2404
|
-
|
|
3081
|
+
const html = render(component);
|
|
3082
|
+
expect(html).toContain('Hello, World!');
|
|
3083
|
+
});
|
|
3084
|
+
});`;
|
|
2405
3085
|
writeFileSync(join2(projectPath, "tests/basic.test.js"), testFile);
|
|
2406
3086
|
}
|
|
2407
3087
|
|
|
@@ -2482,7 +3162,15 @@ function validateComponentName(name) {
|
|
|
2482
3162
|
}
|
|
2483
3163
|
|
|
2484
3164
|
// src/commands/create.js
|
|
2485
|
-
|
|
3165
|
+
function getDefaultDockerPort(database) {
|
|
3166
|
+
const ports = {
|
|
3167
|
+
postgres: 5432,
|
|
3168
|
+
mysql: 3306,
|
|
3169
|
+
mongodb: 27017
|
|
3170
|
+
};
|
|
3171
|
+
return ports[database] || 5432;
|
|
3172
|
+
}
|
|
3173
|
+
var createCommand = new Command("create").description("Create a new Coherent.js project").argument("[name]", "project name").option("-t, --template <template>", "project template", "basic").option("--runtime <runtime>", "runtime framework", "koa").option("--database <database>", "database type").option("--auth <auth>", "authentication type").option("--language <language>", "language", "javascript").option("--skip-install", "skip npm install").option("--skip-git", "skip git initialization").option("--skip-prompts", "skip interactive prompts").option("--use-docker", "include Docker configuration for database").option("--docker-db-port <port>", "Docker database port").option("--docker-db-name <name>", "Docker database name").option("--docker-db-user <user>", "Docker database user").option("--docker-db-password <password>", "Docker database password").action(async (name, options) => {
|
|
2486
3174
|
let projectName = name;
|
|
2487
3175
|
if (!projectName) {
|
|
2488
3176
|
const response = await prompts({
|
|
@@ -2514,48 +3202,48 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2514
3202
|
console.log(picocolors.gray("\u{1F4CD} Location:"), projectPath);
|
|
2515
3203
|
console.log();
|
|
2516
3204
|
let template = options.template;
|
|
2517
|
-
if (!template || template === "basic") {
|
|
2518
|
-
|
|
3205
|
+
if (!template || template === "basic" && !options.skipPrompts) {
|
|
3206
|
+
if (!options.skipPrompts) {
|
|
3207
|
+
const response = await prompts({
|
|
3208
|
+
type: "select",
|
|
3209
|
+
name: "template",
|
|
3210
|
+
message: "Which template would you like to use?",
|
|
3211
|
+
choices: [
|
|
3212
|
+
{ title: "\u{1F3C3}\u200D\u2642\uFE0F Basic App", value: "basic", description: "Simple SSR app with routing" },
|
|
3213
|
+
{ title: "\u{1F310} Full Stack", value: "fullstack", description: "API + SSR with database and auth options" }
|
|
3214
|
+
],
|
|
3215
|
+
initial: 0
|
|
3216
|
+
});
|
|
3217
|
+
if (!response.template) {
|
|
3218
|
+
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
3219
|
+
process.exit(0);
|
|
3220
|
+
}
|
|
3221
|
+
template = response.template;
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
let runtime = options.runtime || "built-in";
|
|
3225
|
+
let database = options.database || null;
|
|
3226
|
+
let auth = options.auth || null;
|
|
3227
|
+
let packages = [];
|
|
3228
|
+
let language = options.language || "javascript";
|
|
3229
|
+
if (!options.skipPrompts) {
|
|
3230
|
+
const languageResponse = await prompts({
|
|
2519
3231
|
type: "select",
|
|
2520
|
-
name: "
|
|
2521
|
-
message: "
|
|
3232
|
+
name: "language",
|
|
3233
|
+
message: "Would you like to use TypeScript or JavaScript?",
|
|
2522
3234
|
choices: [
|
|
2523
|
-
{ title: "\u{
|
|
2524
|
-
{ title: "\u{
|
|
2525
|
-
{ title: "\u26A1 Express Integration", value: "express", description: "Coherent.js with Express.js" },
|
|
2526
|
-
{ title: "\u{1F680} Fastify Integration", value: "fastify", description: "Coherent.js with Fastify" },
|
|
2527
|
-
{ title: "\u{1F4F1} Component Library", value: "components", description: "Reusable component library" },
|
|
2528
|
-
{ title: "\u{1F3A8} Custom Setup", value: "custom", description: "Choose your own runtime and packages" }
|
|
3235
|
+
{ title: "\u{1F4D8} JavaScript", value: "javascript", description: "JavaScript with JSDoc type hints (recommended)" },
|
|
3236
|
+
{ title: "\u{1F4D5} TypeScript", value: "typescript", description: "Full TypeScript with static type checking" }
|
|
2529
3237
|
],
|
|
2530
3238
|
initial: 0
|
|
2531
3239
|
});
|
|
2532
|
-
if (!
|
|
3240
|
+
if (!languageResponse.language) {
|
|
2533
3241
|
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
2534
3242
|
process.exit(0);
|
|
2535
3243
|
}
|
|
2536
|
-
|
|
3244
|
+
language = languageResponse.language;
|
|
2537
3245
|
}
|
|
2538
|
-
|
|
2539
|
-
let database = null;
|
|
2540
|
-
let auth = null;
|
|
2541
|
-
let packages = [];
|
|
2542
|
-
let language = "javascript";
|
|
2543
|
-
const languageResponse = await prompts({
|
|
2544
|
-
type: "select",
|
|
2545
|
-
name: "language",
|
|
2546
|
-
message: "Would you like to use TypeScript or JavaScript?",
|
|
2547
|
-
choices: [
|
|
2548
|
-
{ title: "\u{1F4D8} JavaScript", value: "javascript", description: "JavaScript with JSDoc type hints (recommended)" },
|
|
2549
|
-
{ title: "\u{1F4D5} TypeScript", value: "typescript", description: "Full TypeScript with static type checking" }
|
|
2550
|
-
],
|
|
2551
|
-
initial: 0
|
|
2552
|
-
});
|
|
2553
|
-
if (!languageResponse.language) {
|
|
2554
|
-
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
2555
|
-
process.exit(0);
|
|
2556
|
-
}
|
|
2557
|
-
language = languageResponse.language;
|
|
2558
|
-
if (template === "custom" || template === "basic" || template === "fullstack" || template === "components") {
|
|
3246
|
+
if ((template === "basic" || template === "fullstack") && !options.skipPrompts) {
|
|
2559
3247
|
const runtimeResponse = await prompts({
|
|
2560
3248
|
type: "select",
|
|
2561
3249
|
name: "runtime",
|
|
@@ -2573,46 +3261,50 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2573
3261
|
process.exit(0);
|
|
2574
3262
|
}
|
|
2575
3263
|
runtime = runtimeResponse.runtime;
|
|
2576
|
-
} else if (template === "express") {
|
|
2577
|
-
runtime = "express";
|
|
2578
|
-
} else if (template === "fastify") {
|
|
2579
|
-
runtime = "fastify";
|
|
2580
3264
|
}
|
|
2581
|
-
if (template === "fullstack"
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
3265
|
+
if (template === "fullstack") {
|
|
3266
|
+
if (!options.skipPrompts) {
|
|
3267
|
+
const dbResponse = await prompts({
|
|
3268
|
+
type: "select",
|
|
3269
|
+
name: "database",
|
|
3270
|
+
message: "Which database would you like to use?",
|
|
3271
|
+
choices: [
|
|
3272
|
+
{ title: "\u{1F418} PostgreSQL", value: "postgres", description: "Powerful, open source relational database" },
|
|
3273
|
+
{ title: "\u{1F42C} MySQL", value: "mysql", description: "Popular open source relational database" },
|
|
3274
|
+
{ title: "\u{1F4E6} SQLite", value: "sqlite", description: "Lightweight, file-based database" },
|
|
3275
|
+
{ title: "\u{1F343} MongoDB", value: "mongodb", description: "NoSQL document database" },
|
|
3276
|
+
{ title: "\u274C None", value: "none", description: "Skip database setup" }
|
|
3277
|
+
],
|
|
3278
|
+
initial: 0
|
|
3279
|
+
});
|
|
3280
|
+
if (!dbResponse.database) {
|
|
3281
|
+
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
3282
|
+
process.exit(0);
|
|
3283
|
+
}
|
|
3284
|
+
database = dbResponse.database === "none" ? null : dbResponse.database;
|
|
3285
|
+
} else {
|
|
3286
|
+
database = options.database || null;
|
|
2598
3287
|
}
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
3288
|
+
if (!options.skipPrompts) {
|
|
3289
|
+
const pkgResponse = await prompts({
|
|
3290
|
+
type: "multiselect",
|
|
3291
|
+
name: "packages",
|
|
3292
|
+
message: "Select optional packages (space to select, enter to confirm):",
|
|
3293
|
+
choices: [
|
|
3294
|
+
{ title: "@coherent.js/api", value: "api", description: "API framework with validation & OpenAPI", selected: template === "fullstack" },
|
|
3295
|
+
{ title: "@coherent.js/client", value: "client", description: "Client-side hydration & progressive enhancement" },
|
|
3296
|
+
{ title: "@coherent.js/i18n", value: "i18n", description: "Internationalization utilities" },
|
|
3297
|
+
{ title: "@coherent.js/forms", value: "forms", description: "Form handling utilities" },
|
|
3298
|
+
{ title: "@coherent.js/devtools", value: "devtools", description: "Development tools & debugging" },
|
|
3299
|
+
{ title: "@coherent.js/seo", value: "seo", description: "SEO optimization utilities" },
|
|
3300
|
+
{ title: "@coherent.js/testing", value: "testing", description: "Testing utilities & helpers" }
|
|
3301
|
+
]
|
|
3302
|
+
});
|
|
3303
|
+
packages = pkgResponse.packages || [];
|
|
3304
|
+
} else {
|
|
3305
|
+
packages = template === "fullstack" ? ["api"] : [];
|
|
3306
|
+
}
|
|
3307
|
+
if (!options.skipPrompts && (packages.includes("api") || database)) {
|
|
2616
3308
|
const authResponse = await prompts({
|
|
2617
3309
|
type: "select",
|
|
2618
3310
|
name: "auth",
|
|
@@ -2626,7 +3318,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2626
3318
|
});
|
|
2627
3319
|
auth = authResponse.auth === "none" ? null : authResponse.auth;
|
|
2628
3320
|
}
|
|
2629
|
-
} else if (template === "basic"
|
|
3321
|
+
} else if (template === "basic" && !options.skipPrompts) {
|
|
2630
3322
|
const pkgResponse = await prompts({
|
|
2631
3323
|
type: "multiselect",
|
|
2632
3324
|
name: "packages",
|
|
@@ -2641,7 +3333,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2641
3333
|
packages = pkgResponse.packages || [];
|
|
2642
3334
|
}
|
|
2643
3335
|
let packageManager = "npm";
|
|
2644
|
-
if (!options.skipInstall) {
|
|
3336
|
+
if (!options.skipInstall && !options.skipPrompts) {
|
|
2645
3337
|
const pmResponse = await prompts({
|
|
2646
3338
|
type: "select",
|
|
2647
3339
|
name: "packageManager",
|
|
@@ -2659,6 +3351,56 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2659
3351
|
}
|
|
2660
3352
|
packageManager = pmResponse.packageManager;
|
|
2661
3353
|
}
|
|
3354
|
+
let dockerConfig = null;
|
|
3355
|
+
if (database && database !== "sqlite" && !options.skipPrompts) {
|
|
3356
|
+
const dockerResponse = await prompts({
|
|
3357
|
+
type: "confirm",
|
|
3358
|
+
name: "useDocker",
|
|
3359
|
+
message: "Would you like to include Docker configuration for the database?",
|
|
3360
|
+
initial: true
|
|
3361
|
+
});
|
|
3362
|
+
if (dockerResponse.useDocker) {
|
|
3363
|
+
const dockerDetailsResponse = await prompts([
|
|
3364
|
+
{
|
|
3365
|
+
type: "number",
|
|
3366
|
+
name: "dbPort",
|
|
3367
|
+
message: "What port should the database use?",
|
|
3368
|
+
initial: getDefaultDockerPort(database)
|
|
3369
|
+
},
|
|
3370
|
+
{
|
|
3371
|
+
type: "text",
|
|
3372
|
+
name: "dbName",
|
|
3373
|
+
message: "What should the database be named?",
|
|
3374
|
+
initial: "coherent_db"
|
|
3375
|
+
},
|
|
3376
|
+
{
|
|
3377
|
+
type: "text",
|
|
3378
|
+
name: "dbUser",
|
|
3379
|
+
message: "What should the database user be?",
|
|
3380
|
+
initial: "coherent_user"
|
|
3381
|
+
},
|
|
3382
|
+
{
|
|
3383
|
+
type: "text",
|
|
3384
|
+
name: "dbPassword",
|
|
3385
|
+
message: "What should the database password be?",
|
|
3386
|
+
initial: "coherent_pass"
|
|
3387
|
+
}
|
|
3388
|
+
]);
|
|
3389
|
+
dockerConfig = {
|
|
3390
|
+
port: dockerDetailsResponse.dbPort || getDefaultDockerPort(database),
|
|
3391
|
+
name: dockerDetailsResponse.dbName,
|
|
3392
|
+
user: dockerDetailsResponse.dbUser,
|
|
3393
|
+
password: dockerDetailsResponse.dbPassword
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
} else if (database && database !== "sqlite" && options.useDocker) {
|
|
3397
|
+
dockerConfig = {
|
|
3398
|
+
port: options.dockerDbPort || getDefaultDockerPort(database),
|
|
3399
|
+
name: options.dockerDbName || "coherent_db",
|
|
3400
|
+
user: options.dockerDbUser || "coherent_user",
|
|
3401
|
+
password: options.dockerDbPassword || "coherent_pass"
|
|
3402
|
+
};
|
|
3403
|
+
}
|
|
2662
3404
|
const spinner = ora("Scaffolding project...").start();
|
|
2663
3405
|
try {
|
|
2664
3406
|
mkdirSync2(projectPath, { recursive: true });
|
|
@@ -2671,30 +3413,77 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2671
3413
|
packages,
|
|
2672
3414
|
language,
|
|
2673
3415
|
packageManager,
|
|
3416
|
+
dockerConfig,
|
|
2674
3417
|
skipInstall: options.skipInstall,
|
|
2675
|
-
skipGit: options.skipGit
|
|
3418
|
+
skipGit: options.skipGit,
|
|
3419
|
+
onProgress: (msg) => {
|
|
3420
|
+
spinner.text = msg;
|
|
3421
|
+
}
|
|
2676
3422
|
});
|
|
2677
3423
|
spinner.succeed("Project created successfully!");
|
|
2678
3424
|
console.log();
|
|
2679
|
-
console.log(picocolors.green("
|
|
3425
|
+
console.log(picocolors.green("Project created successfully!"));
|
|
2680
3426
|
console.log();
|
|
2681
|
-
console.log(picocolors.cyan("
|
|
2682
|
-
console.log(picocolors.gray("
|
|
2683
|
-
console.log(picocolors.gray("
|
|
3427
|
+
console.log(picocolors.cyan("Configuration:"));
|
|
3428
|
+
console.log(picocolors.gray(" Template:"), picocolors.white(template === "fullstack" ? "Full Stack" : "Basic"));
|
|
3429
|
+
console.log(picocolors.gray(" Language:"), picocolors.white(language === "typescript" ? "TypeScript" : "JavaScript"));
|
|
3430
|
+
console.log(picocolors.gray(" Runtime:"), picocolors.white(runtime));
|
|
2684
3431
|
if (database) {
|
|
2685
|
-
console.log(picocolors.gray(" Database:"), picocolors.
|
|
3432
|
+
console.log(picocolors.gray(" Database:"), picocolors.white(database));
|
|
2686
3433
|
}
|
|
2687
3434
|
if (auth) {
|
|
2688
|
-
console.log(picocolors.gray("
|
|
3435
|
+
console.log(picocolors.gray(" Auth:"), picocolors.white(auth.toUpperCase()));
|
|
2689
3436
|
}
|
|
2690
3437
|
if (packages.length > 0) {
|
|
2691
|
-
|
|
3438
|
+
const formattedPackages = packages.map((p) => `@coherent.js/${p}`).join(", ");
|
|
3439
|
+
console.log(picocolors.gray(" Packages:"), picocolors.white(formattedPackages));
|
|
2692
3440
|
}
|
|
2693
3441
|
console.log();
|
|
2694
|
-
|
|
2695
|
-
console.log(picocolors.
|
|
3442
|
+
const fileExt = language === "typescript" ? ".ts" : ".js";
|
|
3443
|
+
console.log(picocolors.cyan("Project structure:"));
|
|
3444
|
+
console.log(picocolors.white(` ${projectName}/`));
|
|
3445
|
+
console.log(picocolors.gray(` src/`));
|
|
3446
|
+
console.log(picocolors.gray(` index${fileExt}`));
|
|
3447
|
+
console.log(picocolors.gray(` components/`));
|
|
2696
3448
|
if (database) {
|
|
2697
|
-
console.log(picocolors.gray(
|
|
3449
|
+
console.log(picocolors.gray(` db/`));
|
|
3450
|
+
}
|
|
3451
|
+
if (auth || packages.includes("api")) {
|
|
3452
|
+
console.log(picocolors.gray(` api/`));
|
|
3453
|
+
}
|
|
3454
|
+
console.log(picocolors.gray(` public/`));
|
|
3455
|
+
console.log(picocolors.gray(` package.json`));
|
|
3456
|
+
if (database) {
|
|
3457
|
+
console.log(picocolors.gray(` .env.example`), picocolors.yellow("<-- Configure this!"));
|
|
3458
|
+
}
|
|
3459
|
+
console.log();
|
|
3460
|
+
const needsEnvConfig = database && database !== "sqlite";
|
|
3461
|
+
const envVars = [];
|
|
3462
|
+
if (needsEnvConfig) {
|
|
3463
|
+
if (database === "mongodb") {
|
|
3464
|
+
envVars.push("MONGODB_URI");
|
|
3465
|
+
} else {
|
|
3466
|
+
envVars.push("DB_HOST", "DB_PORT", "DB_NAME", "DB_USER", "DB_PASSWORD");
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
if (auth === "jwt") {
|
|
3470
|
+
envVars.push("JWT_SECRET");
|
|
3471
|
+
}
|
|
3472
|
+
if (auth === "session") {
|
|
3473
|
+
envVars.push("SESSION_SECRET");
|
|
3474
|
+
}
|
|
3475
|
+
if (envVars.length > 0) {
|
|
3476
|
+
console.log(picocolors.yellow("Environment variables to configure:"));
|
|
3477
|
+
envVars.forEach((v) => console.log(picocolors.gray(` ${v}`)));
|
|
3478
|
+
console.log();
|
|
3479
|
+
}
|
|
3480
|
+
console.log(picocolors.cyan("Next steps:"));
|
|
3481
|
+
let stepNum = 1;
|
|
3482
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(`cd ${projectName}`));
|
|
3483
|
+
stepNum++;
|
|
3484
|
+
if (needsEnvConfig) {
|
|
3485
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray("Edit .env with your database credentials"));
|
|
3486
|
+
stepNum++;
|
|
2698
3487
|
}
|
|
2699
3488
|
const pmCommands = {
|
|
2700
3489
|
npm: { install: "npm install", dev: "npm run dev" },
|
|
@@ -2702,14 +3491,41 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2702
3491
|
pnpm: { install: "pnpm install", dev: "pnpm dev" }
|
|
2703
3492
|
};
|
|
2704
3493
|
const commands = pmCommands[packageManager] || pmCommands.npm;
|
|
2705
|
-
if (
|
|
2706
|
-
console.log(picocolors.
|
|
2707
|
-
|
|
2708
|
-
console.log(picocolors.gray(` ${commands.install}`));
|
|
2709
|
-
console.log(picocolors.gray(` ${commands.dev}`));
|
|
3494
|
+
if (options.skipInstall) {
|
|
3495
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.install));
|
|
3496
|
+
stepNum++;
|
|
2710
3497
|
}
|
|
3498
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.dev));
|
|
2711
3499
|
console.log();
|
|
2712
|
-
|
|
3500
|
+
if (!options.skipPrompts && !options.skipInstall) {
|
|
3501
|
+
const startResponse = await prompts({
|
|
3502
|
+
type: "confirm",
|
|
3503
|
+
name: "startDev",
|
|
3504
|
+
message: "Start development server now?",
|
|
3505
|
+
initial: true
|
|
3506
|
+
});
|
|
3507
|
+
if (startResponse.startDev) {
|
|
3508
|
+
console.log();
|
|
3509
|
+
console.log(picocolors.cyan("Starting development server..."));
|
|
3510
|
+
console.log(picocolors.gray(` ${commands.dev}`));
|
|
3511
|
+
console.log();
|
|
3512
|
+
try {
|
|
3513
|
+
const devProcess = spawn(commands.dev, [], {
|
|
3514
|
+
cwd: projectPath,
|
|
3515
|
+
stdio: "inherit",
|
|
3516
|
+
shell: true,
|
|
3517
|
+
detached: true
|
|
3518
|
+
});
|
|
3519
|
+
devProcess.unref();
|
|
3520
|
+
return;
|
|
3521
|
+
} catch {
|
|
3522
|
+
console.log(picocolors.yellow("Could not start development server automatically."));
|
|
3523
|
+
console.log(picocolors.gray(` Run manually: cd ${projectName} && ${commands.dev}`));
|
|
3524
|
+
console.log();
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
console.log(picocolors.gray("Happy coding!"));
|
|
2713
3529
|
} catch (_error) {
|
|
2714
3530
|
spinner.fail("Failed to create project");
|
|
2715
3531
|
console.error(picocolors.red("\u274C Error:"), _error.message);
|
|
@@ -2776,7 +3592,7 @@ function generateBasicComponent(name) {
|
|
|
2776
3592
|
|
|
2777
3593
|
/**
|
|
2778
3594
|
* ${name} component
|
|
2779
|
-
*
|
|
3595
|
+
*
|
|
2780
3596
|
* @param {Object} props - Component properties
|
|
2781
3597
|
* @param {string} props.className - CSS class name
|
|
2782
3598
|
* @param {Array|Object} props.children - Child elements
|
|
@@ -2803,7 +3619,7 @@ function generateFunctionalComponent(name) {
|
|
|
2803
3619
|
|
|
2804
3620
|
/**
|
|
2805
3621
|
* ${name} - Functional component with business logic
|
|
2806
|
-
*
|
|
3622
|
+
*
|
|
2807
3623
|
* @param {Object} props - Component properties
|
|
2808
3624
|
* @param {Array} props.items - Items to display
|
|
2809
3625
|
* @param {Function} props.onItemClick - Callback for item clicks
|
|
@@ -2821,11 +3637,11 @@ export const ${name} = createComponent(({ items = [], onItemClick, className = '
|
|
|
2821
3637
|
div: {
|
|
2822
3638
|
className: \`${name.toLowerCase()} \${className}\`.trim(),
|
|
2823
3639
|
children: [
|
|
2824
|
-
{
|
|
2825
|
-
h3: {
|
|
3640
|
+
{
|
|
3641
|
+
h3: {
|
|
2826
3642
|
className: '${name.toLowerCase()}__title',
|
|
2827
|
-
text: '${name}'
|
|
2828
|
-
}
|
|
3643
|
+
text: '${name}'
|
|
3644
|
+
}
|
|
2829
3645
|
},
|
|
2830
3646
|
{
|
|
2831
3647
|
ul: {
|
|
@@ -2868,17 +3684,17 @@ function generateInteractiveComponent(name) {
|
|
|
2868
3684
|
|
|
2869
3685
|
/**
|
|
2870
3686
|
* ${name} - Interactive component with state management
|
|
2871
|
-
*
|
|
3687
|
+
*
|
|
2872
3688
|
* @param {Object} props - Component properties
|
|
2873
3689
|
* @param {*} props.initialValue - Initial value
|
|
2874
3690
|
* @param {Function} props.onChange - Change callback
|
|
2875
3691
|
* @param {string} props.className - CSS class name
|
|
2876
3692
|
*/
|
|
2877
|
-
export const ${name} = createComponent(({
|
|
2878
|
-
initialValue = '',
|
|
3693
|
+
export const ${name} = createComponent(({
|
|
3694
|
+
initialValue = '',
|
|
2879
3695
|
onChange,
|
|
2880
3696
|
className = '',
|
|
2881
|
-
...props
|
|
3697
|
+
...props
|
|
2882
3698
|
}) => {
|
|
2883
3699
|
// Component state (handled by Coherent.js hydration)
|
|
2884
3700
|
const state = {
|
|
@@ -2955,7 +3771,7 @@ function generateLayoutComponent(name) {
|
|
|
2955
3771
|
|
|
2956
3772
|
/**
|
|
2957
3773
|
* ${name} - Layout component for page structure
|
|
2958
|
-
*
|
|
3774
|
+
*
|
|
2959
3775
|
* @param {Object} props - Component properties
|
|
2960
3776
|
* @param {string} props.title - Page title
|
|
2961
3777
|
* @param {Array|Object} props.children - Child content
|
|
@@ -2963,7 +3779,7 @@ function generateLayoutComponent(name) {
|
|
|
2963
3779
|
* @param {Object} props.footer - Footer content
|
|
2964
3780
|
* @param {string} props.className - CSS class name
|
|
2965
3781
|
*/
|
|
2966
|
-
export const ${name} = createComponent(({
|
|
3782
|
+
export const ${name} = createComponent(({
|
|
2967
3783
|
title = 'Page Title',
|
|
2968
3784
|
children = [],
|
|
2969
3785
|
header = null,
|
|
@@ -3037,38 +3853,39 @@ export const ${name} = createComponent(({
|
|
|
3037
3853
|
`;
|
|
3038
3854
|
}
|
|
3039
3855
|
function generateTestContent(name) {
|
|
3040
|
-
return `import {
|
|
3041
|
-
import assert from 'node:assert';
|
|
3856
|
+
return `import { describe, it, expect } from 'vitest';
|
|
3042
3857
|
import { render } from '@coherent.js/core';
|
|
3043
3858
|
import { ${name} } from './${name}.js';
|
|
3044
3859
|
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
assert(typeof html === 'string');
|
|
3050
|
-
assert(html.length > 0);
|
|
3051
|
-
assert(html.includes('${name.toLowerCase()}'));
|
|
3052
|
-
});
|
|
3860
|
+
describe('${name}', () => {
|
|
3861
|
+
it('renders correctly', () => {
|
|
3862
|
+
const component = ${name}({});
|
|
3863
|
+
const html = render(component);
|
|
3053
3864
|
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
assert(html.includes('test-class'));
|
|
3059
|
-
});
|
|
3865
|
+
expect(typeof html).toBe('string');
|
|
3866
|
+
expect(html.length).toBeGreaterThan(0);
|
|
3867
|
+
expect(html).toContain('${name.toLowerCase()}');
|
|
3868
|
+
});
|
|
3060
3869
|
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
const html = render(component);
|
|
3068
|
-
|
|
3069
|
-
assert(html.includes('Test child content'));
|
|
3870
|
+
it('accepts className prop', () => {
|
|
3871
|
+
const component = ${name}({ className: 'test-class' });
|
|
3872
|
+
const html = render(component);
|
|
3873
|
+
|
|
3874
|
+
expect(html).toContain('test-class');
|
|
3875
|
+
});
|
|
3070
3876
|
});
|
|
3071
|
-
|
|
3877
|
+
|
|
3878
|
+
it('renders children correctly', () => {
|
|
3879
|
+
const children = [
|
|
3880
|
+
{ p: { text: 'Test child content' } }
|
|
3881
|
+
];
|
|
3882
|
+
|
|
3883
|
+
const component = ${name}({ children });
|
|
3884
|
+
const html = render(component);
|
|
3885
|
+
|
|
3886
|
+
expect(html).toContain('Test child content');
|
|
3887
|
+
});
|
|
3888
|
+
});`;
|
|
3072
3889
|
}
|
|
3073
3890
|
function generateStoryContent(name) {
|
|
3074
3891
|
return `import { ${name} } from './${name}.js';
|
|
@@ -3161,7 +3978,7 @@ function generateBasicPage(name) {
|
|
|
3161
3978
|
/**
|
|
3162
3979
|
* ${name} Page Component
|
|
3163
3980
|
* Route: /${routeName}
|
|
3164
|
-
*
|
|
3981
|
+
*
|
|
3165
3982
|
* @param {Object} props - Page properties
|
|
3166
3983
|
* @param {Object} props.params - Route parameters
|
|
3167
3984
|
* @param {Object} props.query - Query parameters
|
|
@@ -3179,17 +3996,17 @@ export const ${name} = createComponent(({ params = {}, query = {}, request, ...p
|
|
|
3179
3996
|
head: {
|
|
3180
3997
|
children: [
|
|
3181
3998
|
{ title: { text: pageTitle } },
|
|
3182
|
-
{
|
|
3183
|
-
meta: {
|
|
3999
|
+
{
|
|
4000
|
+
meta: {
|
|
3184
4001
|
name: 'description',
|
|
3185
4002
|
content: pageDescription
|
|
3186
|
-
}
|
|
4003
|
+
}
|
|
3187
4004
|
},
|
|
3188
|
-
{
|
|
3189
|
-
meta: {
|
|
3190
|
-
name: 'viewport',
|
|
3191
|
-
content: 'width=device-width, initial-scale=1.0'
|
|
3192
|
-
}
|
|
4005
|
+
{
|
|
4006
|
+
meta: {
|
|
4007
|
+
name: 'viewport',
|
|
4008
|
+
content: 'width=device-width, initial-scale=1.0'
|
|
4009
|
+
}
|
|
3193
4010
|
}
|
|
3194
4011
|
]
|
|
3195
4012
|
}
|
|
@@ -3300,10 +4117,10 @@ ${name}.description = '${name} page description';
|
|
|
3300
4117
|
|
|
3301
4118
|
// Usage in router:
|
|
3302
4119
|
// app.get('/${routeName}', (req, res) => {
|
|
3303
|
-
// const html = render(${name}({
|
|
3304
|
-
// params: req.params,
|
|
4120
|
+
// const html = render(${name}({
|
|
4121
|
+
// params: req.params,
|
|
3305
4122
|
// query: req.query,
|
|
3306
|
-
// request: req
|
|
4123
|
+
// request: req
|
|
3307
4124
|
// }));
|
|
3308
4125
|
// res.send(html);
|
|
3309
4126
|
// });
|
|
@@ -3331,11 +4148,11 @@ export const ${name} = createComponent(({ stats = {}, user = null }) => {
|
|
|
3331
4148
|
head: {
|
|
3332
4149
|
children: [
|
|
3333
4150
|
{ title: { text: '${name} Dashboard' } },
|
|
3334
|
-
{
|
|
3335
|
-
meta: {
|
|
3336
|
-
name: 'viewport',
|
|
3337
|
-
content: 'width=device-width, initial-scale=1.0'
|
|
3338
|
-
}
|
|
4151
|
+
{
|
|
4152
|
+
meta: {
|
|
4153
|
+
name: 'viewport',
|
|
4154
|
+
content: 'width=device-width, initial-scale=1.0'
|
|
4155
|
+
}
|
|
3339
4156
|
}
|
|
3340
4157
|
]
|
|
3341
4158
|
}
|
|
@@ -3486,11 +4303,11 @@ export const ${name} = createComponent(({ initialData = {}, errors = {} }) => {
|
|
|
3486
4303
|
head: {
|
|
3487
4304
|
children: [
|
|
3488
4305
|
{ title: { text: '${name} Form' } },
|
|
3489
|
-
{
|
|
3490
|
-
meta: {
|
|
3491
|
-
name: 'viewport',
|
|
3492
|
-
content: 'width=device-width, initial-scale=1.0'
|
|
3493
|
-
}
|
|
4306
|
+
{
|
|
4307
|
+
meta: {
|
|
4308
|
+
name: 'viewport',
|
|
4309
|
+
content: 'width=device-width, initial-scale=1.0'
|
|
4310
|
+
}
|
|
3494
4311
|
}
|
|
3495
4312
|
]
|
|
3496
4313
|
}
|
|
@@ -3630,42 +4447,42 @@ export const ${name} = createComponent(({ initialData = {}, errors = {} }) => {
|
|
|
3630
4447
|
`;
|
|
3631
4448
|
}
|
|
3632
4449
|
function generateTestContent2(name) {
|
|
3633
|
-
return `import {
|
|
3634
|
-
import assert from 'node:assert';
|
|
4450
|
+
return `import { describe, it, expect } from 'vitest';
|
|
3635
4451
|
import { render } from '@coherent.js/core';
|
|
3636
4452
|
import { ${name} } from './${name}.js';
|
|
3637
4453
|
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
assert(typeof html === 'string');
|
|
3643
|
-
assert(html.length > 0);
|
|
3644
|
-
assert(html.includes('<html>'));
|
|
3645
|
-
assert(html.includes('${name}'));
|
|
3646
|
-
});
|
|
4454
|
+
describe('${name} Page', () => {
|
|
4455
|
+
it('renders correctly', () => {
|
|
4456
|
+
const page = ${name}({});
|
|
4457
|
+
const html = render(page);
|
|
3647
4458
|
|
|
3648
|
-
|
|
4459
|
+
expect(typeof html).toBe('string');
|
|
4460
|
+
expect(html.length).toBeGreaterThan(0);
|
|
4461
|
+
expect(html).toContain('<html>');
|
|
4462
|
+
expect(html).toContain('${name}');
|
|
4463
|
+
});
|
|
4464
|
+
|
|
4465
|
+
it('includes proper head elements', () => {
|
|
3649
4466
|
const page = ${name}({});
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
});
|
|
4467
|
+
const html = render(page);
|
|
4468
|
+
|
|
4469
|
+
expect(html).toContain('<title>');
|
|
4470
|
+
expect(html).toContain('<meta');
|
|
4471
|
+
expect(html).toContain('viewport');
|
|
4472
|
+
});
|
|
4473
|
+
|
|
4474
|
+
it('renders with custom props', () => {
|
|
4475
|
+
const props = {
|
|
4476
|
+
params: { id: '123' },
|
|
4477
|
+
query: { search: 'test' }
|
|
4478
|
+
};
|
|
3656
4479
|
|
|
3657
|
-
test('${name} page renders with custom props', () => {
|
|
3658
|
-
const props = {
|
|
3659
|
-
params: { id: '123' },
|
|
3660
|
-
query: { search: 'test' }
|
|
3661
|
-
};
|
|
3662
|
-
|
|
3663
4480
|
const page = ${name}(props);
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
});
|
|
3668
|
-
|
|
4481
|
+
const html = render(page);
|
|
4482
|
+
|
|
4483
|
+
expect(html).toContain('${name}');
|
|
4484
|
+
});
|
|
4485
|
+
});`;
|
|
3669
4486
|
}
|
|
3670
4487
|
function toPascalCase2(str) {
|
|
3671
4488
|
return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (_, c) => c.toUpperCase());
|
|
@@ -3722,7 +4539,7 @@ function generateRESTAPI(apiName, originalName) {
|
|
|
3722
4539
|
/**
|
|
3723
4540
|
* ${className} API Routes
|
|
3724
4541
|
* REST API for ${apiName} resources
|
|
3725
|
-
*
|
|
4542
|
+
*
|
|
3726
4543
|
* Base URL: /api/${apiName}
|
|
3727
4544
|
*/
|
|
3728
4545
|
|
|
@@ -3742,14 +4559,14 @@ const sampleData = [
|
|
|
3742
4559
|
const ${apiName}Schema = {
|
|
3743
4560
|
type: 'object',
|
|
3744
4561
|
properties: {
|
|
3745
|
-
name: {
|
|
3746
|
-
type: 'string',
|
|
4562
|
+
name: {
|
|
4563
|
+
type: 'string',
|
|
3747
4564
|
minLength: 1,
|
|
3748
|
-
maxLength: 100
|
|
4565
|
+
maxLength: 100
|
|
3749
4566
|
},
|
|
3750
|
-
description: {
|
|
4567
|
+
description: {
|
|
3751
4568
|
type: 'string',
|
|
3752
|
-
maxLength: 500
|
|
4569
|
+
maxLength: 500
|
|
3753
4570
|
}
|
|
3754
4571
|
},
|
|
3755
4572
|
required: ['name'],
|
|
@@ -3759,14 +4576,14 @@ const ${apiName}Schema = {
|
|
|
3759
4576
|
const ${apiName}UpdateSchema = {
|
|
3760
4577
|
type: 'object',
|
|
3761
4578
|
properties: {
|
|
3762
|
-
name: {
|
|
3763
|
-
type: 'string',
|
|
4579
|
+
name: {
|
|
4580
|
+
type: 'string',
|
|
3764
4581
|
minLength: 1,
|
|
3765
|
-
maxLength: 100
|
|
4582
|
+
maxLength: 100
|
|
3766
4583
|
},
|
|
3767
|
-
description: {
|
|
4584
|
+
description: {
|
|
3768
4585
|
type: 'string',
|
|
3769
|
-
maxLength: 500
|
|
4586
|
+
maxLength: 500
|
|
3770
4587
|
}
|
|
3771
4588
|
},
|
|
3772
4589
|
additionalProperties: false,
|
|
@@ -3781,21 +4598,21 @@ const ${apiName}UpdateSchema = {
|
|
|
3781
4598
|
*/
|
|
3782
4599
|
${camelCaseApiName}API.get('/', (req, res) => {
|
|
3783
4600
|
const { page = 1, limit = 10, search } = req.query;
|
|
3784
|
-
|
|
4601
|
+
|
|
3785
4602
|
let data = [...sampleData];
|
|
3786
|
-
|
|
4603
|
+
|
|
3787
4604
|
// Apply search filter
|
|
3788
4605
|
if (search) {
|
|
3789
|
-
data = data.filter(item =>
|
|
4606
|
+
data = data.filter(item =>
|
|
3790
4607
|
item.name.toLowerCase().includes(search.toLowerCase())
|
|
3791
4608
|
);
|
|
3792
4609
|
}
|
|
3793
|
-
|
|
4610
|
+
|
|
3794
4611
|
// Apply pagination
|
|
3795
4612
|
const startIndex = (page - 1) * limit;
|
|
3796
4613
|
const endIndex = startIndex + parseInt(limit);
|
|
3797
4614
|
const paginatedData = data.slice(startIndex, endIndex);
|
|
3798
|
-
|
|
4615
|
+
|
|
3799
4616
|
return {
|
|
3800
4617
|
data: paginatedData,
|
|
3801
4618
|
pagination: {
|
|
@@ -3814,14 +4631,14 @@ ${camelCaseApiName}API.get('/', (req, res) => {
|
|
|
3814
4631
|
${camelCaseApiName}API.get('/:id', (req, res) => {
|
|
3815
4632
|
const { id } = req.params;
|
|
3816
4633
|
const item = sampleData.find(item => item.id === id);
|
|
3817
|
-
|
|
4634
|
+
|
|
3818
4635
|
if (!item) {
|
|
3819
4636
|
return res.status(404).json({
|
|
3820
4637
|
_error: '${className} not found',
|
|
3821
4638
|
code: 'NOT_FOUND'
|
|
3822
4639
|
});
|
|
3823
4640
|
}
|
|
3824
|
-
|
|
4641
|
+
|
|
3825
4642
|
return { data: item };
|
|
3826
4643
|
});
|
|
3827
4644
|
|
|
@@ -3829,11 +4646,11 @@ ${camelCaseApiName}API.get('/:id', (req, res) => {
|
|
|
3829
4646
|
* POST /${apiName}
|
|
3830
4647
|
* Create a new ${apiName} item
|
|
3831
4648
|
*/
|
|
3832
|
-
${camelCaseApiName}API.post('/',
|
|
4649
|
+
${camelCaseApiName}API.post('/',
|
|
3833
4650
|
withValidation(${apiName}Schema),
|
|
3834
4651
|
(req, res) => {
|
|
3835
4652
|
const { name, description } = req.body;
|
|
3836
|
-
|
|
4653
|
+
|
|
3837
4654
|
const newItem = {
|
|
3838
4655
|
id: String(Date.now()),
|
|
3839
4656
|
name,
|
|
@@ -3841,9 +4658,9 @@ ${camelCaseApiName}API.post('/',
|
|
|
3841
4658
|
createdAt: new Date().toISOString(),
|
|
3842
4659
|
updatedAt: new Date().toISOString()
|
|
3843
4660
|
};
|
|
3844
|
-
|
|
4661
|
+
|
|
3845
4662
|
sampleData.push(newItem);
|
|
3846
|
-
|
|
4663
|
+
|
|
3847
4664
|
return res.status(201).json({
|
|
3848
4665
|
data: newItem,
|
|
3849
4666
|
message: '${className} created successfully'
|
|
@@ -3860,22 +4677,22 @@ ${camelCaseApiName}API.put('/:id',
|
|
|
3860
4677
|
(req, res) => {
|
|
3861
4678
|
const { id } = req.params;
|
|
3862
4679
|
const itemIndex = sampleData.findIndex(item => item.id === id);
|
|
3863
|
-
|
|
4680
|
+
|
|
3864
4681
|
if (itemIndex === -1) {
|
|
3865
4682
|
return res.status(404).json({
|
|
3866
4683
|
_error: '${className} not found',
|
|
3867
4684
|
code: 'NOT_FOUND'
|
|
3868
4685
|
});
|
|
3869
4686
|
}
|
|
3870
|
-
|
|
4687
|
+
|
|
3871
4688
|
const updatedItem = {
|
|
3872
4689
|
...sampleData[itemIndex],
|
|
3873
4690
|
...req.body,
|
|
3874
4691
|
updatedAt: new Date().toISOString()
|
|
3875
4692
|
};
|
|
3876
|
-
|
|
4693
|
+
|
|
3877
4694
|
sampleData[itemIndex] = updatedItem;
|
|
3878
|
-
|
|
4695
|
+
|
|
3879
4696
|
return {
|
|
3880
4697
|
data: updatedItem,
|
|
3881
4698
|
message: '${className} updated successfully'
|
|
@@ -3890,16 +4707,16 @@ ${camelCaseApiName}API.put('/:id',
|
|
|
3890
4707
|
${camelCaseApiName}API.delete('/:id', (req, res) => {
|
|
3891
4708
|
const { id } = req.params;
|
|
3892
4709
|
const itemIndex = sampleData.findIndex(item => item.id === id);
|
|
3893
|
-
|
|
4710
|
+
|
|
3894
4711
|
if (itemIndex === -1) {
|
|
3895
4712
|
return res.status(404).json({
|
|
3896
4713
|
_error: '${className} not found',
|
|
3897
4714
|
code: 'NOT_FOUND'
|
|
3898
4715
|
});
|
|
3899
4716
|
}
|
|
3900
|
-
|
|
4717
|
+
|
|
3901
4718
|
const deletedItem = sampleData.splice(itemIndex, 1)[0];
|
|
3902
|
-
|
|
4719
|
+
|
|
3903
4720
|
return {
|
|
3904
4721
|
data: deletedItem,
|
|
3905
4722
|
message: '${className} deleted successfully'
|
|
@@ -3920,7 +4737,7 @@ export default ${camelCaseApiName}API;
|
|
|
3920
4737
|
// Usage example:
|
|
3921
4738
|
// import express from 'express';
|
|
3922
4739
|
// import ${camelCaseApiName}API from './api/${apiName}.js';
|
|
3923
|
-
//
|
|
4740
|
+
//
|
|
3924
4741
|
// const app = express();
|
|
3925
4742
|
// app.use(express.json());
|
|
3926
4743
|
// app.use('/api', ${camelCaseApiName}API.toExpress());
|
|
@@ -3941,7 +4758,7 @@ function generateRPCAPI(apiName, originalName) {
|
|
|
3941
4758
|
/**
|
|
3942
4759
|
* ${className} RPC API
|
|
3943
4760
|
* Remote Procedure Call API for ${apiName}
|
|
3944
|
-
*
|
|
4761
|
+
*
|
|
3945
4762
|
* Base URL: /rpc/${apiName}
|
|
3946
4763
|
*/
|
|
3947
4764
|
|
|
@@ -3964,10 +4781,10 @@ sampleData.set('2', { id: '2', name: 'Sample ${className} 2', createdAt: new Dat
|
|
|
3964
4781
|
${camelCaseApiName}RPC.post('/list', (req, res) => {
|
|
3965
4782
|
const { params = {} } = req.body;
|
|
3966
4783
|
const { limit = 10, offset = 0 } = params;
|
|
3967
|
-
|
|
4784
|
+
|
|
3968
4785
|
const items = Array.from(sampleData.values())
|
|
3969
4786
|
.slice(offset, offset + limit);
|
|
3970
|
-
|
|
4787
|
+
|
|
3971
4788
|
return {
|
|
3972
4789
|
jsonrpc: '2.0',
|
|
3973
4790
|
result: {
|
|
@@ -3982,7 +4799,7 @@ ${camelCaseApiName}RPC.post('/list', (req, res) => {
|
|
|
3982
4799
|
* RPC Method: ${apiName}.get
|
|
3983
4800
|
* Get a specific ${apiName} item
|
|
3984
4801
|
*/
|
|
3985
|
-
${camelCaseApiName}RPC.post('/get',
|
|
4802
|
+
${camelCaseApiName}RPC.post('/get',
|
|
3986
4803
|
withValidation({
|
|
3987
4804
|
type: 'object',
|
|
3988
4805
|
properties: {
|
|
@@ -3999,7 +4816,7 @@ ${camelCaseApiName}RPC.post('/get',
|
|
|
3999
4816
|
(req, res) => {
|
|
4000
4817
|
const { params } = req.body;
|
|
4001
4818
|
const item = sampleData.get(params.id);
|
|
4002
|
-
|
|
4819
|
+
|
|
4003
4820
|
if (!item) {
|
|
4004
4821
|
return {
|
|
4005
4822
|
jsonrpc: '2.0',
|
|
@@ -4010,7 +4827,7 @@ ${camelCaseApiName}RPC.post('/get',
|
|
|
4010
4827
|
id: req.body.id
|
|
4011
4828
|
};
|
|
4012
4829
|
}
|
|
4013
|
-
|
|
4830
|
+
|
|
4014
4831
|
return {
|
|
4015
4832
|
jsonrpc: '2.0',
|
|
4016
4833
|
result: item,
|
|
@@ -4041,16 +4858,16 @@ ${camelCaseApiName}RPC.post('/create',
|
|
|
4041
4858
|
(req, res) => {
|
|
4042
4859
|
const { params } = req.body;
|
|
4043
4860
|
const id = String(Date.now());
|
|
4044
|
-
|
|
4861
|
+
|
|
4045
4862
|
const newItem = {
|
|
4046
4863
|
id,
|
|
4047
4864
|
...params,
|
|
4048
4865
|
createdAt: new Date(),
|
|
4049
4866
|
updatedAt: new Date()
|
|
4050
4867
|
};
|
|
4051
|
-
|
|
4868
|
+
|
|
4052
4869
|
sampleData.set(id, newItem);
|
|
4053
|
-
|
|
4870
|
+
|
|
4054
4871
|
return {
|
|
4055
4872
|
jsonrpc: '2.0',
|
|
4056
4873
|
result: newItem,
|
|
@@ -4082,7 +4899,7 @@ ${camelCaseApiName}RPC.post('/update',
|
|
|
4082
4899
|
(req, res) => {
|
|
4083
4900
|
const { params } = req.body;
|
|
4084
4901
|
const existing = sampleData.get(params.id);
|
|
4085
|
-
|
|
4902
|
+
|
|
4086
4903
|
if (!existing) {
|
|
4087
4904
|
return {
|
|
4088
4905
|
jsonrpc: '2.0',
|
|
@@ -4093,15 +4910,15 @@ ${camelCaseApiName}RPC.post('/update',
|
|
|
4093
4910
|
id: req.body.id
|
|
4094
4911
|
};
|
|
4095
4912
|
}
|
|
4096
|
-
|
|
4913
|
+
|
|
4097
4914
|
const updated = {
|
|
4098
4915
|
...existing,
|
|
4099
4916
|
...params,
|
|
4100
4917
|
updatedAt: new Date()
|
|
4101
4918
|
};
|
|
4102
|
-
|
|
4919
|
+
|
|
4103
4920
|
sampleData.set(params.id, updated);
|
|
4104
|
-
|
|
4921
|
+
|
|
4105
4922
|
return {
|
|
4106
4923
|
jsonrpc: '2.0',
|
|
4107
4924
|
result: updated,
|
|
@@ -4131,7 +4948,7 @@ ${camelCaseApiName}RPC.post('/delete',
|
|
|
4131
4948
|
(req, res) => {
|
|
4132
4949
|
const { params } = req.body;
|
|
4133
4950
|
const item = sampleData.get(params.id);
|
|
4134
|
-
|
|
4951
|
+
|
|
4135
4952
|
if (!item) {
|
|
4136
4953
|
return {
|
|
4137
4954
|
jsonrpc: '2.0',
|
|
@@ -4142,9 +4959,9 @@ ${camelCaseApiName}RPC.post('/delete',
|
|
|
4142
4959
|
id: req.body.id
|
|
4143
4960
|
};
|
|
4144
4961
|
}
|
|
4145
|
-
|
|
4962
|
+
|
|
4146
4963
|
sampleData.delete(params.id);
|
|
4147
|
-
|
|
4964
|
+
|
|
4148
4965
|
return {
|
|
4149
4966
|
jsonrpc: '2.0',
|
|
4150
4967
|
result: { success: true, deleted: item },
|
|
@@ -4158,17 +4975,17 @@ export default ${camelCaseApiName}RPC;
|
|
|
4158
4975
|
}
|
|
4159
4976
|
function generateTestContent3(apiName, originalName) {
|
|
4160
4977
|
const className = toPascalCase3(originalName);
|
|
4161
|
-
return `import {
|
|
4162
|
-
import assert from 'node:assert';
|
|
4978
|
+
return `import { describe, it, expect } from 'vitest';
|
|
4163
4979
|
import ${apiName}API from './${apiName}.js';
|
|
4164
4980
|
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4981
|
+
describe('${className} API', () => {
|
|
4982
|
+
it('should be defined', () => {
|
|
4983
|
+
expect(typeof ${apiName}API).toBe('object');
|
|
4984
|
+
expect(typeof ${apiName}API.get).toBe('function');
|
|
4985
|
+
expect(typeof ${apiName}API.post).toBe('function');
|
|
4169
4986
|
});
|
|
4170
4987
|
|
|
4171
|
-
|
|
4988
|
+
it('should handle GET requests', async () => {
|
|
4172
4989
|
const mockReq = {
|
|
4173
4990
|
query: {}
|
|
4174
4991
|
};
|
|
@@ -4176,15 +4993,15 @@ test('${className} API should handle GET requests', async () => {
|
|
|
4176
4993
|
status: (code) => mockRes,
|
|
4177
4994
|
json: (data) => data
|
|
4178
4995
|
};
|
|
4179
|
-
|
|
4996
|
+
|
|
4180
4997
|
// This is a basic test structure
|
|
4181
4998
|
// In a real test, you'd use a testing framework like supertest
|
|
4182
|
-
|
|
4999
|
+
expect(true).toBe(true); // Placeholder
|
|
4183
5000
|
});
|
|
4184
5001
|
|
|
4185
5002
|
// Add more specific tests for your API endpoints
|
|
4186
5003
|
// Example:
|
|
4187
|
-
//
|
|
5004
|
+
// it('POST /${apiName} should create new item', async () => {
|
|
4188
5005
|
// // Test implementation
|
|
4189
5006
|
// });
|
|
4190
5007
|
//
|
|
@@ -4316,7 +5133,7 @@ import { Command as Command3 } from "commander";
|
|
|
4316
5133
|
import ora3 from "ora";
|
|
4317
5134
|
import picocolors3 from "picocolors";
|
|
4318
5135
|
import { execSync as execSync2 } from "child_process";
|
|
4319
|
-
import { existsSync as existsSync6, readFileSync as
|
|
5136
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
4320
5137
|
import { join as join6 } from "path";
|
|
4321
5138
|
var buildCommand = new Command3("build").description("Build the project for production").option("-w, --watch", "watch for changes").option("--analyze", "analyze bundle size").option("--no-minify", "disable minification").option("--no-optimize", "disable optimizations").action(async (options) => {
|
|
4322
5139
|
console.log(picocolors3.cyan("\u{1F3D7}\uFE0F Building Coherent.js project..."));
|
|
@@ -4328,7 +5145,7 @@ var buildCommand = new Command3("build").description("Build the project for prod
|
|
|
4328
5145
|
}
|
|
4329
5146
|
let packageJson;
|
|
4330
5147
|
try {
|
|
4331
|
-
packageJson = JSON.parse(
|
|
5148
|
+
packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
4332
5149
|
} catch {
|
|
4333
5150
|
console.error(picocolors3.red("\u274C Failed to read package.json"));
|
|
4334
5151
|
process.exit(1);
|
|
@@ -4422,8 +5239,8 @@ var buildCommand = new Command3("build").description("Build the project for prod
|
|
|
4422
5239
|
import { Command as Command4 } from "commander";
|
|
4423
5240
|
import ora4 from "ora";
|
|
4424
5241
|
import picocolors4 from "picocolors";
|
|
4425
|
-
import { spawn } from "child_process";
|
|
4426
|
-
import { existsSync as existsSync7, readFileSync as
|
|
5242
|
+
import { spawn as spawn2 } from "child_process";
|
|
5243
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
4427
5244
|
import { join as join7 } from "path";
|
|
4428
5245
|
var devCommand = new Command4("dev").description("Start development server with hot reload").option("-p, --port <port>", "port number", "3000").option("-h, --host <host>", "host address", "localhost").option("--open", "open browser automatically").option("--no-hmr", "disable hot module replacement").action(async (options) => {
|
|
4429
5246
|
console.log(picocolors4.cyan("\u{1F680} Starting Coherent.js development server..."));
|
|
@@ -4435,7 +5252,7 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4435
5252
|
}
|
|
4436
5253
|
let packageJson;
|
|
4437
5254
|
try {
|
|
4438
|
-
packageJson = JSON.parse(
|
|
5255
|
+
packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
|
|
4439
5256
|
} catch {
|
|
4440
5257
|
console.error(picocolors4.red("\u274C Failed to read package.json"));
|
|
4441
5258
|
process.exit(1);
|
|
@@ -4445,7 +5262,7 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4445
5262
|
let devProcess;
|
|
4446
5263
|
if (packageJson.scripts && packageJson.scripts.dev) {
|
|
4447
5264
|
spinner.text = "Running dev script...";
|
|
4448
|
-
devProcess =
|
|
5265
|
+
devProcess = spawn2("npm", ["run", "dev"], {
|
|
4449
5266
|
stdio: "inherit",
|
|
4450
5267
|
cwd: process.cwd(),
|
|
4451
5268
|
shell: true,
|
|
@@ -4458,19 +5275,19 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4458
5275
|
} else {
|
|
4459
5276
|
spinner.text = "Starting default dev server...";
|
|
4460
5277
|
if (existsSync7("vite.config.js") || existsSync7("vite.config.ts")) {
|
|
4461
|
-
devProcess =
|
|
5278
|
+
devProcess = spawn2("npx", ["vite", "--port", options.port, "--host", options.host], {
|
|
4462
5279
|
stdio: "inherit",
|
|
4463
5280
|
cwd: process.cwd(),
|
|
4464
5281
|
shell: true
|
|
4465
5282
|
});
|
|
4466
5283
|
} else if (existsSync7("webpack.config.js")) {
|
|
4467
|
-
devProcess =
|
|
5284
|
+
devProcess = spawn2("npx", ["webpack", "serve", "--port", options.port, "--host", options.host], {
|
|
4468
5285
|
stdio: "inherit",
|
|
4469
5286
|
cwd: process.cwd(),
|
|
4470
5287
|
shell: true
|
|
4471
5288
|
});
|
|
4472
5289
|
} else if (packageJson.type === "module" || existsSync7("src/index.js")) {
|
|
4473
|
-
devProcess =
|
|
5290
|
+
devProcess = spawn2("npx", ["nodemon", "src/index.js"], {
|
|
4474
5291
|
stdio: "inherit",
|
|
4475
5292
|
cwd: process.cwd(),
|
|
4476
5293
|
shell: true,
|
|
@@ -4535,11 +5352,12 @@ import { Command as Command5 } from "commander";
|
|
|
4535
5352
|
import prompts3 from "prompts";
|
|
4536
5353
|
import ora5 from "ora";
|
|
4537
5354
|
import picocolors5 from "picocolors";
|
|
4538
|
-
import {
|
|
5355
|
+
import process2, { env as env2 } from "node:process";
|
|
5356
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
4539
5357
|
import { resolve as resolve5 } from "path";
|
|
4540
5358
|
|
|
4541
5359
|
// src/analyzers/component-analyzer.js
|
|
4542
|
-
import { readFileSync as
|
|
5360
|
+
import { readFileSync as readFileSync5, existsSync as existsSync8 } from "fs";
|
|
4543
5361
|
import { resolve as resolve3 } from "path";
|
|
4544
5362
|
|
|
4545
5363
|
// ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
@@ -4753,7 +5571,7 @@ function expand_(str, isTop) {
|
|
|
4753
5571
|
return expansions;
|
|
4754
5572
|
}
|
|
4755
5573
|
|
|
4756
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
5574
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/assert-valid-pattern.js
|
|
4757
5575
|
var MAX_PATTERN_LENGTH = 1024 * 64;
|
|
4758
5576
|
var assertValidPattern = (pattern) => {
|
|
4759
5577
|
if (typeof pattern !== "string") {
|
|
@@ -4764,7 +5582,7 @@ var assertValidPattern = (pattern) => {
|
|
|
4764
5582
|
}
|
|
4765
5583
|
};
|
|
4766
5584
|
|
|
4767
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
5585
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/brace-expressions.js
|
|
4768
5586
|
var posixClasses = {
|
|
4769
5587
|
"[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
|
|
4770
5588
|
"[:alpha:]": ["\\p{L}\\p{Nl}", true],
|
|
@@ -4873,12 +5691,15 @@ var parseClass = (glob2, position) => {
|
|
|
4873
5691
|
return [comb, uflag, endPos - pos, true];
|
|
4874
5692
|
};
|
|
4875
5693
|
|
|
4876
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
4877
|
-
var unescape = (s, { windowsPathsNoEscape = false } = {}) => {
|
|
4878
|
-
|
|
5694
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/unescape.js
|
|
5695
|
+
var unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true } = {}) => {
|
|
5696
|
+
if (magicalBraces) {
|
|
5697
|
+
return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
|
|
5698
|
+
}
|
|
5699
|
+
return windowsPathsNoEscape ? s.replace(/\[([^\/\\{}])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\{}])\]/g, "$1$2").replace(/\\([^\/{}])/g, "$1");
|
|
4879
5700
|
};
|
|
4880
5701
|
|
|
4881
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
5702
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/ast.js
|
|
4882
5703
|
var types = /* @__PURE__ */ new Set(["!", "?", "+", "*", "@"]);
|
|
4883
5704
|
var isExtglobType = (c) => types.has(c);
|
|
4884
5705
|
var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))";
|
|
@@ -5229,7 +6050,7 @@ var AST = class _AST {
|
|
|
5229
6050
|
if (this.#root === this)
|
|
5230
6051
|
this.#fillNegs();
|
|
5231
6052
|
if (!this.type) {
|
|
5232
|
-
const noEmpty = this.isStart() && this.isEnd();
|
|
6053
|
+
const noEmpty = this.isStart() && this.isEnd() && !this.#parts.some((s) => typeof s !== "string");
|
|
5233
6054
|
const src = this.#parts.map((p) => {
|
|
5234
6055
|
const [re, _, hasMagic2, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
|
|
5235
6056
|
this.#hasMagic = this.#hasMagic || hasMagic2;
|
|
@@ -5339,10 +6160,7 @@ var AST = class _AST {
|
|
|
5339
6160
|
}
|
|
5340
6161
|
}
|
|
5341
6162
|
if (c === "*") {
|
|
5342
|
-
|
|
5343
|
-
re += starNoEmpty;
|
|
5344
|
-
else
|
|
5345
|
-
re += star;
|
|
6163
|
+
re += noEmpty && glob2 === "*" ? starNoEmpty : star;
|
|
5346
6164
|
hasMagic2 = true;
|
|
5347
6165
|
continue;
|
|
5348
6166
|
}
|
|
@@ -5357,12 +6175,15 @@ var AST = class _AST {
|
|
|
5357
6175
|
}
|
|
5358
6176
|
};
|
|
5359
6177
|
|
|
5360
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
5361
|
-
var escape = (s, { windowsPathsNoEscape = false } = {}) => {
|
|
6178
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/escape.js
|
|
6179
|
+
var escape = (s, { windowsPathsNoEscape = false, magicalBraces = false } = {}) => {
|
|
6180
|
+
if (magicalBraces) {
|
|
6181
|
+
return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, "[$&]") : s.replace(/[?*()[\]\\{}]/g, "\\$&");
|
|
6182
|
+
}
|
|
5362
6183
|
return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, "[$&]") : s.replace(/[?*()[\]\\]/g, "\\$&");
|
|
5363
6184
|
};
|
|
5364
6185
|
|
|
5365
|
-
// ../../node_modules/.pnpm/minimatch@10.
|
|
6186
|
+
// ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/index.js
|
|
5366
6187
|
var minimatch = (p, pattern, options = {}) => {
|
|
5367
6188
|
assertValidPattern(pattern);
|
|
5368
6189
|
if (!options.nocomment && pattern.charAt(0) === "#") {
|
|
@@ -5427,7 +6248,7 @@ var path = {
|
|
|
5427
6248
|
};
|
|
5428
6249
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
5429
6250
|
minimatch.sep = sep;
|
|
5430
|
-
var GLOBSTAR = Symbol("globstar **");
|
|
6251
|
+
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
5431
6252
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
5432
6253
|
var qmark2 = "[^/]";
|
|
5433
6254
|
var star2 = qmark2 + "*?";
|
|
@@ -5999,16 +6820,27 @@ var Minimatch = class {
|
|
|
5999
6820
|
pp[i] = twoStar;
|
|
6000
6821
|
}
|
|
6001
6822
|
} else if (next === void 0) {
|
|
6002
|
-
pp[i - 1] = prev + "(
|
|
6823
|
+
pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + ")?";
|
|
6003
6824
|
} else if (next !== GLOBSTAR) {
|
|
6004
6825
|
pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
|
|
6005
6826
|
pp[i + 1] = GLOBSTAR;
|
|
6006
6827
|
}
|
|
6007
6828
|
});
|
|
6008
|
-
|
|
6829
|
+
const filtered = pp.filter((p) => p !== GLOBSTAR);
|
|
6830
|
+
if (this.partial && filtered.length >= 1) {
|
|
6831
|
+
const prefixes = [];
|
|
6832
|
+
for (let i = 1; i <= filtered.length; i++) {
|
|
6833
|
+
prefixes.push(filtered.slice(0, i).join("/"));
|
|
6834
|
+
}
|
|
6835
|
+
return "(?:" + prefixes.join("|") + ")";
|
|
6836
|
+
}
|
|
6837
|
+
return filtered.join("/");
|
|
6009
6838
|
}).join("|");
|
|
6010
6839
|
const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
|
|
6011
6840
|
re = "^" + open + re + close + "$";
|
|
6841
|
+
if (this.partial) {
|
|
6842
|
+
re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
|
|
6843
|
+
}
|
|
6012
6844
|
if (this.negate)
|
|
6013
6845
|
re = "^(?!" + re + ").+$";
|
|
6014
6846
|
try {
|
|
@@ -6080,10 +6912,10 @@ minimatch.Minimatch = Minimatch;
|
|
|
6080
6912
|
minimatch.escape = escape;
|
|
6081
6913
|
minimatch.unescape = unescape;
|
|
6082
6914
|
|
|
6083
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
6915
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/glob.js
|
|
6084
6916
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
6085
6917
|
|
|
6086
|
-
// ../../node_modules/.pnpm/lru-cache@11.2.
|
|
6918
|
+
// ../../node_modules/.pnpm/lru-cache@11.2.2/node_modules/lru-cache/dist/esm/index.js
|
|
6087
6919
|
var defaultPerf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
|
|
6088
6920
|
var warned = /* @__PURE__ */ new Set();
|
|
6089
6921
|
var PROCESS = typeof process === "object" && !!process ? process : {};
|
|
@@ -6127,7 +6959,6 @@ if (typeof AC === "undefined") {
|
|
|
6127
6959
|
};
|
|
6128
6960
|
}
|
|
6129
6961
|
var shouldWarn = (code) => !warned.has(code);
|
|
6130
|
-
var TYPE = Symbol("type");
|
|
6131
6962
|
var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
6132
6963
|
var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
|
|
6133
6964
|
var ZeroArray = class extends Array {
|
|
@@ -7129,7 +7960,8 @@ var LRUCache = class _LRUCache {
|
|
|
7129
7960
|
return fetchFail(ac.signal.reason);
|
|
7130
7961
|
}
|
|
7131
7962
|
const bf2 = p;
|
|
7132
|
-
|
|
7963
|
+
const vl = this.#valList[index];
|
|
7964
|
+
if (vl === p || ignoreAbort && updateCache && vl === void 0) {
|
|
7133
7965
|
if (v2 === void 0) {
|
|
7134
7966
|
if (bf2.__staleWhileFetching !== void 0) {
|
|
7135
7967
|
this.#valList[index] = bf2.__staleWhileFetching;
|
|
@@ -7483,7 +8315,7 @@ var LRUCache = class _LRUCache {
|
|
|
7483
8315
|
}
|
|
7484
8316
|
};
|
|
7485
8317
|
|
|
7486
|
-
// ../../node_modules/.pnpm/path-scurry@2.0.
|
|
8318
|
+
// ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
|
|
7487
8319
|
import { posix, win32 } from "node:path";
|
|
7488
8320
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7489
8321
|
import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "fs";
|
|
@@ -7502,37 +8334,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
|
|
|
7502
8334
|
var isReadable = (s) => !!s && typeof s === "object" && s instanceof EventEmitter && typeof s.pipe === "function" && // node core Writable streams have a pipe() method, but it throws
|
|
7503
8335
|
s.pipe !== Stream.Writable.prototype.pipe;
|
|
7504
8336
|
var isWritable = (s) => !!s && typeof s === "object" && s instanceof EventEmitter && typeof s.write === "function" && typeof s.end === "function";
|
|
7505
|
-
var EOF = Symbol("EOF");
|
|
7506
|
-
var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
|
|
7507
|
-
var EMITTED_END = Symbol("emittedEnd");
|
|
7508
|
-
var EMITTING_END = Symbol("emittingEnd");
|
|
7509
|
-
var EMITTED_ERROR = Symbol("emittedError");
|
|
7510
|
-
var CLOSED = Symbol("closed");
|
|
7511
|
-
var READ = Symbol("read");
|
|
7512
|
-
var FLUSH = Symbol("flush");
|
|
7513
|
-
var FLUSHCHUNK = Symbol("flushChunk");
|
|
7514
|
-
var ENCODING = Symbol("encoding");
|
|
7515
|
-
var DECODER = Symbol("decoder");
|
|
7516
|
-
var FLOWING = Symbol("flowing");
|
|
7517
|
-
var PAUSED = Symbol("paused");
|
|
7518
|
-
var RESUME = Symbol("resume");
|
|
7519
|
-
var BUFFER = Symbol("buffer");
|
|
7520
|
-
var PIPES = Symbol("pipes");
|
|
7521
|
-
var BUFFERLENGTH = Symbol("bufferLength");
|
|
7522
|
-
var BUFFERPUSH = Symbol("bufferPush");
|
|
7523
|
-
var BUFFERSHIFT = Symbol("bufferShift");
|
|
7524
|
-
var OBJECTMODE = Symbol("objectMode");
|
|
7525
|
-
var DESTROYED = Symbol("destroyed");
|
|
7526
|
-
var ERROR = Symbol("error");
|
|
7527
|
-
var EMITDATA = Symbol("emitData");
|
|
7528
|
-
var EMITEND = Symbol("emitEnd");
|
|
7529
|
-
var EMITEND2 = Symbol("emitEnd2");
|
|
7530
|
-
var ASYNC = Symbol("async");
|
|
7531
|
-
var ABORT = Symbol("abort");
|
|
7532
|
-
var ABORTED = Symbol("aborted");
|
|
7533
|
-
var SIGNAL = Symbol("signal");
|
|
7534
|
-
var DATALISTENERS = Symbol("dataListeners");
|
|
7535
|
-
var DISCARDED = Symbol("discarded");
|
|
8337
|
+
var EOF = /* @__PURE__ */ Symbol("EOF");
|
|
8338
|
+
var MAYBE_EMIT_END = /* @__PURE__ */ Symbol("maybeEmitEnd");
|
|
8339
|
+
var EMITTED_END = /* @__PURE__ */ Symbol("emittedEnd");
|
|
8340
|
+
var EMITTING_END = /* @__PURE__ */ Symbol("emittingEnd");
|
|
8341
|
+
var EMITTED_ERROR = /* @__PURE__ */ Symbol("emittedError");
|
|
8342
|
+
var CLOSED = /* @__PURE__ */ Symbol("closed");
|
|
8343
|
+
var READ = /* @__PURE__ */ Symbol("read");
|
|
8344
|
+
var FLUSH = /* @__PURE__ */ Symbol("flush");
|
|
8345
|
+
var FLUSHCHUNK = /* @__PURE__ */ Symbol("flushChunk");
|
|
8346
|
+
var ENCODING = /* @__PURE__ */ Symbol("encoding");
|
|
8347
|
+
var DECODER = /* @__PURE__ */ Symbol("decoder");
|
|
8348
|
+
var FLOWING = /* @__PURE__ */ Symbol("flowing");
|
|
8349
|
+
var PAUSED = /* @__PURE__ */ Symbol("paused");
|
|
8350
|
+
var RESUME = /* @__PURE__ */ Symbol("resume");
|
|
8351
|
+
var BUFFER = /* @__PURE__ */ Symbol("buffer");
|
|
8352
|
+
var PIPES = /* @__PURE__ */ Symbol("pipes");
|
|
8353
|
+
var BUFFERLENGTH = /* @__PURE__ */ Symbol("bufferLength");
|
|
8354
|
+
var BUFFERPUSH = /* @__PURE__ */ Symbol("bufferPush");
|
|
8355
|
+
var BUFFERSHIFT = /* @__PURE__ */ Symbol("bufferShift");
|
|
8356
|
+
var OBJECTMODE = /* @__PURE__ */ Symbol("objectMode");
|
|
8357
|
+
var DESTROYED = /* @__PURE__ */ Symbol("destroyed");
|
|
8358
|
+
var ERROR = /* @__PURE__ */ Symbol("error");
|
|
8359
|
+
var EMITDATA = /* @__PURE__ */ Symbol("emitData");
|
|
8360
|
+
var EMITEND = /* @__PURE__ */ Symbol("emitEnd");
|
|
8361
|
+
var EMITEND2 = /* @__PURE__ */ Symbol("emitEnd2");
|
|
8362
|
+
var ASYNC = /* @__PURE__ */ Symbol("async");
|
|
8363
|
+
var ABORT = /* @__PURE__ */ Symbol("abort");
|
|
8364
|
+
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
8365
|
+
var SIGNAL = /* @__PURE__ */ Symbol("signal");
|
|
8366
|
+
var DATALISTENERS = /* @__PURE__ */ Symbol("dataListeners");
|
|
8367
|
+
var DISCARDED = /* @__PURE__ */ Symbol("discarded");
|
|
7536
8368
|
var defer = (fn) => Promise.resolve().then(fn);
|
|
7537
8369
|
var nodefer = (fn) => fn();
|
|
7538
8370
|
var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
|
|
@@ -8368,7 +9200,7 @@ var Minipass = class extends EventEmitter {
|
|
|
8368
9200
|
}
|
|
8369
9201
|
};
|
|
8370
9202
|
|
|
8371
|
-
// ../../node_modules/.pnpm/path-scurry@2.0.
|
|
9203
|
+
// ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
|
|
8372
9204
|
var realpathSync = rps.native;
|
|
8373
9205
|
var defaultFS = {
|
|
8374
9206
|
lstatSync,
|
|
@@ -8413,7 +9245,7 @@ var ENOREALPATH = 512;
|
|
|
8413
9245
|
var ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
|
|
8414
9246
|
var TYPEMASK = 1023;
|
|
8415
9247
|
var entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
|
|
8416
|
-
var normalizeCache =
|
|
9248
|
+
var normalizeCache = new LRUCache({ max: 2 ** 12 });
|
|
8417
9249
|
var normalize = (s) => {
|
|
8418
9250
|
const c = normalizeCache.get(s);
|
|
8419
9251
|
if (c)
|
|
@@ -8422,7 +9254,7 @@ var normalize = (s) => {
|
|
|
8422
9254
|
normalizeCache.set(s, n);
|
|
8423
9255
|
return n;
|
|
8424
9256
|
};
|
|
8425
|
-
var normalizeNocaseCache =
|
|
9257
|
+
var normalizeNocaseCache = new LRUCache({ max: 2 ** 12 });
|
|
8426
9258
|
var normalizeNocase = (s) => {
|
|
8427
9259
|
const c = normalizeNocaseCache.get(s);
|
|
8428
9260
|
if (c)
|
|
@@ -8445,7 +9277,7 @@ var ChildrenCache = class extends LRUCache {
|
|
|
8445
9277
|
});
|
|
8446
9278
|
}
|
|
8447
9279
|
};
|
|
8448
|
-
var setAsCwd = Symbol("PathScurry setAsCwd");
|
|
9280
|
+
var setAsCwd = /* @__PURE__ */ Symbol("PathScurry setAsCwd");
|
|
8449
9281
|
var PathBase = class {
|
|
8450
9282
|
/**
|
|
8451
9283
|
* the basename of this path
|
|
@@ -8579,6 +9411,7 @@ var PathBase = class {
|
|
|
8579
9411
|
get parentPath() {
|
|
8580
9412
|
return (this.parent || this).fullpath();
|
|
8581
9413
|
}
|
|
9414
|
+
/* c8 ignore start */
|
|
8582
9415
|
/**
|
|
8583
9416
|
* Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
|
|
8584
9417
|
* this property refers to the *parent* path, not the path object itself.
|
|
@@ -8588,6 +9421,7 @@ var PathBase = class {
|
|
|
8588
9421
|
get path() {
|
|
8589
9422
|
return this.parentPath;
|
|
8590
9423
|
}
|
|
9424
|
+
/* c8 ignore stop */
|
|
8591
9425
|
/**
|
|
8592
9426
|
* Do not create new Path objects directly. They should always be accessed
|
|
8593
9427
|
* via the PathScurry class or other methods on the Path class.
|
|
@@ -9910,7 +10744,7 @@ var PathScurryBase = class {
|
|
|
9910
10744
|
const dirs = /* @__PURE__ */ new Set();
|
|
9911
10745
|
const queue = [entry];
|
|
9912
10746
|
let processing = 0;
|
|
9913
|
-
const
|
|
10747
|
+
const process3 = () => {
|
|
9914
10748
|
let paused = false;
|
|
9915
10749
|
while (!paused) {
|
|
9916
10750
|
const dir = queue.shift();
|
|
@@ -9951,9 +10785,9 @@ var PathScurryBase = class {
|
|
|
9951
10785
|
}
|
|
9952
10786
|
}
|
|
9953
10787
|
if (paused && !results.flowing) {
|
|
9954
|
-
results.once("drain",
|
|
10788
|
+
results.once("drain", process3);
|
|
9955
10789
|
} else if (!sync2) {
|
|
9956
|
-
|
|
10790
|
+
process3();
|
|
9957
10791
|
}
|
|
9958
10792
|
};
|
|
9959
10793
|
let sync2 = true;
|
|
@@ -9961,7 +10795,7 @@ var PathScurryBase = class {
|
|
|
9961
10795
|
sync2 = false;
|
|
9962
10796
|
}
|
|
9963
10797
|
};
|
|
9964
|
-
|
|
10798
|
+
process3();
|
|
9965
10799
|
return results;
|
|
9966
10800
|
}
|
|
9967
10801
|
streamSync(entry = this.cwd, opts = {}) {
|
|
@@ -9979,7 +10813,7 @@ var PathScurryBase = class {
|
|
|
9979
10813
|
}
|
|
9980
10814
|
const queue = [entry];
|
|
9981
10815
|
let processing = 0;
|
|
9982
|
-
const
|
|
10816
|
+
const process3 = () => {
|
|
9983
10817
|
let paused = false;
|
|
9984
10818
|
while (!paused) {
|
|
9985
10819
|
const dir = queue.shift();
|
|
@@ -10013,9 +10847,9 @@ var PathScurryBase = class {
|
|
|
10013
10847
|
}
|
|
10014
10848
|
}
|
|
10015
10849
|
if (paused && !results.flowing)
|
|
10016
|
-
results.once("drain",
|
|
10850
|
+
results.once("drain", process3);
|
|
10017
10851
|
};
|
|
10018
|
-
|
|
10852
|
+
process3();
|
|
10019
10853
|
return results;
|
|
10020
10854
|
}
|
|
10021
10855
|
chdir(path2 = this.cwd) {
|
|
@@ -10094,7 +10928,7 @@ var PathScurryDarwin = class extends PathScurryPosix {
|
|
|
10094
10928
|
var Path = process.platform === "win32" ? PathWin32 : PathPosix;
|
|
10095
10929
|
var PathScurry = process.platform === "win32" ? PathScurryWin32 : process.platform === "darwin" ? PathScurryDarwin : PathScurryPosix;
|
|
10096
10930
|
|
|
10097
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
10931
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/pattern.js
|
|
10098
10932
|
var isPatternList = (pl) => pl.length >= 1;
|
|
10099
10933
|
var isGlobList = (gl) => gl.length >= 1;
|
|
10100
10934
|
var Pattern = class _Pattern {
|
|
@@ -10259,7 +11093,7 @@ var Pattern = class _Pattern {
|
|
|
10259
11093
|
}
|
|
10260
11094
|
};
|
|
10261
11095
|
|
|
10262
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11096
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/ignore.js
|
|
10263
11097
|
var defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
10264
11098
|
var Ignore = class {
|
|
10265
11099
|
relative;
|
|
@@ -10346,7 +11180,7 @@ var Ignore = class {
|
|
|
10346
11180
|
}
|
|
10347
11181
|
};
|
|
10348
11182
|
|
|
10349
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11183
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/processor.js
|
|
10350
11184
|
var HasWalkedCache = class _HasWalkedCache {
|
|
10351
11185
|
store;
|
|
10352
11186
|
constructor(store = /* @__PURE__ */ new Map()) {
|
|
@@ -10567,7 +11401,7 @@ var Processor = class _Processor {
|
|
|
10567
11401
|
}
|
|
10568
11402
|
};
|
|
10569
11403
|
|
|
10570
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11404
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/walker.js
|
|
10571
11405
|
var makeIgnore = (ignore, opts) => typeof ignore === "string" ? new Ignore([ignore], opts) : Array.isArray(ignore) ? new Ignore(ignore, opts) : ignore;
|
|
10572
11406
|
var GlobUtil = class {
|
|
10573
11407
|
path;
|
|
@@ -10894,7 +11728,7 @@ var GlobStream = class extends GlobUtil {
|
|
|
10894
11728
|
}
|
|
10895
11729
|
};
|
|
10896
11730
|
|
|
10897
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11731
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/glob.js
|
|
10898
11732
|
var defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
10899
11733
|
var Glob = class {
|
|
10900
11734
|
absolute;
|
|
@@ -11094,7 +11928,7 @@ var Glob = class {
|
|
|
11094
11928
|
}
|
|
11095
11929
|
};
|
|
11096
11930
|
|
|
11097
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11931
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/has-magic.js
|
|
11098
11932
|
var hasMagic = (pattern, options = {}) => {
|
|
11099
11933
|
if (!Array.isArray(pattern)) {
|
|
11100
11934
|
pattern = [pattern];
|
|
@@ -11106,7 +11940,7 @@ var hasMagic = (pattern, options = {}) => {
|
|
|
11106
11940
|
return false;
|
|
11107
11941
|
};
|
|
11108
11942
|
|
|
11109
|
-
// ../../node_modules/.pnpm/glob@11.0
|
|
11943
|
+
// ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/index.js
|
|
11110
11944
|
function globStreamSync(pattern, options = {}) {
|
|
11111
11945
|
return new Glob(pattern, options).streamSync();
|
|
11112
11946
|
}
|
|
@@ -11268,7 +12102,7 @@ async function analyzeComponentFile(filePath, _options = {}) {
|
|
|
11268
12102
|
});
|
|
11269
12103
|
return analysis;
|
|
11270
12104
|
}
|
|
11271
|
-
const content =
|
|
12105
|
+
const content = readFileSync5(resolve3(filePath), "utf-8");
|
|
11272
12106
|
analysis.size = Buffer.byteLength(content, "utf8");
|
|
11273
12107
|
analysis.lines = content.split("\n").length;
|
|
11274
12108
|
const syntaxAnalysis = analyzeSyntax(content, filePath);
|
|
@@ -11629,7 +12463,7 @@ async function analyzeHydration(options = {}) {
|
|
|
11629
12463
|
}
|
|
11630
12464
|
|
|
11631
12465
|
// src/validators/project-validator.js
|
|
11632
|
-
import { existsSync as existsSync9, readFileSync as
|
|
12466
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
11633
12467
|
import { resolve as resolve4 } from "path";
|
|
11634
12468
|
async function validateProject(_options = {}) {
|
|
11635
12469
|
const validation = {
|
|
@@ -11696,7 +12530,7 @@ function validatePackageJson() {
|
|
|
11696
12530
|
const issues = [];
|
|
11697
12531
|
const recommendations = [];
|
|
11698
12532
|
try {
|
|
11699
|
-
const packageJson = JSON.parse(
|
|
12533
|
+
const packageJson = JSON.parse(readFileSync6("package.json", "utf-8"));
|
|
11700
12534
|
const requiredFields = ["name", "version", "description"];
|
|
11701
12535
|
requiredFields.forEach((field) => {
|
|
11702
12536
|
const hasField = packageJson[field];
|
|
@@ -11852,7 +12686,7 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
|
|
|
11852
12686
|
});
|
|
11853
12687
|
if (!response.target) {
|
|
11854
12688
|
console.log(picocolors5.yellow("\u{1F44B} Debug cancelled"));
|
|
11855
|
-
|
|
12689
|
+
process2.exit(0);
|
|
11856
12690
|
}
|
|
11857
12691
|
debugTarget = response.target;
|
|
11858
12692
|
}
|
|
@@ -11894,14 +12728,14 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
|
|
|
11894
12728
|
console.log();
|
|
11895
12729
|
console.log(picocolors5.red("\u274C Debug Error:"));
|
|
11896
12730
|
console.log(picocolors5.gray(` ${error.message}`));
|
|
11897
|
-
if (
|
|
12731
|
+
if (env2.DEBUG) {
|
|
11898
12732
|
console.log();
|
|
11899
12733
|
console.log(picocolors5.gray("Stack trace:"));
|
|
11900
12734
|
console.log(picocolors5.gray(error.stack));
|
|
11901
12735
|
} else {
|
|
11902
12736
|
console.log(picocolors5.gray(" Run with DEBUG=1 for detailed error information"));
|
|
11903
12737
|
}
|
|
11904
|
-
|
|
12738
|
+
process2.exit(1);
|
|
11905
12739
|
}
|
|
11906
12740
|
});
|
|
11907
12741
|
debugCommand.command("component [name]").description("Analyze component structure and performance").option("-f, --file <file>", "component file path").option("--props <props>", "test component with specific props (JSON)").option("--deep", "perform deep structural analysis").action(async (name, options) => {
|
|
@@ -11980,7 +12814,7 @@ async function analyzeConfiguration(_options = {}) {
|
|
|
11980
12814
|
};
|
|
11981
12815
|
if (existsSync10("package.json")) {
|
|
11982
12816
|
try {
|
|
11983
|
-
const packageJson = JSON.parse(
|
|
12817
|
+
const packageJson = JSON.parse(readFileSync7("package.json", "utf-8"));
|
|
11984
12818
|
const hasCoherentDeps = Object.keys(packageJson.dependencies || {}).some((dep) => dep.startsWith("@coherent.js/"));
|
|
11985
12819
|
if (!hasCoherentDeps) {
|
|
11986
12820
|
analysis.summary.issues.push("No Coherent.js dependencies found");
|
|
@@ -12089,12 +12923,12 @@ async function generateHTMLReport(result) {
|
|
|
12089
12923
|
<h1>\u{1F50D} Coherent.js Debug Report</h1>
|
|
12090
12924
|
<p>Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}</p>
|
|
12091
12925
|
</div>
|
|
12092
|
-
|
|
12926
|
+
|
|
12093
12927
|
<div class="section">
|
|
12094
12928
|
<h2>Summary</h2>
|
|
12095
12929
|
<pre>${JSON.stringify(result.summary, null, 2)}</pre>
|
|
12096
12930
|
</div>
|
|
12097
|
-
|
|
12931
|
+
|
|
12098
12932
|
${result.issues ? `
|
|
12099
12933
|
<div class="section">
|
|
12100
12934
|
<h2>Issues</h2>
|
|
@@ -12103,7 +12937,7 @@ async function generateHTMLReport(result) {
|
|
|
12103
12937
|
`).join("")}
|
|
12104
12938
|
</div>
|
|
12105
12939
|
` : ""}
|
|
12106
|
-
|
|
12940
|
+
|
|
12107
12941
|
${result.recommendations ? `
|
|
12108
12942
|
<div class="section">
|
|
12109
12943
|
<h2>Recommendations</h2>
|
|
@@ -12129,7 +12963,7 @@ var __dirname = dirname3(__filename);
|
|
|
12129
12963
|
var version = "1.0.1";
|
|
12130
12964
|
try {
|
|
12131
12965
|
const packagePath = join8(__dirname, "..", "package.json");
|
|
12132
|
-
const packageJson = JSON.parse(
|
|
12966
|
+
const packageJson = JSON.parse(readFileSync8(packagePath, "utf-8"));
|
|
12133
12967
|
version = packageJson.version;
|
|
12134
12968
|
} catch {
|
|
12135
12969
|
}
|