@coherent.js/cli 1.0.0-beta.5 → 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/dist/index.js +876 -322
- package/package.json +1 -1
- 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
|
}
|
|
@@ -45,7 +47,9 @@ var cliVersion = getCLIVersion();
|
|
|
45
47
|
function generateBuiltInServer(options = {}) {
|
|
46
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';`);
|
|
@@ -79,11 +83,42 @@ ${hasApi || hasAuth ? ` // Handle API routes
|
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
` : ""} // Serve
|
|
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');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Serve static files
|
|
83
100
|
if (url.pathname.startsWith('/public')) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
+
}
|
|
87
122
|
}
|
|
88
123
|
|
|
89
124
|
// Render page
|
|
@@ -114,23 +149,23 @@ function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
|
|
|
114
149
|
if (requestMethod !== routeMethod) {
|
|
115
150
|
return null;
|
|
116
151
|
}
|
|
117
|
-
|
|
152
|
+
|
|
118
153
|
// Split paths into segments
|
|
119
154
|
const routeSegments = routePattern.split('/').filter(Boolean);
|
|
120
155
|
const urlSegments = urlPath.split('/').filter(Boolean);
|
|
121
|
-
|
|
156
|
+
|
|
122
157
|
// Check if lengths match
|
|
123
158
|
if (routeSegments.length !== urlSegments.length) {
|
|
124
159
|
return null;
|
|
125
160
|
}
|
|
126
|
-
|
|
161
|
+
|
|
127
162
|
const params = {};
|
|
128
|
-
|
|
163
|
+
|
|
129
164
|
// Match each segment
|
|
130
165
|
for (let i = 0; i < routeSegments.length; i++) {
|
|
131
166
|
const routeSegment = routeSegments[i];
|
|
132
167
|
const urlSegment = urlSegments[i];
|
|
133
|
-
|
|
168
|
+
|
|
134
169
|
// Check for parameter (e.g., :id)
|
|
135
170
|
if (routeSegment.startsWith(':')) {
|
|
136
171
|
const paramName = routeSegment.substring(1);
|
|
@@ -140,7 +175,7 @@ function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
|
|
|
140
175
|
return null;
|
|
141
176
|
}
|
|
142
177
|
}
|
|
143
|
-
|
|
178
|
+
|
|
144
179
|
return { params };
|
|
145
180
|
}
|
|
146
181
|
|
|
@@ -154,7 +189,7 @@ function generateExpressServer(options = {}) {
|
|
|
154
189
|
const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
|
|
155
190
|
const imports = [
|
|
156
191
|
`import express from 'express';`,
|
|
157
|
-
`import {
|
|
192
|
+
`import { render } from '@coherent.js/core';`
|
|
158
193
|
];
|
|
159
194
|
if (hasApi) imports.push(`import apiRoutes from './api/routes.js';`);
|
|
160
195
|
if (hasDatabase) imports.push(`import { initDatabase } from './db/index.js';`);
|
|
@@ -175,15 +210,25 @@ ${hasDatabase ? `// Initialize database
|
|
|
175
210
|
await initDatabase();
|
|
176
211
|
` : ""}${hasAuth ? `// Setup authentication
|
|
177
212
|
app.use(authMiddleware);
|
|
178
|
-
` : ""}// Setup Coherent.js
|
|
179
|
-
setupCoherent(app);
|
|
180
|
-
|
|
181
|
-
${hasApi ? `// API routes
|
|
182
|
-
app.use('/api', apiRoutes);
|
|
183
213
|
` : ""}
|
|
184
|
-
|
|
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
|
|
185
218
|
app.get('/', (req, res) => {
|
|
186
|
-
|
|
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);
|
|
187
232
|
});
|
|
188
233
|
|
|
189
234
|
// Error handling
|
|
@@ -232,9 +277,9 @@ await fastify.register(import('@fastify/static'), {
|
|
|
232
277
|
${hasApi ? `// API routes
|
|
233
278
|
await fastify.register(apiRoutes, { prefix: '/api' });
|
|
234
279
|
` : ""}
|
|
235
|
-
// Main route
|
|
280
|
+
// Main route - return Coherent.js component (auto-rendered by plugin)
|
|
236
281
|
fastify.get('/', async (request, reply) => {
|
|
237
|
-
return
|
|
282
|
+
return HomePage({});
|
|
238
283
|
});
|
|
239
284
|
|
|
240
285
|
// Start server
|
|
@@ -282,9 +327,9 @@ setupCoherent(app);
|
|
|
282
327
|
${hasApi ? `// API routes
|
|
283
328
|
apiRoutes(router);
|
|
284
329
|
` : ""}
|
|
285
|
-
// Main route
|
|
330
|
+
// Main route - set body to Coherent.js component (auto-rendered by middleware)
|
|
286
331
|
router.get('/', async (ctx) => {
|
|
287
|
-
ctx.
|
|
332
|
+
ctx.body = HomePage({});
|
|
288
333
|
});
|
|
289
334
|
|
|
290
335
|
app.use(router.routes());
|
|
@@ -350,9 +395,12 @@ export const dbConfig = {
|
|
|
350
395
|
user: process.env.DB_USER || 'postgres',
|
|
351
396
|
password: process.env.DB_PASSWORD || 'postgres',
|
|
352
397
|
// Connection pool settings
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
398
|
+
pool: {
|
|
399
|
+
min: 2,
|
|
400
|
+
max: 20,
|
|
401
|
+
idleTimeoutMillis: 30000,
|
|
402
|
+
connectionTimeoutMillis: 2000,
|
|
403
|
+
}
|
|
356
404
|
};
|
|
357
405
|
`,
|
|
358
406
|
mysql: `
|
|
@@ -363,9 +411,12 @@ export const dbConfig = {
|
|
|
363
411
|
user: process.env.DB_USER || 'root',
|
|
364
412
|
password: process.env.DB_PASSWORD || 'password',
|
|
365
413
|
// Connection pool settings
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
414
|
+
pool: {
|
|
415
|
+
max: 10,
|
|
416
|
+
min: 0,
|
|
417
|
+
waitForConnections: true,
|
|
418
|
+
queueLimit: 0
|
|
419
|
+
}
|
|
369
420
|
};
|
|
370
421
|
`,
|
|
371
422
|
sqlite: `
|
|
@@ -389,22 +440,33 @@ export const dbConfig = {
|
|
|
389
440
|
};
|
|
390
441
|
return configs[dbType] || "";
|
|
391
442
|
}
|
|
392
|
-
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>" : "";
|
|
393
447
|
const inits = {
|
|
394
448
|
postgres: `
|
|
395
449
|
import { setupDatabase } from '@coherent.js/database';
|
|
396
450
|
import { dbConfig } from './config.js';
|
|
397
451
|
|
|
398
|
-
let db;
|
|
452
|
+
let db${typeAnnotation};
|
|
399
453
|
|
|
400
|
-
export async function initDatabase() {
|
|
454
|
+
export async function initDatabase()${returnType} {
|
|
401
455
|
try {
|
|
402
456
|
// Setup database with Coherent.js
|
|
403
457
|
db = setupDatabase({
|
|
404
|
-
type: '
|
|
405
|
-
|
|
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
|
|
406
465
|
});
|
|
407
466
|
|
|
467
|
+
// Wait for connection
|
|
468
|
+
await db.connect();
|
|
469
|
+
|
|
408
470
|
console.log('\u2713 Connected to PostgreSQL database');
|
|
409
471
|
|
|
410
472
|
return db;
|
|
@@ -414,7 +476,7 @@ export async function initDatabase() {
|
|
|
414
476
|
}
|
|
415
477
|
}
|
|
416
478
|
|
|
417
|
-
export function getDatabase() {
|
|
479
|
+
export function getDatabase()${typeAnnotation} {
|
|
418
480
|
if (!db) {
|
|
419
481
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
420
482
|
}
|
|
@@ -434,16 +496,24 @@ process.on('SIGINT', async () => {
|
|
|
434
496
|
import { setupDatabase } from '@coherent.js/database';
|
|
435
497
|
import { dbConfig } from './config.js';
|
|
436
498
|
|
|
437
|
-
let db;
|
|
499
|
+
let db${typeAnnotation};
|
|
438
500
|
|
|
439
|
-
export async function initDatabase() {
|
|
501
|
+
export async function initDatabase()${returnType} {
|
|
440
502
|
try {
|
|
441
503
|
// Setup database with Coherent.js
|
|
442
504
|
db = setupDatabase({
|
|
443
505
|
type: 'mysql',
|
|
444
|
-
|
|
506
|
+
host: dbConfig.host,
|
|
507
|
+
port: dbConfig.port,
|
|
508
|
+
database: dbConfig.database,
|
|
509
|
+
username: dbConfig.user,
|
|
510
|
+
password: dbConfig.password,
|
|
511
|
+
pool: dbConfig.pool
|
|
445
512
|
});
|
|
446
513
|
|
|
514
|
+
// Wait for connection
|
|
515
|
+
await db.connect();
|
|
516
|
+
|
|
447
517
|
console.log('\u2713 Connected to MySQL database');
|
|
448
518
|
|
|
449
519
|
return db;
|
|
@@ -453,7 +523,7 @@ export async function initDatabase() {
|
|
|
453
523
|
}
|
|
454
524
|
}
|
|
455
525
|
|
|
456
|
-
export function getDatabase() {
|
|
526
|
+
export function getDatabase()${typeAnnotation} {
|
|
457
527
|
if (!db) {
|
|
458
528
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
459
529
|
}
|
|
@@ -475,21 +545,24 @@ import { dbConfig } from './config.js';
|
|
|
475
545
|
import { mkdirSync } from 'fs';
|
|
476
546
|
import { dirname } from 'path';
|
|
477
547
|
|
|
478
|
-
let db;
|
|
548
|
+
let db${typeAnnotation};
|
|
479
549
|
|
|
480
|
-
export async function initDatabase() {
|
|
550
|
+
export async function initDatabase()${returnType} {
|
|
481
551
|
try {
|
|
482
|
-
// Ensure directory exists
|
|
483
|
-
if (dbConfig.filename) {
|
|
552
|
+
// Ensure directory exists for SQLite file
|
|
553
|
+
if (dbConfig.filename && dbConfig.filename !== ':memory:') {
|
|
484
554
|
mkdirSync(dirname(dbConfig.filename), { recursive: true });
|
|
485
555
|
}
|
|
486
556
|
|
|
487
557
|
// Setup database with Coherent.js
|
|
488
558
|
db = setupDatabase({
|
|
489
559
|
type: 'sqlite',
|
|
490
|
-
|
|
560
|
+
database: dbConfig.filename || ':memory:'
|
|
491
561
|
});
|
|
492
562
|
|
|
563
|
+
// Wait for connection
|
|
564
|
+
await db.connect();
|
|
565
|
+
|
|
493
566
|
console.log('\u2713 Connected to SQLite database');
|
|
494
567
|
|
|
495
568
|
return db;
|
|
@@ -499,7 +572,7 @@ export async function initDatabase() {
|
|
|
499
572
|
}
|
|
500
573
|
}
|
|
501
574
|
|
|
502
|
-
export function getDatabase() {
|
|
575
|
+
export function getDatabase()${typeAnnotation} {
|
|
503
576
|
if (!db) {
|
|
504
577
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
505
578
|
}
|
|
@@ -507,9 +580,9 @@ export function getDatabase() {
|
|
|
507
580
|
}
|
|
508
581
|
|
|
509
582
|
// Graceful shutdown
|
|
510
|
-
process.on('SIGINT', () => {
|
|
583
|
+
process.on('SIGINT', async () => {
|
|
511
584
|
if (db) {
|
|
512
|
-
db.
|
|
585
|
+
await db.disconnect();
|
|
513
586
|
console.log('Database closed');
|
|
514
587
|
}
|
|
515
588
|
process.exit(0);
|
|
@@ -519,16 +592,20 @@ process.on('SIGINT', () => {
|
|
|
519
592
|
import { setupDatabase } from '@coherent.js/database';
|
|
520
593
|
import { dbConfig } from './config.js';
|
|
521
594
|
|
|
522
|
-
let db;
|
|
595
|
+
let db${typeAnnotation};
|
|
523
596
|
|
|
524
|
-
export async function initDatabase() {
|
|
597
|
+
export async function initDatabase()${returnType} {
|
|
525
598
|
try {
|
|
526
599
|
// Setup database with Coherent.js
|
|
527
600
|
db = setupDatabase({
|
|
528
601
|
type: 'mongodb',
|
|
529
|
-
|
|
602
|
+
database: dbConfig.uri,
|
|
603
|
+
...dbConfig.options
|
|
530
604
|
});
|
|
531
605
|
|
|
606
|
+
// Wait for connection
|
|
607
|
+
await db.connect();
|
|
608
|
+
|
|
532
609
|
console.log('\u2713 Connected to MongoDB database');
|
|
533
610
|
|
|
534
611
|
return db;
|
|
@@ -538,7 +615,7 @@ export async function initDatabase() {
|
|
|
538
615
|
}
|
|
539
616
|
}
|
|
540
617
|
|
|
541
|
-
export function getDatabase() {
|
|
618
|
+
export function getDatabase()${typeAnnotation} {
|
|
542
619
|
if (!db) {
|
|
543
620
|
throw new Error('Database not initialized. Call initDatabase() first.');
|
|
544
621
|
}
|
|
@@ -557,47 +634,57 @@ process.on('SIGINT', async () => {
|
|
|
557
634
|
};
|
|
558
635
|
return inits[dbType] || "";
|
|
559
636
|
}
|
|
560
|
-
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
|
+
}` : "";
|
|
561
645
|
const models = {
|
|
562
646
|
postgres: `
|
|
563
647
|
import { getDatabase } from '../index.js';
|
|
564
648
|
|
|
649
|
+
${interfaceDef}
|
|
650
|
+
|
|
565
651
|
export class UserModel {
|
|
566
|
-
static async createTable() {
|
|
652
|
+
static async createTable()${typeAnnotation} {
|
|
567
653
|
const db = getDatabase();
|
|
568
654
|
await db.query(\`
|
|
569
655
|
CREATE TABLE IF NOT EXISTS users (
|
|
570
656
|
id SERIAL PRIMARY KEY,
|
|
571
657
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
572
658
|
name VARCHAR(255) NOT NULL,
|
|
659
|
+
password_hash VARCHAR(255),
|
|
573
660
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
574
661
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
575
662
|
)
|
|
576
663
|
\`);
|
|
577
664
|
}
|
|
578
665
|
|
|
579
|
-
static async create(
|
|
666
|
+
static async create(userData)${typeAnnotation} {
|
|
580
667
|
const db = getDatabase();
|
|
581
668
|
const result = await db.query(
|
|
582
669
|
'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
|
|
583
|
-
[
|
|
670
|
+
[userData.email, userData.name]
|
|
584
671
|
);
|
|
585
672
|
return result.rows[0];
|
|
586
673
|
}
|
|
587
674
|
|
|
588
|
-
static async findById(id) {
|
|
675
|
+
static async findById(id)${typeAnnotation} {
|
|
589
676
|
const db = getDatabase();
|
|
590
677
|
const result = await db.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
591
678
|
return result.rows[0];
|
|
592
679
|
}
|
|
593
680
|
|
|
594
|
-
static async findByEmail(email) {
|
|
681
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
595
682
|
const db = getDatabase();
|
|
596
683
|
const result = await db.query('SELECT * FROM users WHERE email = $1', [email]);
|
|
597
684
|
return result.rows[0];
|
|
598
685
|
}
|
|
599
686
|
|
|
600
|
-
static async update(id, data) {
|
|
687
|
+
static async update(id, data)${typeAnnotation} {
|
|
601
688
|
const db = getDatabase();
|
|
602
689
|
const result = await db.query(
|
|
603
690
|
'UPDATE users SET email = $1, name = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $3 RETURNING *',
|
|
@@ -606,7 +693,7 @@ export class UserModel {
|
|
|
606
693
|
return result.rows[0];
|
|
607
694
|
}
|
|
608
695
|
|
|
609
|
-
static async delete(id) {
|
|
696
|
+
static async delete(id)${typeAnnotation} {
|
|
610
697
|
const db = getDatabase();
|
|
611
698
|
await db.query('DELETE FROM users WHERE id = $1', [id]);
|
|
612
699
|
}
|
|
@@ -615,61 +702,66 @@ export class UserModel {
|
|
|
615
702
|
mysql: `
|
|
616
703
|
import { getDatabase } from '../index.js';
|
|
617
704
|
|
|
705
|
+
${interfaceDef}
|
|
706
|
+
|
|
618
707
|
export class UserModel {
|
|
619
|
-
static async createTable() {
|
|
708
|
+
static async createTable()${typeAnnotation} {
|
|
620
709
|
const db = getDatabase();
|
|
621
|
-
await db.
|
|
710
|
+
await db.query(\`
|
|
622
711
|
CREATE TABLE IF NOT EXISTS users (
|
|
623
712
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
624
713
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
625
714
|
name VARCHAR(255) NOT NULL,
|
|
715
|
+
password_hash VARCHAR(255),
|
|
626
716
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
627
717
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
628
718
|
)
|
|
629
719
|
\`);
|
|
630
720
|
}
|
|
631
721
|
|
|
632
|
-
static async create(
|
|
722
|
+
static async create(userData)${typeAnnotation} {
|
|
633
723
|
const db = getDatabase();
|
|
634
|
-
const
|
|
724
|
+
const result = await db.query(
|
|
635
725
|
'INSERT INTO users (email, name) VALUES (?, ?)',
|
|
636
|
-
[
|
|
726
|
+
[userData.email, userData.name]
|
|
637
727
|
);
|
|
638
|
-
return
|
|
728
|
+
return result[0];
|
|
639
729
|
}
|
|
640
730
|
|
|
641
|
-
static async findById(id) {
|
|
731
|
+
static async findById(id)${typeAnnotation} {
|
|
642
732
|
const db = getDatabase();
|
|
643
|
-
const
|
|
644
|
-
return
|
|
733
|
+
const result = await db.query('SELECT * FROM users WHERE id = ?', [id]);
|
|
734
|
+
return result[0];
|
|
645
735
|
}
|
|
646
736
|
|
|
647
|
-
static async findByEmail(email) {
|
|
737
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
648
738
|
const db = getDatabase();
|
|
649
|
-
const
|
|
650
|
-
return
|
|
739
|
+
const result = await db.query('SELECT * FROM users WHERE email = ?', [email]);
|
|
740
|
+
return result[0];
|
|
651
741
|
}
|
|
652
742
|
|
|
653
|
-
static async update(id, data) {
|
|
743
|
+
static async update(id, data)${typeAnnotation} {
|
|
654
744
|
const db = getDatabase();
|
|
655
|
-
await db.
|
|
656
|
-
'UPDATE users SET email = ?, name =
|
|
745
|
+
const result = await db.query(
|
|
746
|
+
'UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
|
|
657
747
|
[data.email, data.name, id]
|
|
658
748
|
);
|
|
659
|
-
return
|
|
749
|
+
return result[0];
|
|
660
750
|
}
|
|
661
751
|
|
|
662
|
-
static async delete(id) {
|
|
752
|
+
static async delete(id)${typeAnnotation} {
|
|
663
753
|
const db = getDatabase();
|
|
664
|
-
await db.
|
|
754
|
+
await db.query('DELETE FROM users WHERE id = ?', [id]);
|
|
665
755
|
}
|
|
666
756
|
}
|
|
667
757
|
`,
|
|
668
758
|
sqlite: `
|
|
669
759
|
import { getDatabase } from '../index.js';
|
|
670
760
|
|
|
761
|
+
${interfaceDef}
|
|
762
|
+
|
|
671
763
|
export class UserModel {
|
|
672
|
-
static createTable() {
|
|
764
|
+
static createTable()${typeAnnotation} {
|
|
673
765
|
const db = getDatabase();
|
|
674
766
|
db.exec(\`
|
|
675
767
|
CREATE TABLE IF NOT EXISTS users (
|
|
@@ -682,94 +774,82 @@ export class UserModel {
|
|
|
682
774
|
\`);
|
|
683
775
|
}
|
|
684
776
|
|
|
685
|
-
static create(data) {
|
|
777
|
+
static create(data)${typeAnnotation} {
|
|
686
778
|
const db = getDatabase();
|
|
687
779
|
const stmt = db.prepare('INSERT INTO users (email, name) VALUES (?, ?)');
|
|
688
780
|
const result = stmt.run(data.email, data.name);
|
|
689
781
|
return { id: result.lastInsertRowid, ...data };
|
|
690
782
|
}
|
|
691
783
|
|
|
692
|
-
static findById(id) {
|
|
784
|
+
static findById(id)${typeAnnotation} {
|
|
693
785
|
const db = getDatabase();
|
|
694
786
|
const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
|
|
695
787
|
return stmt.get(id);
|
|
696
788
|
}
|
|
697
789
|
|
|
698
|
-
static findByEmail(email) {
|
|
790
|
+
static findByEmail(email)${typeAnnotation} {
|
|
699
791
|
const db = getDatabase();
|
|
700
792
|
const stmt = db.prepare('SELECT * FROM users WHERE email = ?');
|
|
701
793
|
return stmt.get(email);
|
|
702
794
|
}
|
|
703
795
|
|
|
704
|
-
static update(id, data) {
|
|
796
|
+
static update(id, data)${typeAnnotation} {
|
|
705
797
|
const db = getDatabase();
|
|
706
798
|
const stmt = db.prepare('UPDATE users SET email = ?, name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
|
|
707
799
|
stmt.run(data.email, data.name, id);
|
|
708
|
-
return
|
|
800
|
+
return this.findById(id);
|
|
709
801
|
}
|
|
710
802
|
|
|
711
|
-
static delete(id) {
|
|
803
|
+
static delete(id)${typeAnnotation} {
|
|
712
804
|
const db = getDatabase();
|
|
713
805
|
const stmt = db.prepare('DELETE FROM users WHERE id = ?');
|
|
714
|
-
stmt.run(id);
|
|
806
|
+
return stmt.run(id);
|
|
715
807
|
}
|
|
716
808
|
}
|
|
717
809
|
`,
|
|
718
810
|
mongodb: `
|
|
719
811
|
import { getDatabase } from '../index.js';
|
|
720
812
|
|
|
721
|
-
|
|
722
|
-
static collectionName = 'users';
|
|
813
|
+
${interfaceDef}
|
|
723
814
|
|
|
724
|
-
|
|
815
|
+
export class UserModel {
|
|
816
|
+
static async createCollection()${typeAnnotation} {
|
|
725
817
|
const db = getDatabase();
|
|
726
|
-
|
|
818
|
+
await db.createCollection('users');
|
|
819
|
+
|
|
820
|
+
// Create index for email uniqueness
|
|
821
|
+
await db.collection('users').createIndex({ email: 1 }, { unique: true });
|
|
727
822
|
}
|
|
728
823
|
|
|
729
|
-
static async create(
|
|
730
|
-
const
|
|
731
|
-
const result = await collection.insertOne(
|
|
732
|
-
|
|
733
|
-
name: data.name,
|
|
734
|
-
createdAt: new Date(),
|
|
735
|
-
updatedAt: new Date()
|
|
736
|
-
});
|
|
737
|
-
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 };
|
|
738
828
|
}
|
|
739
829
|
|
|
740
|
-
static async findById(id) {
|
|
741
|
-
const
|
|
742
|
-
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 });
|
|
743
833
|
}
|
|
744
834
|
|
|
745
|
-
static async findByEmail(email) {
|
|
746
|
-
const
|
|
747
|
-
return await collection.findOne({ email });
|
|
835
|
+
static async findByEmail(email)${typeAnnotation} {
|
|
836
|
+
const db = getDatabase();
|
|
837
|
+
return await db.collection('users').findOne({ email });
|
|
748
838
|
}
|
|
749
839
|
|
|
750
|
-
static async update(id, data) {
|
|
751
|
-
const
|
|
752
|
-
await collection.updateOne(
|
|
840
|
+
static async update(id, data)${typeAnnotation} {
|
|
841
|
+
const db = getDatabase();
|
|
842
|
+
const result = await db.collection('users').updateOne(
|
|
753
843
|
{ _id: id },
|
|
754
|
-
{
|
|
755
|
-
$set: {
|
|
756
|
-
email: data.email,
|
|
757
|
-
name: data.name,
|
|
758
|
-
updatedAt: new Date()
|
|
759
|
-
}
|
|
760
|
-
}
|
|
844
|
+
{ $set: { ...data, updatedAt: new Date() } }
|
|
761
845
|
);
|
|
762
|
-
return
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
static async delete(id) {
|
|
766
|
-
const collection = this.getCollection();
|
|
767
|
-
await collection.deleteOne({ _id: id });
|
|
846
|
+
return result.modifiedCount > 0 ? this.findById(id) : null;
|
|
768
847
|
}
|
|
769
848
|
|
|
770
|
-
static async
|
|
771
|
-
const
|
|
772
|
-
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;
|
|
773
853
|
}
|
|
774
854
|
}
|
|
775
855
|
`
|
|
@@ -822,11 +902,11 @@ function getDatabaseDependencies(dbType) {
|
|
|
822
902
|
};
|
|
823
903
|
return deps[dbType] || {};
|
|
824
904
|
}
|
|
825
|
-
function generateDatabaseScaffolding(dbType) {
|
|
905
|
+
function generateDatabaseScaffolding(dbType, language = "javascript") {
|
|
826
906
|
return {
|
|
827
907
|
config: generateDatabaseConfig(dbType),
|
|
828
|
-
init: generateDatabaseInit(dbType),
|
|
829
|
-
model: generateExampleModel(dbType),
|
|
908
|
+
init: generateDatabaseInit(dbType, language),
|
|
909
|
+
model: generateExampleModel(dbType, language),
|
|
830
910
|
env: generateEnvExample(dbType),
|
|
831
911
|
dependencies: getDatabaseDependencies(dbType)
|
|
832
912
|
};
|
|
@@ -1122,7 +1202,7 @@ function generateAuthRoutes(runtime, authType) {
|
|
|
1122
1202
|
const jwtRoutes = {
|
|
1123
1203
|
express: `
|
|
1124
1204
|
import express from 'express';
|
|
1125
|
-
import { generateToken } from '../middleware/auth.js';
|
|
1205
|
+
import { generateToken, authMiddleware } from '../middleware/auth.js';
|
|
1126
1206
|
import { UserModel } from '../db/models/User.js';
|
|
1127
1207
|
|
|
1128
1208
|
const router = express.Router();
|
|
@@ -1522,11 +1602,7 @@ router.get('/me', authMiddleware, async (ctx) => {
|
|
|
1522
1602
|
}
|
|
1523
1603
|
});
|
|
1524
1604
|
|
|
1525
|
-
export default
|
|
1526
|
-
router.post('/auth/register', registerHandler);
|
|
1527
|
-
router.post('/auth/login', loginHandler);
|
|
1528
|
-
router.get('/auth/me', authMiddleware, meHandler);
|
|
1529
|
-
}
|
|
1605
|
+
export default router;
|
|
1530
1606
|
`
|
|
1531
1607
|
};
|
|
1532
1608
|
const sessionRoutes = {
|
|
@@ -1666,6 +1742,312 @@ function generateAuthScaffolding(authType, runtime) {
|
|
|
1666
1742
|
};
|
|
1667
1743
|
}
|
|
1668
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
|
+
|
|
1669
2051
|
// src/generators/package-scaffold.js
|
|
1670
2052
|
var cliVersion3 = getCLIVersion();
|
|
1671
2053
|
function generateApiScaffolding() {
|
|
@@ -1674,41 +2056,42 @@ import { createRouter } from '@coherent.js/api';
|
|
|
1674
2056
|
|
|
1675
2057
|
const router = createRouter();
|
|
1676
2058
|
|
|
1677
|
-
//
|
|
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)
|
|
1678
2069
|
router.get('/users/:id', {
|
|
1679
2070
|
params: {
|
|
1680
2071
|
id: { type: 'number', required: true }
|
|
1681
2072
|
},
|
|
1682
2073
|
handler: async (req, res) => {
|
|
1683
2074
|
const { id } = req.params;
|
|
1684
|
-
|
|
1685
|
-
return { id, name: 'Example User', email: 'user@example.com' };
|
|
2075
|
+
return getUserById(id);
|
|
1686
2076
|
}
|
|
1687
2077
|
});
|
|
1688
2078
|
|
|
1689
|
-
// Example POST route with body validation
|
|
1690
2079
|
router.post('/users', {
|
|
1691
2080
|
body: {
|
|
1692
2081
|
name: { type: 'string', required: true, minLength: 2 },
|
|
1693
2082
|
email: { type: 'string', required: true, pattern: /^[^@]+@[^@]+\\.[^@]+$/ }
|
|
1694
2083
|
},
|
|
1695
2084
|
handler: async (req, res) => {
|
|
1696
|
-
|
|
1697
|
-
// Create user logic here
|
|
1698
|
-
return { id: 1, name, email };
|
|
2085
|
+
return createUser(req.body);
|
|
1699
2086
|
}
|
|
1700
2087
|
});
|
|
1701
2088
|
|
|
1702
|
-
// Handler for GET /api/users/:id
|
|
2089
|
+
// Handler for GET /api/users/:id (Built-in Server)
|
|
1703
2090
|
export async function getUsersByIdHandler(req, res) {
|
|
1704
2091
|
try {
|
|
1705
|
-
// Extract ID from URL parameters
|
|
1706
2092
|
const { id } = req.params;
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
const result = await router.handle('GET', '/users/:id', { params: { id } }, {});
|
|
1710
|
-
|
|
1711
|
-
// Send JSON response
|
|
2093
|
+
const result = await getUserById(id);
|
|
2094
|
+
|
|
1712
2095
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1713
2096
|
res.end(JSON.stringify(result));
|
|
1714
2097
|
} catch (error) {
|
|
@@ -1718,23 +2101,19 @@ export async function getUsersByIdHandler(req, res) {
|
|
|
1718
2101
|
}
|
|
1719
2102
|
}
|
|
1720
2103
|
|
|
1721
|
-
// Handler for POST /api/users
|
|
2104
|
+
// Handler for POST /api/users (Built-in Server)
|
|
1722
2105
|
export async function postUsersHandler(req, res) {
|
|
1723
2106
|
try {
|
|
1724
|
-
// Parse JSON body
|
|
1725
2107
|
let body = '';
|
|
1726
2108
|
req.on('data', chunk => {
|
|
1727
2109
|
body += chunk.toString();
|
|
1728
2110
|
});
|
|
1729
|
-
|
|
2111
|
+
|
|
1730
2112
|
req.on('end', async () => {
|
|
1731
2113
|
try {
|
|
1732
2114
|
const parsedBody = JSON.parse(body);
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
const result = await router.handle('POST', '/users', { body: parsedBody }, {});
|
|
1736
|
-
|
|
1737
|
-
// Send JSON response
|
|
2115
|
+
const result = await createUser(parsedBody);
|
|
2116
|
+
|
|
1738
2117
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1739
2118
|
res.end(JSON.stringify(result));
|
|
1740
2119
|
} catch (error) {
|
|
@@ -1789,7 +2168,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
1789
2168
|
|
|
1790
2169
|
try {
|
|
1791
2170
|
// Dynamically import component
|
|
1792
|
-
const module = await import(
|
|
2171
|
+
const module = await import(\`/components/\${componentName}.js\`);
|
|
1793
2172
|
const Component = module.default || module[componentName];
|
|
1794
2173
|
|
|
1795
2174
|
// Hydrate component
|
|
@@ -2271,7 +2650,9 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2271
2650
|
auth = null,
|
|
2272
2651
|
packages = [],
|
|
2273
2652
|
language = "javascript",
|
|
2274
|
-
packageManager = "npm"
|
|
2653
|
+
packageManager = "npm",
|
|
2654
|
+
onProgress = () => {
|
|
2655
|
+
}
|
|
2275
2656
|
} = options;
|
|
2276
2657
|
const isTypeScript = language === "typescript";
|
|
2277
2658
|
const fileExtension = isTypeScript ? ".ts" : ".js";
|
|
@@ -2302,8 +2683,10 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2302
2683
|
dirs.forEach((dir) => {
|
|
2303
2684
|
mkdirSync(join2(projectPath, dir), { recursive: true });
|
|
2304
2685
|
});
|
|
2686
|
+
onProgress("Created project structure");
|
|
2305
2687
|
const packageJson = generatePackageJson(name, { template, runtime, database, auth, packages, language, packageManager });
|
|
2306
2688
|
writeFileSync(join2(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
2689
|
+
onProgress("Generated package.json");
|
|
2307
2690
|
if (isTypeScript) {
|
|
2308
2691
|
const tsConfig = generateTsConfig();
|
|
2309
2692
|
writeFileSync(join2(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
|
|
@@ -2311,6 +2694,7 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2311
2694
|
const jsConfig = generateJsConfig();
|
|
2312
2695
|
writeFileSync(join2(projectPath, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
|
|
2313
2696
|
}
|
|
2697
|
+
onProgress("Created configuration files");
|
|
2314
2698
|
const serverContent = generateServerFile(runtime, {
|
|
2315
2699
|
port: 3e3,
|
|
2316
2700
|
hasApi: packages.includes("api") || auth,
|
|
@@ -2318,23 +2702,54 @@ async function scaffoldProject(projectPath, options) {
|
|
|
2318
2702
|
hasAuth: !!auth
|
|
2319
2703
|
});
|
|
2320
2704
|
writeFileSync(join2(projectPath, `src/index${fileExtension}`), serverContent);
|
|
2705
|
+
onProgress("Set up server");
|
|
2321
2706
|
await generateHomePageComponent(projectPath, name, isTypeScript, fileExtension);
|
|
2707
|
+
onProgress("Created components");
|
|
2322
2708
|
if (database) {
|
|
2323
|
-
const dbScaffolding = generateDatabaseScaffolding(database);
|
|
2324
|
-
writeFileSync(join2(projectPath,
|
|
2325
|
-
writeFileSync(join2(projectPath,
|
|
2326
|
-
writeFileSync(join2(projectPath,
|
|
2327
|
-
|
|
2328
|
-
|
|
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");
|
|
2329
2735
|
}
|
|
2330
2736
|
if (auth) {
|
|
2331
2737
|
const authScaffolding = generateAuthScaffolding(auth, runtime);
|
|
2332
2738
|
const authDir = runtime === "fastify" ? "plugins" : "middleware";
|
|
2333
|
-
writeFileSync(join2(projectPath, `src/${authDir}/auth
|
|
2334
|
-
writeFileSync(join2(projectPath,
|
|
2739
|
+
writeFileSync(join2(projectPath, `src/${authDir}/auth${fileExtension}`), authScaffolding.middleware);
|
|
2740
|
+
writeFileSync(join2(projectPath, `src/api/auth${fileExtension}`), authScaffolding.routes);
|
|
2335
2741
|
const envPath = join2(projectPath, ".env.example");
|
|
2336
2742
|
const existingEnv = "";
|
|
2337
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");
|
|
2338
2753
|
}
|
|
2339
2754
|
if (packages.length > 0) {
|
|
2340
2755
|
const { files } = generatePackageScaffolding(packages);
|
|
@@ -2405,6 +2820,9 @@ function generatePackageJson(name, options) {
|
|
|
2405
2820
|
const tsDeps = getTypeScriptDependencies();
|
|
2406
2821
|
Object.assign(base.devDependencies, tsDeps);
|
|
2407
2822
|
base.devDependencies.tsx = "^4.19.2";
|
|
2823
|
+
if (auth) {
|
|
2824
|
+
base.devDependencies["@types/jsonwebtoken"] = "^9.0.7";
|
|
2825
|
+
}
|
|
2408
2826
|
}
|
|
2409
2827
|
if (packageManager === "pnpm") {
|
|
2410
2828
|
base.packageManager = "pnpm@9.0.0";
|
|
@@ -2414,7 +2832,7 @@ function generatePackageJson(name, options) {
|
|
|
2414
2832
|
const runtimeDeps = getRuntimeDependencies(runtime);
|
|
2415
2833
|
Object.assign(base.dependencies, runtimeDeps);
|
|
2416
2834
|
if (database) {
|
|
2417
|
-
const { dependencies: dbDeps } = generateDatabaseScaffolding(database);
|
|
2835
|
+
const { dependencies: dbDeps } = generateDatabaseScaffolding(database, language);
|
|
2418
2836
|
Object.assign(base.dependencies, dbDeps);
|
|
2419
2837
|
}
|
|
2420
2838
|
if (auth) {
|
|
@@ -2744,7 +3162,15 @@ function validateComponentName(name) {
|
|
|
2744
3162
|
}
|
|
2745
3163
|
|
|
2746
3164
|
// src/commands/create.js
|
|
2747
|
-
|
|
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) => {
|
|
2748
3174
|
let projectName = name;
|
|
2749
3175
|
if (!projectName) {
|
|
2750
3176
|
const response = await prompts({
|
|
@@ -2776,48 +3202,48 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2776
3202
|
console.log(picocolors.gray("\u{1F4CD} Location:"), projectPath);
|
|
2777
3203
|
console.log();
|
|
2778
3204
|
let template = options.template;
|
|
2779
|
-
if (!template || template === "basic") {
|
|
2780
|
-
|
|
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({
|
|
2781
3231
|
type: "select",
|
|
2782
|
-
name: "
|
|
2783
|
-
message: "
|
|
3232
|
+
name: "language",
|
|
3233
|
+
message: "Would you like to use TypeScript or JavaScript?",
|
|
2784
3234
|
choices: [
|
|
2785
|
-
{ title: "\u{
|
|
2786
|
-
{ title: "\u{
|
|
2787
|
-
{ title: "\u26A1 Express Integration", value: "express", description: "Coherent.js with Express.js" },
|
|
2788
|
-
{ title: "\u{1F680} Fastify Integration", value: "fastify", description: "Coherent.js with Fastify" },
|
|
2789
|
-
{ title: "\u{1F4F1} Component Library", value: "components", description: "Reusable component library" },
|
|
2790
|
-
{ 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" }
|
|
2791
3237
|
],
|
|
2792
3238
|
initial: 0
|
|
2793
3239
|
});
|
|
2794
|
-
if (!
|
|
3240
|
+
if (!languageResponse.language) {
|
|
2795
3241
|
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
2796
3242
|
process.exit(0);
|
|
2797
3243
|
}
|
|
2798
|
-
|
|
2799
|
-
}
|
|
2800
|
-
let runtime = "built-in";
|
|
2801
|
-
let database = null;
|
|
2802
|
-
let auth = null;
|
|
2803
|
-
let packages = [];
|
|
2804
|
-
let language = "javascript";
|
|
2805
|
-
const languageResponse = await prompts({
|
|
2806
|
-
type: "select",
|
|
2807
|
-
name: "language",
|
|
2808
|
-
message: "Would you like to use TypeScript or JavaScript?",
|
|
2809
|
-
choices: [
|
|
2810
|
-
{ title: "\u{1F4D8} JavaScript", value: "javascript", description: "JavaScript with JSDoc type hints (recommended)" },
|
|
2811
|
-
{ title: "\u{1F4D5} TypeScript", value: "typescript", description: "Full TypeScript with static type checking" }
|
|
2812
|
-
],
|
|
2813
|
-
initial: 0
|
|
2814
|
-
});
|
|
2815
|
-
if (!languageResponse.language) {
|
|
2816
|
-
console.log(picocolors.yellow("\u{1F44B} Project creation cancelled"));
|
|
2817
|
-
process.exit(0);
|
|
3244
|
+
language = languageResponse.language;
|
|
2818
3245
|
}
|
|
2819
|
-
|
|
2820
|
-
if (template === "custom" || template === "basic" || template === "fullstack" || template === "components") {
|
|
3246
|
+
if ((template === "basic" || template === "fullstack") && !options.skipPrompts) {
|
|
2821
3247
|
const runtimeResponse = await prompts({
|
|
2822
3248
|
type: "select",
|
|
2823
3249
|
name: "runtime",
|
|
@@ -2835,46 +3261,50 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2835
3261
|
process.exit(0);
|
|
2836
3262
|
}
|
|
2837
3263
|
runtime = runtimeResponse.runtime;
|
|
2838
|
-
} else if (template === "express") {
|
|
2839
|
-
runtime = "express";
|
|
2840
|
-
} else if (template === "fastify") {
|
|
2841
|
-
runtime = "fastify";
|
|
2842
3264
|
}
|
|
2843
|
-
if (template === "fullstack"
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
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;
|
|
2860
3287
|
}
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
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)) {
|
|
2878
3308
|
const authResponse = await prompts({
|
|
2879
3309
|
type: "select",
|
|
2880
3310
|
name: "auth",
|
|
@@ -2888,7 +3318,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2888
3318
|
});
|
|
2889
3319
|
auth = authResponse.auth === "none" ? null : authResponse.auth;
|
|
2890
3320
|
}
|
|
2891
|
-
} else if (template === "basic"
|
|
3321
|
+
} else if (template === "basic" && !options.skipPrompts) {
|
|
2892
3322
|
const pkgResponse = await prompts({
|
|
2893
3323
|
type: "multiselect",
|
|
2894
3324
|
name: "packages",
|
|
@@ -2903,7 +3333,7 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2903
3333
|
packages = pkgResponse.packages || [];
|
|
2904
3334
|
}
|
|
2905
3335
|
let packageManager = "npm";
|
|
2906
|
-
if (!options.skipInstall) {
|
|
3336
|
+
if (!options.skipInstall && !options.skipPrompts) {
|
|
2907
3337
|
const pmResponse = await prompts({
|
|
2908
3338
|
type: "select",
|
|
2909
3339
|
name: "packageManager",
|
|
@@ -2921,6 +3351,56 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2921
3351
|
}
|
|
2922
3352
|
packageManager = pmResponse.packageManager;
|
|
2923
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
|
+
}
|
|
2924
3404
|
const spinner = ora("Scaffolding project...").start();
|
|
2925
3405
|
try {
|
|
2926
3406
|
mkdirSync2(projectPath, { recursive: true });
|
|
@@ -2933,30 +3413,77 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2933
3413
|
packages,
|
|
2934
3414
|
language,
|
|
2935
3415
|
packageManager,
|
|
3416
|
+
dockerConfig,
|
|
2936
3417
|
skipInstall: options.skipInstall,
|
|
2937
|
-
skipGit: options.skipGit
|
|
3418
|
+
skipGit: options.skipGit,
|
|
3419
|
+
onProgress: (msg) => {
|
|
3420
|
+
spinner.text = msg;
|
|
3421
|
+
}
|
|
2938
3422
|
});
|
|
2939
3423
|
spinner.succeed("Project created successfully!");
|
|
2940
3424
|
console.log();
|
|
2941
|
-
console.log(picocolors.green("
|
|
3425
|
+
console.log(picocolors.green("Project created successfully!"));
|
|
2942
3426
|
console.log();
|
|
2943
|
-
console.log(picocolors.cyan("
|
|
2944
|
-
console.log(picocolors.gray("
|
|
2945
|
-
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));
|
|
2946
3431
|
if (database) {
|
|
2947
|
-
console.log(picocolors.gray(" Database:"), picocolors.
|
|
3432
|
+
console.log(picocolors.gray(" Database:"), picocolors.white(database));
|
|
2948
3433
|
}
|
|
2949
3434
|
if (auth) {
|
|
2950
|
-
console.log(picocolors.gray("
|
|
3435
|
+
console.log(picocolors.gray(" Auth:"), picocolors.white(auth.toUpperCase()));
|
|
2951
3436
|
}
|
|
2952
3437
|
if (packages.length > 0) {
|
|
2953
|
-
|
|
3438
|
+
const formattedPackages = packages.map((p) => `@coherent.js/${p}`).join(", ");
|
|
3439
|
+
console.log(picocolors.gray(" Packages:"), picocolors.white(formattedPackages));
|
|
2954
3440
|
}
|
|
2955
3441
|
console.log();
|
|
2956
|
-
|
|
2957
|
-
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/`));
|
|
3448
|
+
if (database) {
|
|
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`));
|
|
2958
3456
|
if (database) {
|
|
2959
|
-
console.log(picocolors.gray(
|
|
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++;
|
|
2960
3487
|
}
|
|
2961
3488
|
const pmCommands = {
|
|
2962
3489
|
npm: { install: "npm install", dev: "npm run dev" },
|
|
@@ -2964,14 +3491,41 @@ var createCommand = new Command("create").description("Create a new Coherent.js
|
|
|
2964
3491
|
pnpm: { install: "pnpm install", dev: "pnpm dev" }
|
|
2965
3492
|
};
|
|
2966
3493
|
const commands = pmCommands[packageManager] || pmCommands.npm;
|
|
2967
|
-
if (
|
|
2968
|
-
console.log(picocolors.
|
|
2969
|
-
|
|
2970
|
-
console.log(picocolors.gray(` ${commands.install}`));
|
|
2971
|
-
console.log(picocolors.gray(` ${commands.dev}`));
|
|
3494
|
+
if (options.skipInstall) {
|
|
3495
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.install));
|
|
3496
|
+
stepNum++;
|
|
2972
3497
|
}
|
|
3498
|
+
console.log(picocolors.white(` ${stepNum}.`), picocolors.gray(commands.dev));
|
|
2973
3499
|
console.log();
|
|
2974
|
-
|
|
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!"));
|
|
2975
3529
|
} catch (_error) {
|
|
2976
3530
|
spinner.fail("Failed to create project");
|
|
2977
3531
|
console.error(picocolors.red("\u274C Error:"), _error.message);
|
|
@@ -4579,7 +5133,7 @@ import { Command as Command3 } from "commander";
|
|
|
4579
5133
|
import ora3 from "ora";
|
|
4580
5134
|
import picocolors3 from "picocolors";
|
|
4581
5135
|
import { execSync as execSync2 } from "child_process";
|
|
4582
|
-
import { existsSync as existsSync6, readFileSync as
|
|
5136
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
4583
5137
|
import { join as join6 } from "path";
|
|
4584
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) => {
|
|
4585
5139
|
console.log(picocolors3.cyan("\u{1F3D7}\uFE0F Building Coherent.js project..."));
|
|
@@ -4591,7 +5145,7 @@ var buildCommand = new Command3("build").description("Build the project for prod
|
|
|
4591
5145
|
}
|
|
4592
5146
|
let packageJson;
|
|
4593
5147
|
try {
|
|
4594
|
-
packageJson = JSON.parse(
|
|
5148
|
+
packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
4595
5149
|
} catch {
|
|
4596
5150
|
console.error(picocolors3.red("\u274C Failed to read package.json"));
|
|
4597
5151
|
process.exit(1);
|
|
@@ -4685,8 +5239,8 @@ var buildCommand = new Command3("build").description("Build the project for prod
|
|
|
4685
5239
|
import { Command as Command4 } from "commander";
|
|
4686
5240
|
import ora4 from "ora";
|
|
4687
5241
|
import picocolors4 from "picocolors";
|
|
4688
|
-
import { spawn } from "child_process";
|
|
4689
|
-
import { existsSync as existsSync7, readFileSync as
|
|
5242
|
+
import { spawn as spawn2 } from "child_process";
|
|
5243
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
|
|
4690
5244
|
import { join as join7 } from "path";
|
|
4691
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) => {
|
|
4692
5246
|
console.log(picocolors4.cyan("\u{1F680} Starting Coherent.js development server..."));
|
|
@@ -4698,7 +5252,7 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4698
5252
|
}
|
|
4699
5253
|
let packageJson;
|
|
4700
5254
|
try {
|
|
4701
|
-
packageJson = JSON.parse(
|
|
5255
|
+
packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
|
|
4702
5256
|
} catch {
|
|
4703
5257
|
console.error(picocolors4.red("\u274C Failed to read package.json"));
|
|
4704
5258
|
process.exit(1);
|
|
@@ -4708,7 +5262,7 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4708
5262
|
let devProcess;
|
|
4709
5263
|
if (packageJson.scripts && packageJson.scripts.dev) {
|
|
4710
5264
|
spinner.text = "Running dev script...";
|
|
4711
|
-
devProcess =
|
|
5265
|
+
devProcess = spawn2("npm", ["run", "dev"], {
|
|
4712
5266
|
stdio: "inherit",
|
|
4713
5267
|
cwd: process.cwd(),
|
|
4714
5268
|
shell: true,
|
|
@@ -4721,19 +5275,19 @@ var devCommand = new Command4("dev").description("Start development server with
|
|
|
4721
5275
|
} else {
|
|
4722
5276
|
spinner.text = "Starting default dev server...";
|
|
4723
5277
|
if (existsSync7("vite.config.js") || existsSync7("vite.config.ts")) {
|
|
4724
|
-
devProcess =
|
|
5278
|
+
devProcess = spawn2("npx", ["vite", "--port", options.port, "--host", options.host], {
|
|
4725
5279
|
stdio: "inherit",
|
|
4726
5280
|
cwd: process.cwd(),
|
|
4727
5281
|
shell: true
|
|
4728
5282
|
});
|
|
4729
5283
|
} else if (existsSync7("webpack.config.js")) {
|
|
4730
|
-
devProcess =
|
|
5284
|
+
devProcess = spawn2("npx", ["webpack", "serve", "--port", options.port, "--host", options.host], {
|
|
4731
5285
|
stdio: "inherit",
|
|
4732
5286
|
cwd: process.cwd(),
|
|
4733
5287
|
shell: true
|
|
4734
5288
|
});
|
|
4735
5289
|
} else if (packageJson.type === "module" || existsSync7("src/index.js")) {
|
|
4736
|
-
devProcess =
|
|
5290
|
+
devProcess = spawn2("npx", ["nodemon", "src/index.js"], {
|
|
4737
5291
|
stdio: "inherit",
|
|
4738
5292
|
cwd: process.cwd(),
|
|
4739
5293
|
shell: true,
|
|
@@ -4798,11 +5352,12 @@ import { Command as Command5 } from "commander";
|
|
|
4798
5352
|
import prompts3 from "prompts";
|
|
4799
5353
|
import ora5 from "ora";
|
|
4800
5354
|
import picocolors5 from "picocolors";
|
|
4801
|
-
import {
|
|
5355
|
+
import process2, { env as env2 } from "node:process";
|
|
5356
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
4802
5357
|
import { resolve as resolve5 } from "path";
|
|
4803
5358
|
|
|
4804
5359
|
// src/analyzers/component-analyzer.js
|
|
4805
|
-
import { readFileSync as
|
|
5360
|
+
import { readFileSync as readFileSync5, existsSync as existsSync8 } from "fs";
|
|
4806
5361
|
import { resolve as resolve3 } from "path";
|
|
4807
5362
|
|
|
4808
5363
|
// ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
@@ -5693,7 +6248,7 @@ var path = {
|
|
|
5693
6248
|
};
|
|
5694
6249
|
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
5695
6250
|
minimatch.sep = sep;
|
|
5696
|
-
var GLOBSTAR = Symbol("globstar **");
|
|
6251
|
+
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
5697
6252
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
5698
6253
|
var qmark2 = "[^/]";
|
|
5699
6254
|
var star2 = qmark2 + "*?";
|
|
@@ -6404,7 +6959,6 @@ if (typeof AC === "undefined") {
|
|
|
6404
6959
|
};
|
|
6405
6960
|
}
|
|
6406
6961
|
var shouldWarn = (code) => !warned.has(code);
|
|
6407
|
-
var TYPE = Symbol("type");
|
|
6408
6962
|
var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
6409
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;
|
|
6410
6964
|
var ZeroArray = class extends Array {
|
|
@@ -7780,37 +8334,37 @@ var isStream = (s) => !!s && typeof s === "object" && (s instanceof Minipass ||
|
|
|
7780
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
|
|
7781
8335
|
s.pipe !== Stream.Writable.prototype.pipe;
|
|
7782
8336
|
var isWritable = (s) => !!s && typeof s === "object" && s instanceof EventEmitter && typeof s.write === "function" && typeof s.end === "function";
|
|
7783
|
-
var EOF = Symbol("EOF");
|
|
7784
|
-
var MAYBE_EMIT_END = Symbol("maybeEmitEnd");
|
|
7785
|
-
var EMITTED_END = Symbol("emittedEnd");
|
|
7786
|
-
var EMITTING_END = Symbol("emittingEnd");
|
|
7787
|
-
var EMITTED_ERROR = Symbol("emittedError");
|
|
7788
|
-
var CLOSED = Symbol("closed");
|
|
7789
|
-
var READ = Symbol("read");
|
|
7790
|
-
var FLUSH = Symbol("flush");
|
|
7791
|
-
var FLUSHCHUNK = Symbol("flushChunk");
|
|
7792
|
-
var ENCODING = Symbol("encoding");
|
|
7793
|
-
var DECODER = Symbol("decoder");
|
|
7794
|
-
var FLOWING = Symbol("flowing");
|
|
7795
|
-
var PAUSED = Symbol("paused");
|
|
7796
|
-
var RESUME = Symbol("resume");
|
|
7797
|
-
var BUFFER = Symbol("buffer");
|
|
7798
|
-
var PIPES = Symbol("pipes");
|
|
7799
|
-
var BUFFERLENGTH = Symbol("bufferLength");
|
|
7800
|
-
var BUFFERPUSH = Symbol("bufferPush");
|
|
7801
|
-
var BUFFERSHIFT = Symbol("bufferShift");
|
|
7802
|
-
var OBJECTMODE = Symbol("objectMode");
|
|
7803
|
-
var DESTROYED = Symbol("destroyed");
|
|
7804
|
-
var ERROR = Symbol("error");
|
|
7805
|
-
var EMITDATA = Symbol("emitData");
|
|
7806
|
-
var EMITEND = Symbol("emitEnd");
|
|
7807
|
-
var EMITEND2 = Symbol("emitEnd2");
|
|
7808
|
-
var ASYNC = Symbol("async");
|
|
7809
|
-
var ABORT = Symbol("abort");
|
|
7810
|
-
var ABORTED = Symbol("aborted");
|
|
7811
|
-
var SIGNAL = Symbol("signal");
|
|
7812
|
-
var DATALISTENERS = Symbol("dataListeners");
|
|
7813
|
-
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");
|
|
7814
8368
|
var defer = (fn) => Promise.resolve().then(fn);
|
|
7815
8369
|
var nodefer = (fn) => fn();
|
|
7816
8370
|
var isEndish = (ev) => ev === "end" || ev === "finish" || ev === "prefinish";
|
|
@@ -8723,7 +9277,7 @@ var ChildrenCache = class extends LRUCache {
|
|
|
8723
9277
|
});
|
|
8724
9278
|
}
|
|
8725
9279
|
};
|
|
8726
|
-
var setAsCwd = Symbol("PathScurry setAsCwd");
|
|
9280
|
+
var setAsCwd = /* @__PURE__ */ Symbol("PathScurry setAsCwd");
|
|
8727
9281
|
var PathBase = class {
|
|
8728
9282
|
/**
|
|
8729
9283
|
* the basename of this path
|
|
@@ -10190,7 +10744,7 @@ var PathScurryBase = class {
|
|
|
10190
10744
|
const dirs = /* @__PURE__ */ new Set();
|
|
10191
10745
|
const queue = [entry];
|
|
10192
10746
|
let processing = 0;
|
|
10193
|
-
const
|
|
10747
|
+
const process3 = () => {
|
|
10194
10748
|
let paused = false;
|
|
10195
10749
|
while (!paused) {
|
|
10196
10750
|
const dir = queue.shift();
|
|
@@ -10231,9 +10785,9 @@ var PathScurryBase = class {
|
|
|
10231
10785
|
}
|
|
10232
10786
|
}
|
|
10233
10787
|
if (paused && !results.flowing) {
|
|
10234
|
-
results.once("drain",
|
|
10788
|
+
results.once("drain", process3);
|
|
10235
10789
|
} else if (!sync2) {
|
|
10236
|
-
|
|
10790
|
+
process3();
|
|
10237
10791
|
}
|
|
10238
10792
|
};
|
|
10239
10793
|
let sync2 = true;
|
|
@@ -10241,7 +10795,7 @@ var PathScurryBase = class {
|
|
|
10241
10795
|
sync2 = false;
|
|
10242
10796
|
}
|
|
10243
10797
|
};
|
|
10244
|
-
|
|
10798
|
+
process3();
|
|
10245
10799
|
return results;
|
|
10246
10800
|
}
|
|
10247
10801
|
streamSync(entry = this.cwd, opts = {}) {
|
|
@@ -10259,7 +10813,7 @@ var PathScurryBase = class {
|
|
|
10259
10813
|
}
|
|
10260
10814
|
const queue = [entry];
|
|
10261
10815
|
let processing = 0;
|
|
10262
|
-
const
|
|
10816
|
+
const process3 = () => {
|
|
10263
10817
|
let paused = false;
|
|
10264
10818
|
while (!paused) {
|
|
10265
10819
|
const dir = queue.shift();
|
|
@@ -10293,9 +10847,9 @@ var PathScurryBase = class {
|
|
|
10293
10847
|
}
|
|
10294
10848
|
}
|
|
10295
10849
|
if (paused && !results.flowing)
|
|
10296
|
-
results.once("drain",
|
|
10850
|
+
results.once("drain", process3);
|
|
10297
10851
|
};
|
|
10298
|
-
|
|
10852
|
+
process3();
|
|
10299
10853
|
return results;
|
|
10300
10854
|
}
|
|
10301
10855
|
chdir(path2 = this.cwd) {
|
|
@@ -11548,7 +12102,7 @@ async function analyzeComponentFile(filePath, _options = {}) {
|
|
|
11548
12102
|
});
|
|
11549
12103
|
return analysis;
|
|
11550
12104
|
}
|
|
11551
|
-
const content =
|
|
12105
|
+
const content = readFileSync5(resolve3(filePath), "utf-8");
|
|
11552
12106
|
analysis.size = Buffer.byteLength(content, "utf8");
|
|
11553
12107
|
analysis.lines = content.split("\n").length;
|
|
11554
12108
|
const syntaxAnalysis = analyzeSyntax(content, filePath);
|
|
@@ -11909,7 +12463,7 @@ async function analyzeHydration(options = {}) {
|
|
|
11909
12463
|
}
|
|
11910
12464
|
|
|
11911
12465
|
// src/validators/project-validator.js
|
|
11912
|
-
import { existsSync as existsSync9, readFileSync as
|
|
12466
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
11913
12467
|
import { resolve as resolve4 } from "path";
|
|
11914
12468
|
async function validateProject(_options = {}) {
|
|
11915
12469
|
const validation = {
|
|
@@ -11976,7 +12530,7 @@ function validatePackageJson() {
|
|
|
11976
12530
|
const issues = [];
|
|
11977
12531
|
const recommendations = [];
|
|
11978
12532
|
try {
|
|
11979
|
-
const packageJson = JSON.parse(
|
|
12533
|
+
const packageJson = JSON.parse(readFileSync6("package.json", "utf-8"));
|
|
11980
12534
|
const requiredFields = ["name", "version", "description"];
|
|
11981
12535
|
requiredFields.forEach((field) => {
|
|
11982
12536
|
const hasField = packageJson[field];
|
|
@@ -12132,7 +12686,7 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
|
|
|
12132
12686
|
});
|
|
12133
12687
|
if (!response.target) {
|
|
12134
12688
|
console.log(picocolors5.yellow("\u{1F44B} Debug cancelled"));
|
|
12135
|
-
|
|
12689
|
+
process2.exit(0);
|
|
12136
12690
|
}
|
|
12137
12691
|
debugTarget = response.target;
|
|
12138
12692
|
}
|
|
@@ -12174,14 +12728,14 @@ var debugCommand = new Command5("debug").description("Debug and analyze Coherent
|
|
|
12174
12728
|
console.log();
|
|
12175
12729
|
console.log(picocolors5.red("\u274C Debug Error:"));
|
|
12176
12730
|
console.log(picocolors5.gray(` ${error.message}`));
|
|
12177
|
-
if (
|
|
12731
|
+
if (env2.DEBUG) {
|
|
12178
12732
|
console.log();
|
|
12179
12733
|
console.log(picocolors5.gray("Stack trace:"));
|
|
12180
12734
|
console.log(picocolors5.gray(error.stack));
|
|
12181
12735
|
} else {
|
|
12182
12736
|
console.log(picocolors5.gray(" Run with DEBUG=1 for detailed error information"));
|
|
12183
12737
|
}
|
|
12184
|
-
|
|
12738
|
+
process2.exit(1);
|
|
12185
12739
|
}
|
|
12186
12740
|
});
|
|
12187
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) => {
|
|
@@ -12260,7 +12814,7 @@ async function analyzeConfiguration(_options = {}) {
|
|
|
12260
12814
|
};
|
|
12261
12815
|
if (existsSync10("package.json")) {
|
|
12262
12816
|
try {
|
|
12263
|
-
const packageJson = JSON.parse(
|
|
12817
|
+
const packageJson = JSON.parse(readFileSync7("package.json", "utf-8"));
|
|
12264
12818
|
const hasCoherentDeps = Object.keys(packageJson.dependencies || {}).some((dep) => dep.startsWith("@coherent.js/"));
|
|
12265
12819
|
if (!hasCoherentDeps) {
|
|
12266
12820
|
analysis.summary.issues.push("No Coherent.js dependencies found");
|
|
@@ -12369,12 +12923,12 @@ async function generateHTMLReport(result) {
|
|
|
12369
12923
|
<h1>\u{1F50D} Coherent.js Debug Report</h1>
|
|
12370
12924
|
<p>Generated: ${(/* @__PURE__ */ new Date()).toLocaleString()}</p>
|
|
12371
12925
|
</div>
|
|
12372
|
-
|
|
12926
|
+
|
|
12373
12927
|
<div class="section">
|
|
12374
12928
|
<h2>Summary</h2>
|
|
12375
12929
|
<pre>${JSON.stringify(result.summary, null, 2)}</pre>
|
|
12376
12930
|
</div>
|
|
12377
|
-
|
|
12931
|
+
|
|
12378
12932
|
${result.issues ? `
|
|
12379
12933
|
<div class="section">
|
|
12380
12934
|
<h2>Issues</h2>
|
|
@@ -12383,7 +12937,7 @@ async function generateHTMLReport(result) {
|
|
|
12383
12937
|
`).join("")}
|
|
12384
12938
|
</div>
|
|
12385
12939
|
` : ""}
|
|
12386
|
-
|
|
12940
|
+
|
|
12387
12941
|
${result.recommendations ? `
|
|
12388
12942
|
<div class="section">
|
|
12389
12943
|
<h2>Recommendations</h2>
|
|
@@ -12409,7 +12963,7 @@ var __dirname = dirname3(__filename);
|
|
|
12409
12963
|
var version = "1.0.1";
|
|
12410
12964
|
try {
|
|
12411
12965
|
const packagePath = join8(__dirname, "..", "package.json");
|
|
12412
|
-
const packageJson = JSON.parse(
|
|
12966
|
+
const packageJson = JSON.parse(readFileSync8(packagePath, "utf-8"));
|
|
12413
12967
|
version = packageJson.version;
|
|
12414
12968
|
} catch {
|
|
12415
12969
|
}
|