@coherent.js/cli 1.0.0-beta.2 → 1.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +4 -12
  2. package/dist/index.cjs +2101 -11612
  3. package/dist/index.js +582 -276
  4. package/package.json +3 -5
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // src/index.js
2
2
  import { Command as Command6 } from "commander";
3
- import { readFileSync as readFileSync6 } from "fs";
4
- import { fileURLToPath as fileURLToPath3 } from "url";
5
- import { dirname as dirname2, join as join7 } from "path";
3
+ import { readFileSync as readFileSync7 } from "fs";
4
+ import { fileURLToPath as fileURLToPath4 } from "url";
5
+ import { dirname as dirname3, join as join8 } from "path";
6
6
  import picocolors6 from "picocolors";
7
7
 
8
8
  // src/commands/create.js
@@ -15,18 +15,42 @@ import { resolve as resolve2 } from "path";
15
15
 
16
16
  // src/generators/project-scaffold.js
17
17
  import { writeFileSync, mkdirSync } from "node:fs";
18
- import { join, dirname } from "node:path";
18
+ import { join as join2, dirname as dirname2 } from "node:path";
19
19
  import { execSync } from "node:child_process";
20
20
 
21
+ // src/utils/version.js
22
+ import { readFileSync } from "fs";
23
+ import { join, dirname } from "path";
24
+ import { fileURLToPath } from "url";
25
+ var cachedVersion = null;
26
+ function getCLIVersion() {
27
+ if (cachedVersion) {
28
+ return cachedVersion;
29
+ }
30
+ try {
31
+ const __filename2 = fileURLToPath(import.meta.url);
32
+ const __dirname2 = dirname(__filename2);
33
+ const packagePath = join(__dirname2, "..", "..", "package.json");
34
+ const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
35
+ cachedVersion = packageJson.version;
36
+ return cachedVersion;
37
+ } catch {
38
+ cachedVersion = process.env.COHERENT_CLI_VERSION || "1.0.0-beta.3";
39
+ return cachedVersion;
40
+ }
41
+ }
42
+
21
43
  // src/generators/runtime-scaffold.js
44
+ var cliVersion = getCLIVersion();
22
45
  function generateBuiltInServer(options = {}) {
23
- const { port = 3e3, hasApi = false, hasDatabase = false } = options;
46
+ const { port = 3e3, hasApi = false, hasDatabase = false, hasAuth = false } = options;
24
47
  const imports = [
25
48
  `import http from 'http';`,
26
49
  `import { render } from '@coherent.js/core';`
27
50
  ];
28
51
  if (hasApi) imports.push(`import { setupRoutes } from './api/routes.js';`);
29
52
  if (hasDatabase) imports.push(`import { initDatabase } from './db/index.js';`);
53
+ if (hasAuth) imports.push(`import { setupAuthRoutes } from './api/auth.js';`);
30
54
  const server = `
31
55
  ${imports.join("\n")}
32
56
  import { HomePage } from './components/HomePage.js';
@@ -37,15 +61,21 @@ ${hasDatabase ? `// Initialize database
37
61
  await initDatabase();
38
62
  ` : ""}${hasApi ? `// Setup API routes
39
63
  const apiRoutes = setupRoutes();
64
+ ` : ""}${hasAuth ? `// Setup auth routes
65
+ const authRoutes = setupAuthRoutes();
40
66
  ` : ""}
41
67
  const server = http.createServer(async (req, res) => {
42
68
  const url = new URL(req.url, \`http://\${req.headers.host}\`);
43
69
 
44
- ${hasApi ? ` // Handle API routes
70
+ ${hasApi || hasAuth ? ` // Handle API routes
45
71
  if (url.pathname.startsWith('/api')) {
46
- const route = apiRoutes.find(r => r.path === url.pathname && r.method === req.method);
47
- if (route) {
48
- return route.handler(req, res);
72
+ const allRoutes = [...${hasApi ? "apiRoutes" : "[]"}, ...${hasAuth ? "authRoutes" : "[]"}];
73
+ for (const route of allRoutes) {
74
+ const match = matchRoute(route.path, url.pathname, req.method, route.method);
75
+ if (match) {
76
+ req.params = match.params;
77
+ return route.handler(req, res);
78
+ }
49
79
  }
50
80
  }
51
81
 
@@ -78,6 +108,42 @@ ${hasApi ? ` // Handle API routes
78
108
  }
79
109
  });
80
110
 
111
+ // Route matching helper
112
+ function matchRoute(routePattern, urlPath, requestMethod, routeMethod) {
113
+ // Check HTTP method
114
+ if (requestMethod !== routeMethod) {
115
+ return null;
116
+ }
117
+
118
+ // Split paths into segments
119
+ const routeSegments = routePattern.split('/').filter(Boolean);
120
+ const urlSegments = urlPath.split('/').filter(Boolean);
121
+
122
+ // Check if lengths match
123
+ if (routeSegments.length !== urlSegments.length) {
124
+ return null;
125
+ }
126
+
127
+ const params = {};
128
+
129
+ // Match each segment
130
+ for (let i = 0; i < routeSegments.length; i++) {
131
+ const routeSegment = routeSegments[i];
132
+ const urlSegment = urlSegments[i];
133
+
134
+ // Check for parameter (e.g., :id)
135
+ if (routeSegment.startsWith(':')) {
136
+ const paramName = routeSegment.substring(1);
137
+ params[paramName] = urlSegment;
138
+ } else if (routeSegment !== urlSegment) {
139
+ // Literal segment doesn't match
140
+ return null;
141
+ }
142
+ }
143
+
144
+ return { params };
145
+ }
146
+
81
147
  server.listen(PORT, () => {
82
148
  console.log(\`Server running at http://localhost:\${PORT}\`);
83
149
  });
@@ -239,20 +305,20 @@ function getRuntimeDependencies(runtime) {
239
305
  const deps = {
240
306
  "built-in": {},
241
307
  express: {
242
- express: "^4.18.2",
243
- "@coherent.js/express": "1.0.0-beta.1"
308
+ express: "^4.19.2",
309
+ "@coherent.js/express": `^${cliVersion}`
244
310
  },
245
311
  fastify: {
246
312
  fastify: "^4.28.1",
247
313
  "@fastify/static": "^7.0.4",
248
- "@coherent.js/fastify": "1.0.0-beta.1"
314
+ "@coherent.js/fastify": `^${cliVersion}`
249
315
  },
250
316
  koa: {
251
317
  koa: "^2.15.3",
252
318
  "@koa/router": "^13.0.1",
253
319
  "koa-body": "^6.0.1",
254
320
  "koa-static": "^5.0.0",
255
- "@coherent.js/koa": "1.0.0-beta.1"
321
+ "@coherent.js/koa": `^${cliVersion}`
256
322
  }
257
323
  };
258
324
  return deps[runtime] || {};
@@ -273,6 +339,7 @@ function generateServerFile(runtime, options = {}) {
273
339
  }
274
340
 
275
341
  // src/generators/database-scaffold.js
342
+ var cliVersion2 = getCLIVersion();
276
343
  function generateDatabaseConfig(dbType) {
277
344
  const configs = {
278
345
  postgres: `
@@ -493,7 +560,7 @@ process.on('SIGINT', async () => {
493
560
  function generateExampleModel(dbType) {
494
561
  const models = {
495
562
  postgres: `
496
- import { getDatabase } from './index.js';
563
+ import { getDatabase } from '../index.js';
497
564
 
498
565
  export class UserModel {
499
566
  static async createTable() {
@@ -546,7 +613,7 @@ export class UserModel {
546
613
  }
547
614
  `,
548
615
  mysql: `
549
- import { getDatabase } from './index.js';
616
+ import { getDatabase } from '../index.js';
550
617
 
551
618
  export class UserModel {
552
619
  static async createTable() {
@@ -599,7 +666,7 @@ export class UserModel {
599
666
  }
600
667
  `,
601
668
  sqlite: `
602
- import { getDatabase } from './index.js';
669
+ import { getDatabase } from '../index.js';
603
670
 
604
671
  export class UserModel {
605
672
  static createTable() {
@@ -649,7 +716,7 @@ export class UserModel {
649
716
  }
650
717
  `,
651
718
  mongodb: `
652
- import { getDatabase } from './index.js';
719
+ import { getDatabase } from '../index.js';
653
720
 
654
721
  export class UserModel {
655
722
  static collectionName = 'users';
@@ -738,19 +805,19 @@ function getDatabaseDependencies(dbType) {
738
805
  const deps = {
739
806
  postgres: {
740
807
  pg: "^8.12.0",
741
- "@coherent.js/database": "^1.0.1"
808
+ "@coherent.js/database": `^${cliVersion2}`
742
809
  },
743
810
  mysql: {
744
811
  "mysql2": "^3.11.0",
745
- "@coherent.js/database": "^1.0.1"
812
+ "@coherent.js/database": `^${cliVersion2}`
746
813
  },
747
814
  sqlite: {
748
815
  "better-sqlite3": "^11.3.0",
749
- "@coherent.js/database": "^1.0.1"
816
+ "@coherent.js/database": `^${cliVersion2}`
750
817
  },
751
818
  mongodb: {
752
819
  mongodb: "^6.9.0",
753
- "@coherent.js/database": "^1.0.1"
820
+ "@coherent.js/database": `^${cliVersion2}`
754
821
  }
755
822
  };
756
823
  return deps[dbType] || {};
@@ -1132,6 +1199,158 @@ router.get('/me', authMiddleware, async (req, res) => {
1132
1199
  });
1133
1200
 
1134
1201
  export default router;
1202
+ `,
1203
+ "built-in": `
1204
+ // Auth routes for built-in HTTP server
1205
+ import { generateToken, verifyToken } from '../middleware/auth.js';
1206
+ import { UserModel } from '../db/models/User.js';
1207
+
1208
+ // Register handler
1209
+ export async function registerHandler(req, res) {
1210
+ try {
1211
+ // Parse JSON body
1212
+ let body = '';
1213
+ req.on('data', chunk => {
1214
+ body += chunk.toString();
1215
+ });
1216
+
1217
+ req.on('end', async () => {
1218
+ try {
1219
+ const { email, name, password } = JSON.parse(body);
1220
+
1221
+ // Validate input
1222
+ if (!email || !name || !password) {
1223
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1224
+ return res.end(JSON.stringify({ error: 'Missing required fields' }));
1225
+ }
1226
+
1227
+ // Check if user exists
1228
+ const existingUser = await UserModel.findByEmail(email);
1229
+ if (existingUser) {
1230
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1231
+ return res.end(JSON.stringify({ error: 'User already exists' }));
1232
+ }
1233
+
1234
+ // Create user (you should hash the password!)
1235
+ const user = await UserModel.create({ email, name });
1236
+
1237
+ // Generate token
1238
+ const token = generateToken({ id: user.id, email: user.email });
1239
+
1240
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1241
+ res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name }, token }));
1242
+ } catch (error) {
1243
+ console.error('Register error:', error);
1244
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1245
+ res.end(JSON.stringify({ error: 'Registration failed' }));
1246
+ }
1247
+ });
1248
+ } catch (error) {
1249
+ console.error('Register error:', error);
1250
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1251
+ res.end(JSON.stringify({ error: 'Registration failed' }));
1252
+ }
1253
+ }
1254
+
1255
+ // Login handler
1256
+ export async function loginHandler(req, res) {
1257
+ try {
1258
+ // Parse JSON body
1259
+ let body = '';
1260
+ req.on('data', chunk => {
1261
+ body += chunk.toString();
1262
+ });
1263
+
1264
+ req.on('end', async () => {
1265
+ try {
1266
+ const { email, password } = JSON.parse(body);
1267
+
1268
+ // Validate input
1269
+ if (!email || !password) {
1270
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1271
+ return res.end(JSON.stringify({ error: 'Missing required fields' }));
1272
+ }
1273
+
1274
+ // Find user
1275
+ const user = await UserModel.findByEmail(email);
1276
+ if (!user) {
1277
+ res.writeHead(401, { 'Content-Type': 'application/json' });
1278
+ return res.end(JSON.stringify({ error: 'Invalid credentials' }));
1279
+ }
1280
+
1281
+ // Verify password (you should implement proper password checking!)
1282
+
1283
+ // Generate token
1284
+ const token = generateToken({ id: user.id, email: user.email });
1285
+
1286
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1287
+ res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name }, token }));
1288
+ } catch (error) {
1289
+ console.error('Login error:', error);
1290
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1291
+ res.end(JSON.stringify({ error: 'Login failed' }));
1292
+ }
1293
+ });
1294
+ } catch (error) {
1295
+ console.error('Login error:', error);
1296
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1297
+ res.end(JSON.stringify({ error: 'Login failed' }));
1298
+ }
1299
+ }
1300
+
1301
+ // Get current user handler
1302
+ export async function meHandler(req, res) {
1303
+ try {
1304
+ // Verify token from Authorization header
1305
+ const authHeader = req.headers.authorization;
1306
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
1307
+ res.writeHead(401, { 'Content-Type': 'application/json' });
1308
+ return res.end(JSON.stringify({ error: 'No token provided' }));
1309
+ }
1310
+
1311
+ const token = authHeader.substring(7);
1312
+ const decoded = verifyToken(token);
1313
+
1314
+ if (!decoded) {
1315
+ res.writeHead(401, { 'Content-Type': 'application/json' });
1316
+ return res.end(JSON.stringify({ error: 'Invalid or expired token' }));
1317
+ }
1318
+
1319
+ const user = await UserModel.findById(decoded.id);
1320
+ if (!user) {
1321
+ res.writeHead(404, { 'Content-Type': 'application/json' });
1322
+ return res.end(JSON.stringify({ error: 'User not found' }));
1323
+ }
1324
+
1325
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1326
+ res.end(JSON.stringify({ user: { id: user.id, email: user.email, name: user.name } }));
1327
+ } catch (error) {
1328
+ console.error('Get user error:', error);
1329
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1330
+ res.end(JSON.stringify({ error: 'Failed to get user' }));
1331
+ }
1332
+ }
1333
+
1334
+ // For built-in HTTP server compatibility
1335
+ export function setupAuthRoutes() {
1336
+ return [
1337
+ {
1338
+ path: '/api/auth/register',
1339
+ method: 'POST',
1340
+ handler: registerHandler
1341
+ },
1342
+ {
1343
+ path: '/api/auth/login',
1344
+ method: 'POST',
1345
+ handler: loginHandler
1346
+ },
1347
+ {
1348
+ path: '/api/auth/me',
1349
+ method: 'GET',
1350
+ handler: meHandler
1351
+ }
1352
+ ];
1353
+ }
1135
1354
  `,
1136
1355
  fastify: `
1137
1356
  import { generateToken } from '../plugins/auth.js';
@@ -1448,6 +1667,7 @@ function generateAuthScaffolding(authType, runtime) {
1448
1667
  }
1449
1668
 
1450
1669
  // src/generators/package-scaffold.js
1670
+ var cliVersion3 = getCLIVersion();
1451
1671
  function generateApiScaffolding() {
1452
1672
  const routes = `
1453
1673
  import { createRouter } from '@coherent.js/api';
@@ -1479,12 +1699,79 @@ router.post('/users', {
1479
1699
  }
1480
1700
  });
1481
1701
 
1702
+ // Handler for GET /api/users/:id
1703
+ export async function getUsersByIdHandler(req, res) {
1704
+ try {
1705
+ // Extract ID from URL parameters
1706
+ const { id } = req.params;
1707
+
1708
+ // Call the original handler
1709
+ const result = await router.handle('GET', '/users/:id', { params: { id } }, {});
1710
+
1711
+ // Send JSON response
1712
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1713
+ res.end(JSON.stringify(result));
1714
+ } catch (error) {
1715
+ console.error('API Error:', error);
1716
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1717
+ res.end(JSON.stringify({ error: 'Internal server error' }));
1718
+ }
1719
+ }
1720
+
1721
+ // Handler for POST /api/users
1722
+ export async function postUsersHandler(req, res) {
1723
+ try {
1724
+ // Parse JSON body
1725
+ let body = '';
1726
+ req.on('data', chunk => {
1727
+ body += chunk.toString();
1728
+ });
1729
+
1730
+ req.on('end', async () => {
1731
+ try {
1732
+ const parsedBody = JSON.parse(body);
1733
+
1734
+ // Call the original handler
1735
+ const result = await router.handle('POST', '/users', { body: parsedBody }, {});
1736
+
1737
+ // Send JSON response
1738
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1739
+ res.end(JSON.stringify(result));
1740
+ } catch (error) {
1741
+ console.error('API Error:', error);
1742
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1743
+ res.end(JSON.stringify({ error: 'Internal server error' }));
1744
+ }
1745
+ });
1746
+ } catch (error) {
1747
+ console.error('API Error:', error);
1748
+ res.writeHead(500, { 'Content-Type': 'application/json' });
1749
+ res.end(JSON.stringify({ error: 'Internal server error' }));
1750
+ }
1751
+ }
1752
+
1753
+ // For built-in HTTP server compatibility
1754
+ export function setupRoutes() {
1755
+ return [
1756
+ {
1757
+ path: '/api/users/:id',
1758
+ method: 'GET',
1759
+ handler: getUsersByIdHandler
1760
+ },
1761
+ {
1762
+ path: '/api/users',
1763
+ method: 'POST',
1764
+ handler: postUsersHandler
1765
+ }
1766
+ ];
1767
+ }
1768
+
1482
1769
  export default router;
1483
1770
  `;
1484
1771
  return {
1485
1772
  "src/api/routes.js": routes,
1486
1773
  dependencies: {
1487
- "@coherent.js/api": "^1.0.0"
1774
+ "@coherent.js/api": `^${cliVersion3}`
1488
1775
  }
1489
1776
  };
1490
1777
  }
@@ -1573,7 +1860,7 @@ if (typeof window !== 'undefined') {
1573
1860
  "public/js/hydration.js": hydration,
1574
1861
  "src/components/InteractiveCounter.js": interactiveExample,
1575
1862
  dependencies: {
1576
- "@coherent.js/client": "^1.0.0"
1863
+ "@coherent.js/client": `^${cliVersion3}`
1577
1864
  }
1578
1865
  };
1579
1866
  }
@@ -1634,7 +1921,7 @@ export const i18n = createI18n({
1634
1921
  "src/i18n/locales/fr.json": frLocale,
1635
1922
  "src/i18n/locales/es.json": esLocale,
1636
1923
  dependencies: {
1637
- "@coherent.js/i18n": "^1.0.0"
1924
+ "@coherent.js/i18n": `^${cliVersion3}`
1638
1925
  }
1639
1926
  };
1640
1927
  }
@@ -1692,7 +1979,7 @@ export function ContactForm(props = {}) {
1692
1979
  return {
1693
1980
  "src/components/ContactForm.js": exampleForm,
1694
1981
  dependencies: {
1695
- "@coherent.js/forms": "^1.0.0"
1982
+ "@coherent.js/forms": `^${cliVersion3}`
1696
1983
  }
1697
1984
  };
1698
1985
  }
@@ -1720,7 +2007,7 @@ export function initDevtools(app) {
1720
2007
  return {
1721
2008
  "src/utils/devtools.js": config,
1722
2009
  dependencies: {
1723
- "@coherent.js/devtools": "^1.0.0"
2010
+ "@coherent.js/devtools": `^${cliVersion3}`
1724
2011
  }
1725
2012
  };
1726
2013
  }
@@ -1769,7 +2056,7 @@ export function getSitemap() {
1769
2056
  return {
1770
2057
  "src/utils/seo.js": metaHelper,
1771
2058
  dependencies: {
1772
- "@coherent.js/seo": "^1.0.0"
2059
+ "@coherent.js/seo": `^${cliVersion3}`
1773
2060
  }
1774
2061
  };
1775
2062
  }
@@ -1837,7 +2124,7 @@ describe('HomePage', () => {
1837
2124
  "tests/helpers/testing.js": testHelper,
1838
2125
  "tests/components/HomePage.test.js": exampleTest,
1839
2126
  dependencies: {
1840
- "@coherent.js/testing": "^1.0.0"
2127
+ "@coherent.js/testing": `^${cliVersion3}`
1841
2128
  }
1842
2129
  };
1843
2130
  }
@@ -1972,6 +2259,7 @@ function getTypeScriptDependencies() {
1972
2259
  }
1973
2260
 
1974
2261
  // src/generators/project-scaffold.js
2262
+ var cliVersion4 = getCLIVersion();
1975
2263
  async function scaffoldProject(projectPath, options) {
1976
2264
  const {
1977
2265
  name,
@@ -2012,16 +2300,16 @@ async function scaffoldProject(projectPath, options) {
2012
2300
  dirs.push("src/i18n", "src/i18n/locales");
2013
2301
  }
2014
2302
  dirs.forEach((dir) => {
2015
- mkdirSync(join(projectPath, dir), { recursive: true });
2303
+ mkdirSync(join2(projectPath, dir), { recursive: true });
2016
2304
  });
2017
2305
  const packageJson = generatePackageJson(name, { template, runtime, database, auth, packages, language, packageManager });
2018
- writeFileSync(join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
2306
+ writeFileSync(join2(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
2019
2307
  if (isTypeScript) {
2020
2308
  const tsConfig = generateTsConfig();
2021
- writeFileSync(join(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
2309
+ writeFileSync(join2(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
2022
2310
  } else {
2023
2311
  const jsConfig = generateJsConfig();
2024
- writeFileSync(join(projectPath, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
2312
+ writeFileSync(join2(projectPath, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
2025
2313
  }
2026
2314
  const serverContent = generateServerFile(runtime, {
2027
2315
  port: 3e3,
@@ -2029,30 +2317,30 @@ async function scaffoldProject(projectPath, options) {
2029
2317
  hasDatabase: !!database,
2030
2318
  hasAuth: !!auth
2031
2319
  });
2032
- writeFileSync(join(projectPath, `src/index${fileExtension}`), serverContent);
2320
+ writeFileSync(join2(projectPath, `src/index${fileExtension}`), serverContent);
2033
2321
  await generateHomePageComponent(projectPath, name, isTypeScript, fileExtension);
2034
2322
  if (database) {
2035
2323
  const dbScaffolding = generateDatabaseScaffolding(database);
2036
- writeFileSync(join(projectPath, "src/db/config.js"), dbScaffolding.config);
2037
- writeFileSync(join(projectPath, "src/db/index.js"), dbScaffolding.init);
2038
- writeFileSync(join(projectPath, "src/db/models/User.js"), dbScaffolding.model);
2324
+ writeFileSync(join2(projectPath, "src/db/config.js"), dbScaffolding.config);
2325
+ writeFileSync(join2(projectPath, "src/db/index.js"), dbScaffolding.init);
2326
+ writeFileSync(join2(projectPath, "src/db/models/User.js"), dbScaffolding.model);
2039
2327
  const existingEnv = "";
2040
- writeFileSync(join(projectPath, ".env.example"), existingEnv + dbScaffolding.env);
2328
+ writeFileSync(join2(projectPath, ".env.example"), existingEnv + dbScaffolding.env);
2041
2329
  }
2042
2330
  if (auth) {
2043
2331
  const authScaffolding = generateAuthScaffolding(auth, runtime);
2044
2332
  const authDir = runtime === "fastify" ? "plugins" : "middleware";
2045
- writeFileSync(join(projectPath, `src/${authDir}/auth.js`), authScaffolding.middleware);
2046
- writeFileSync(join(projectPath, "src/api/auth.js"), authScaffolding.routes);
2047
- const envPath = join(projectPath, ".env.example");
2333
+ writeFileSync(join2(projectPath, `src/${authDir}/auth.js`), authScaffolding.middleware);
2334
+ writeFileSync(join2(projectPath, "src/api/auth.js"), authScaffolding.routes);
2335
+ const envPath = join2(projectPath, ".env.example");
2048
2336
  const existingEnv = "";
2049
2337
  writeFileSync(envPath, existingEnv + authScaffolding.env);
2050
2338
  }
2051
2339
  if (packages.length > 0) {
2052
2340
  const { files } = generatePackageScaffolding(packages);
2053
2341
  Object.entries(files).forEach(([filePath, content]) => {
2054
- const fullPath = join(projectPath, filePath);
2055
- mkdirSync(dirname(fullPath), { recursive: true });
2342
+ const fullPath = join2(projectPath, filePath);
2343
+ mkdirSync(dirname2(fullPath), { recursive: true });
2056
2344
  writeFileSync(fullPath, content);
2057
2345
  });
2058
2346
  }
@@ -2107,10 +2395,10 @@ function generatePackageJson(name, options) {
2107
2395
  test: "node --test tests/*.test.js"
2108
2396
  },
2109
2397
  dependencies: {
2110
- "@coherent.js/core": "^1.0.0-beta.1"
2398
+ "@coherent.js/core": `^${cliVersion4}`
2111
2399
  },
2112
2400
  devDependencies: {
2113
- "@coherent.js/cli": "^1.0.0-beta.1"
2401
+ "@coherent.js/cli": `^${cliVersion4}`
2114
2402
  }
2115
2403
  };
2116
2404
  if (isTypeScript) {
@@ -2222,7 +2510,7 @@ export function HomePage(props = {}) {
2222
2510
  };
2223
2511
  }
2224
2512
  `;
2225
- writeFileSync(join(projectPath, `src/components/HomePage${fileExtension}`), homePage);
2513
+ writeFileSync(join2(projectPath, `src/components/HomePage${fileExtension}`), homePage);
2226
2514
  const buttonComponent = isTypeScript ? `/**
2227
2515
  * Button Component
2228
2516
  */
@@ -2258,7 +2546,7 @@ export function Button(props = {}) {
2258
2546
  };
2259
2547
  }
2260
2548
  `;
2261
- writeFileSync(join(projectPath, `src/components/Button${fileExtension}`), buttonComponent);
2549
+ writeFileSync(join2(projectPath, `src/components/Button${fileExtension}`), buttonComponent);
2262
2550
  }
2263
2551
  function generateCommonFiles(projectPath, name) {
2264
2552
  const readme = `# ${name}
@@ -2269,16 +2557,16 @@ A Coherent.js application built with pure JavaScript objects.
2269
2557
 
2270
2558
  \`\`\`bash
2271
2559
  # Install dependencies
2272
- npm install
2560
+ pnpm install
2273
2561
 
2274
2562
  # Start development server
2275
- npm run dev
2563
+ pnpm run dev
2276
2564
 
2277
2565
  # Build for production
2278
- npm run build
2566
+ pnpm run build
2279
2567
 
2280
2568
  # Run tests
2281
- npm test
2569
+ pnpm test
2282
2570
  \`\`\`
2283
2571
 
2284
2572
  ## Project Structure
@@ -2297,13 +2585,13 @@ tests/ # Test files
2297
2585
  ## Learn More
2298
2586
 
2299
2587
  - [Coherent.js Documentation](https://github.com/Tomdrouv1/coherent.js)
2300
- - [API Reference](https://github.com/Tomdrouv1/coherent.js/docs/api-reference.md)
2588
+ - [API Reference](https://github.com/Tomdrouv1/coherent.js/tree/main/docs/api-reference.md)
2301
2589
 
2302
2590
  ## License
2303
2591
 
2304
2592
  MIT
2305
2593
  `;
2306
- writeFileSync(join(projectPath, "README.md"), readme);
2594
+ writeFileSync(join2(projectPath, "README.md"), readme);
2307
2595
  const gitignore = `# Dependencies
2308
2596
  node_modules/
2309
2597
  npm-debug.log*
@@ -2360,23 +2648,23 @@ logs
2360
2648
  # Optional REPL history
2361
2649
  .node_repl_history
2362
2650
  `;
2363
- writeFileSync(join(projectPath, ".gitignore"), gitignore);
2364
- const testFile = `import { test } from 'node:test';
2365
- import assert from 'node:assert';
2651
+ writeFileSync(join2(projectPath, ".gitignore"), gitignore);
2652
+ const testFile = `import { describe, it, expect } from 'vitest';
2366
2653
  import { render } from '@coherent.js/core';
2367
2654
 
2368
- test('renders basic component', () => {
2369
- const component = {
2370
- div: {
2371
- text: 'Hello, World!'
2372
- }
2373
- };
2655
+ describe('Basic Component Rendering', () => {
2656
+ it('renders basic component', () => {
2657
+ const component = {
2658
+ div: {
2659
+ text: 'Hello, World!'
2660
+ }
2661
+ };
2374
2662
 
2375
- const html = render(component);
2376
- assert(html.includes('Hello, World!'));
2377
- });
2378
- `;
2379
- writeFileSync(join(projectPath, "tests/basic.test.js"), testFile);
2663
+ const html = render(component);
2664
+ expect(html).toContain('Hello, World!');
2665
+ });
2666
+ });`;
2667
+ writeFileSync(join2(projectPath, "tests/basic.test.js"), testFile);
2380
2668
  }
2381
2669
 
2382
2670
  // src/utils/validation.js
@@ -2699,29 +2987,29 @@ import picocolors2 from "picocolors";
2699
2987
 
2700
2988
  // src/generators/component-generator.js
2701
2989
  import { writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
2702
- import { join as join2 } from "path";
2990
+ import { join as join3 } from "path";
2703
2991
  async function generateComponent(name, options = {}) {
2704
2992
  const { path: path2 = "src/components", template = "basic", skipTest = false, skipStory = false } = options;
2705
2993
  const componentName = toPascalCase(name);
2706
2994
  const fileName = componentName;
2707
- const outputDir = join2(process.cwd(), path2);
2995
+ const outputDir = join3(process.cwd(), path2);
2708
2996
  if (!existsSync3(outputDir)) {
2709
2997
  mkdirSync3(outputDir, { recursive: true });
2710
2998
  }
2711
2999
  const files = [];
2712
3000
  const nextSteps = [];
2713
- const componentPath = join2(outputDir, `${fileName}.js`);
3001
+ const componentPath = join3(outputDir, `${fileName}.js`);
2714
3002
  const componentContent = generateComponentContent(componentName, template);
2715
3003
  writeFileSync2(componentPath, componentContent);
2716
3004
  files.push(componentPath);
2717
3005
  if (!skipTest) {
2718
- const testPath = join2(outputDir, `${fileName}.test.js`);
3006
+ const testPath = join3(outputDir, `${fileName}.test.js`);
2719
3007
  const testContent = generateTestContent(componentName);
2720
3008
  writeFileSync2(testPath, testContent);
2721
3009
  files.push(testPath);
2722
3010
  }
2723
3011
  if (!skipStory) {
2724
- const storyPath = join2(outputDir, `${fileName}.stories.js`);
3012
+ const storyPath = join3(outputDir, `${fileName}.stories.js`);
2725
3013
  const storyContent = generateStoryContent(componentName);
2726
3014
  writeFileSync2(storyPath, storyContent);
2727
3015
  files.push(storyPath);
@@ -2750,7 +3038,7 @@ function generateBasicComponent(name) {
2750
3038
 
2751
3039
  /**
2752
3040
  * ${name} component
2753
- *
3041
+ *
2754
3042
  * @param {Object} props - Component properties
2755
3043
  * @param {string} props.className - CSS class name
2756
3044
  * @param {Array|Object} props.children - Child elements
@@ -2777,7 +3065,7 @@ function generateFunctionalComponent(name) {
2777
3065
 
2778
3066
  /**
2779
3067
  * ${name} - Functional component with business logic
2780
- *
3068
+ *
2781
3069
  * @param {Object} props - Component properties
2782
3070
  * @param {Array} props.items - Items to display
2783
3071
  * @param {Function} props.onItemClick - Callback for item clicks
@@ -2795,11 +3083,11 @@ export const ${name} = createComponent(({ items = [], onItemClick, className = '
2795
3083
  div: {
2796
3084
  className: \`${name.toLowerCase()} \${className}\`.trim(),
2797
3085
  children: [
2798
- {
2799
- h3: {
3086
+ {
3087
+ h3: {
2800
3088
  className: '${name.toLowerCase()}__title',
2801
- text: '${name}'
2802
- }
3089
+ text: '${name}'
3090
+ }
2803
3091
  },
2804
3092
  {
2805
3093
  ul: {
@@ -2842,17 +3130,17 @@ function generateInteractiveComponent(name) {
2842
3130
 
2843
3131
  /**
2844
3132
  * ${name} - Interactive component with state management
2845
- *
3133
+ *
2846
3134
  * @param {Object} props - Component properties
2847
3135
  * @param {*} props.initialValue - Initial value
2848
3136
  * @param {Function} props.onChange - Change callback
2849
3137
  * @param {string} props.className - CSS class name
2850
3138
  */
2851
- export const ${name} = createComponent(({
2852
- initialValue = '',
3139
+ export const ${name} = createComponent(({
3140
+ initialValue = '',
2853
3141
  onChange,
2854
3142
  className = '',
2855
- ...props
3143
+ ...props
2856
3144
  }) => {
2857
3145
  // Component state (handled by Coherent.js hydration)
2858
3146
  const state = {
@@ -2929,7 +3217,7 @@ function generateLayoutComponent(name) {
2929
3217
 
2930
3218
  /**
2931
3219
  * ${name} - Layout component for page structure
2932
- *
3220
+ *
2933
3221
  * @param {Object} props - Component properties
2934
3222
  * @param {string} props.title - Page title
2935
3223
  * @param {Array|Object} props.children - Child content
@@ -2937,7 +3225,7 @@ function generateLayoutComponent(name) {
2937
3225
  * @param {Object} props.footer - Footer content
2938
3226
  * @param {string} props.className - CSS class name
2939
3227
  */
2940
- export const ${name} = createComponent(({
3228
+ export const ${name} = createComponent(({
2941
3229
  title = 'Page Title',
2942
3230
  children = [],
2943
3231
  header = null,
@@ -3011,38 +3299,39 @@ export const ${name} = createComponent(({
3011
3299
  `;
3012
3300
  }
3013
3301
  function generateTestContent(name) {
3014
- return `import { test } from 'node:test';
3015
- import assert from 'node:assert';
3302
+ return `import { describe, it, expect } from 'vitest';
3016
3303
  import { render } from '@coherent.js/core';
3017
3304
  import { ${name} } from './${name}.js';
3018
3305
 
3019
- test('${name} renders correctly', () => {
3020
- const component = ${name}({});
3021
- const html = render(component);
3022
-
3023
- assert(typeof html === 'string');
3024
- assert(html.length > 0);
3025
- assert(html.includes('${name.toLowerCase()}'));
3026
- });
3306
+ describe('${name}', () => {
3307
+ it('renders correctly', () => {
3308
+ const component = ${name}({});
3309
+ const html = render(component);
3027
3310
 
3028
- test('${name} accepts className prop', () => {
3029
- const component = ${name}({ className: 'test-class' });
3030
- const html = render(component);
3031
-
3032
- assert(html.includes('test-class'));
3033
- });
3311
+ expect(typeof html).toBe('string');
3312
+ expect(html.length).toBeGreaterThan(0);
3313
+ expect(html).toContain('${name.toLowerCase()}');
3314
+ });
3034
3315
 
3035
- test('${name} renders children correctly', () => {
3036
- const children = [
3037
- { p: { text: 'Test child content' } }
3038
- ];
3039
-
3040
- const component = ${name}({ children });
3041
- const html = render(component);
3042
-
3043
- assert(html.includes('Test child content'));
3316
+ it('accepts className prop', () => {
3317
+ const component = ${name}({ className: 'test-class' });
3318
+ const html = render(component);
3319
+
3320
+ expect(html).toContain('test-class');
3321
+ });
3044
3322
  });
3045
- `;
3323
+
3324
+ it('renders children correctly', () => {
3325
+ const children = [
3326
+ { p: { text: 'Test child content' } }
3327
+ ];
3328
+
3329
+ const component = ${name}({ children });
3330
+ const html = render(component);
3331
+
3332
+ expect(html).toContain('Test child content');
3333
+ });
3334
+ });`;
3046
3335
  }
3047
3336
  function generateStoryContent(name) {
3048
3337
  return `import { ${name} } from './${name}.js';
@@ -3085,23 +3374,23 @@ function toPascalCase(str) {
3085
3374
 
3086
3375
  // src/generators/page-generator.js
3087
3376
  import { writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync4 } from "fs";
3088
- import { join as join3 } from "path";
3377
+ import { join as join4 } from "path";
3089
3378
  async function generatePage(name, options = {}) {
3090
3379
  const { path: path2 = "src/pages", template = "basic", skipTest = false } = options;
3091
3380
  const pageName = toPascalCase2(name);
3092
3381
  const fileName = pageName;
3093
- const outputDir = join3(process.cwd(), path2);
3382
+ const outputDir = join4(process.cwd(), path2);
3094
3383
  if (!existsSync4(outputDir)) {
3095
3384
  mkdirSync4(outputDir, { recursive: true });
3096
3385
  }
3097
3386
  const files = [];
3098
3387
  const nextSteps = [];
3099
- const pagePath = join3(outputDir, `${fileName}.js`);
3388
+ const pagePath = join4(outputDir, `${fileName}.js`);
3100
3389
  const pageContent = generatePageContent(pageName, template);
3101
3390
  writeFileSync3(pagePath, pageContent);
3102
3391
  files.push(pagePath);
3103
3392
  if (!skipTest) {
3104
- const testPath = join3(outputDir, `${fileName}.test.js`);
3393
+ const testPath = join4(outputDir, `${fileName}.test.js`);
3105
3394
  const testContent = generateTestContent2(pageName);
3106
3395
  writeFileSync3(testPath, testContent);
3107
3396
  files.push(testPath);
@@ -3135,7 +3424,7 @@ function generateBasicPage(name) {
3135
3424
  /**
3136
3425
  * ${name} Page Component
3137
3426
  * Route: /${routeName}
3138
- *
3427
+ *
3139
3428
  * @param {Object} props - Page properties
3140
3429
  * @param {Object} props.params - Route parameters
3141
3430
  * @param {Object} props.query - Query parameters
@@ -3153,17 +3442,17 @@ export const ${name} = createComponent(({ params = {}, query = {}, request, ...p
3153
3442
  head: {
3154
3443
  children: [
3155
3444
  { title: { text: pageTitle } },
3156
- {
3157
- meta: {
3445
+ {
3446
+ meta: {
3158
3447
  name: 'description',
3159
3448
  content: pageDescription
3160
- }
3449
+ }
3161
3450
  },
3162
- {
3163
- meta: {
3164
- name: 'viewport',
3165
- content: 'width=device-width, initial-scale=1.0'
3166
- }
3451
+ {
3452
+ meta: {
3453
+ name: 'viewport',
3454
+ content: 'width=device-width, initial-scale=1.0'
3455
+ }
3167
3456
  }
3168
3457
  ]
3169
3458
  }
@@ -3274,10 +3563,10 @@ ${name}.description = '${name} page description';
3274
3563
 
3275
3564
  // Usage in router:
3276
3565
  // app.get('/${routeName}', (req, res) => {
3277
- // const html = render(${name}({
3278
- // params: req.params,
3566
+ // const html = render(${name}({
3567
+ // params: req.params,
3279
3568
  // query: req.query,
3280
- // request: req
3569
+ // request: req
3281
3570
  // }));
3282
3571
  // res.send(html);
3283
3572
  // });
@@ -3305,11 +3594,11 @@ export const ${name} = createComponent(({ stats = {}, user = null }) => {
3305
3594
  head: {
3306
3595
  children: [
3307
3596
  { title: { text: '${name} Dashboard' } },
3308
- {
3309
- meta: {
3310
- name: 'viewport',
3311
- content: 'width=device-width, initial-scale=1.0'
3312
- }
3597
+ {
3598
+ meta: {
3599
+ name: 'viewport',
3600
+ content: 'width=device-width, initial-scale=1.0'
3601
+ }
3313
3602
  }
3314
3603
  ]
3315
3604
  }
@@ -3460,11 +3749,11 @@ export const ${name} = createComponent(({ initialData = {}, errors = {} }) => {
3460
3749
  head: {
3461
3750
  children: [
3462
3751
  { title: { text: '${name} Form' } },
3463
- {
3464
- meta: {
3465
- name: 'viewport',
3466
- content: 'width=device-width, initial-scale=1.0'
3467
- }
3752
+ {
3753
+ meta: {
3754
+ name: 'viewport',
3755
+ content: 'width=device-width, initial-scale=1.0'
3756
+ }
3468
3757
  }
3469
3758
  ]
3470
3759
  }
@@ -3604,42 +3893,42 @@ export const ${name} = createComponent(({ initialData = {}, errors = {} }) => {
3604
3893
  `;
3605
3894
  }
3606
3895
  function generateTestContent2(name) {
3607
- return `import { test } from 'node:test';
3608
- import assert from 'node:assert';
3896
+ return `import { describe, it, expect } from 'vitest';
3609
3897
  import { render } from '@coherent.js/core';
3610
3898
  import { ${name} } from './${name}.js';
3611
3899
 
3612
- test('${name} page renders correctly', () => {
3613
- const page = ${name}({});
3614
- const html = render(page);
3615
-
3616
- assert(typeof html === 'string');
3617
- assert(html.length > 0);
3618
- assert(html.includes('<html>'));
3619
- assert(html.includes('${name}'));
3620
- });
3900
+ describe('${name} Page', () => {
3901
+ it('renders correctly', () => {
3902
+ const page = ${name}({});
3903
+ const html = render(page);
3904
+
3905
+ expect(typeof html).toBe('string');
3906
+ expect(html.length).toBeGreaterThan(0);
3907
+ expect(html).toContain('<html>');
3908
+ expect(html).toContain('${name}');
3909
+ });
3621
3910
 
3622
- test('${name} page includes proper head elements', () => {
3911
+ it('includes proper head elements', () => {
3623
3912
  const page = ${name}({});
3624
- const html = render(page);
3625
-
3626
- assert(html.includes('<title>'));
3627
- assert(html.includes('<meta'));
3628
- assert(html.includes('viewport'));
3629
- });
3913
+ const html = render(page);
3914
+
3915
+ expect(html).toContain('<title>');
3916
+ expect(html).toContain('<meta');
3917
+ expect(html).toContain('viewport');
3918
+ });
3919
+
3920
+ it('renders with custom props', () => {
3921
+ const props = {
3922
+ params: { id: '123' },
3923
+ query: { search: 'test' }
3924
+ };
3630
3925
 
3631
- test('${name} page renders with custom props', () => {
3632
- const props = {
3633
- params: { id: '123' },
3634
- query: { search: 'test' }
3635
- };
3636
-
3637
3926
  const page = ${name}(props);
3638
- const html = render(page);
3639
-
3640
- assert(html.includes('${name}'));
3641
- });
3642
- `;
3927
+ const html = render(page);
3928
+
3929
+ expect(html).toContain('${name}');
3930
+ });
3931
+ });`;
3643
3932
  }
3644
3933
  function toPascalCase2(str) {
3645
3934
  return str.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : "").replace(/^(.)/, (_, c) => c.toUpperCase());
@@ -3647,23 +3936,23 @@ function toPascalCase2(str) {
3647
3936
 
3648
3937
  // src/generators/api-generator.js
3649
3938
  import { writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync5 } from "fs";
3650
- import { join as join4 } from "path";
3939
+ import { join as join5 } from "path";
3651
3940
  async function generateAPI(name, options = {}) {
3652
3941
  const { path: path2 = "src/api", template = "rest", skipTest = false } = options;
3653
3942
  const apiName = toKebabCase(name);
3654
3943
  const fileName = apiName;
3655
- const outputDir = join4(process.cwd(), path2);
3944
+ const outputDir = join5(process.cwd(), path2);
3656
3945
  if (!existsSync5(outputDir)) {
3657
3946
  mkdirSync5(outputDir, { recursive: true });
3658
3947
  }
3659
3948
  const files = [];
3660
3949
  const nextSteps = [];
3661
- const apiPath = join4(outputDir, `${fileName}.js`);
3950
+ const apiPath = join5(outputDir, `${fileName}.js`);
3662
3951
  const apiContent = generateAPIContent(apiName, name, template);
3663
3952
  writeFileSync4(apiPath, apiContent);
3664
3953
  files.push(apiPath);
3665
3954
  if (!skipTest) {
3666
- const testPath = join4(outputDir, `${fileName}.test.js`);
3955
+ const testPath = join5(outputDir, `${fileName}.test.js`);
3667
3956
  const testContent = generateTestContent3(apiName, name);
3668
3957
  writeFileSync4(testPath, testContent);
3669
3958
  files.push(testPath);
@@ -3696,7 +3985,7 @@ function generateRESTAPI(apiName, originalName) {
3696
3985
  /**
3697
3986
  * ${className} API Routes
3698
3987
  * REST API for ${apiName} resources
3699
- *
3988
+ *
3700
3989
  * Base URL: /api/${apiName}
3701
3990
  */
3702
3991
 
@@ -3716,14 +4005,14 @@ const sampleData = [
3716
4005
  const ${apiName}Schema = {
3717
4006
  type: 'object',
3718
4007
  properties: {
3719
- name: {
3720
- type: 'string',
4008
+ name: {
4009
+ type: 'string',
3721
4010
  minLength: 1,
3722
- maxLength: 100
4011
+ maxLength: 100
3723
4012
  },
3724
- description: {
4013
+ description: {
3725
4014
  type: 'string',
3726
- maxLength: 500
4015
+ maxLength: 500
3727
4016
  }
3728
4017
  },
3729
4018
  required: ['name'],
@@ -3733,14 +4022,14 @@ const ${apiName}Schema = {
3733
4022
  const ${apiName}UpdateSchema = {
3734
4023
  type: 'object',
3735
4024
  properties: {
3736
- name: {
3737
- type: 'string',
4025
+ name: {
4026
+ type: 'string',
3738
4027
  minLength: 1,
3739
- maxLength: 100
4028
+ maxLength: 100
3740
4029
  },
3741
- description: {
4030
+ description: {
3742
4031
  type: 'string',
3743
- maxLength: 500
4032
+ maxLength: 500
3744
4033
  }
3745
4034
  },
3746
4035
  additionalProperties: false,
@@ -3755,21 +4044,21 @@ const ${apiName}UpdateSchema = {
3755
4044
  */
3756
4045
  ${camelCaseApiName}API.get('/', (req, res) => {
3757
4046
  const { page = 1, limit = 10, search } = req.query;
3758
-
4047
+
3759
4048
  let data = [...sampleData];
3760
-
4049
+
3761
4050
  // Apply search filter
3762
4051
  if (search) {
3763
- data = data.filter(item =>
4052
+ data = data.filter(item =>
3764
4053
  item.name.toLowerCase().includes(search.toLowerCase())
3765
4054
  );
3766
4055
  }
3767
-
4056
+
3768
4057
  // Apply pagination
3769
4058
  const startIndex = (page - 1) * limit;
3770
4059
  const endIndex = startIndex + parseInt(limit);
3771
4060
  const paginatedData = data.slice(startIndex, endIndex);
3772
-
4061
+
3773
4062
  return {
3774
4063
  data: paginatedData,
3775
4064
  pagination: {
@@ -3788,14 +4077,14 @@ ${camelCaseApiName}API.get('/', (req, res) => {
3788
4077
  ${camelCaseApiName}API.get('/:id', (req, res) => {
3789
4078
  const { id } = req.params;
3790
4079
  const item = sampleData.find(item => item.id === id);
3791
-
4080
+
3792
4081
  if (!item) {
3793
4082
  return res.status(404).json({
3794
4083
  _error: '${className} not found',
3795
4084
  code: 'NOT_FOUND'
3796
4085
  });
3797
4086
  }
3798
-
4087
+
3799
4088
  return { data: item };
3800
4089
  });
3801
4090
 
@@ -3803,11 +4092,11 @@ ${camelCaseApiName}API.get('/:id', (req, res) => {
3803
4092
  * POST /${apiName}
3804
4093
  * Create a new ${apiName} item
3805
4094
  */
3806
- ${camelCaseApiName}API.post('/',
4095
+ ${camelCaseApiName}API.post('/',
3807
4096
  withValidation(${apiName}Schema),
3808
4097
  (req, res) => {
3809
4098
  const { name, description } = req.body;
3810
-
4099
+
3811
4100
  const newItem = {
3812
4101
  id: String(Date.now()),
3813
4102
  name,
@@ -3815,9 +4104,9 @@ ${camelCaseApiName}API.post('/',
3815
4104
  createdAt: new Date().toISOString(),
3816
4105
  updatedAt: new Date().toISOString()
3817
4106
  };
3818
-
4107
+
3819
4108
  sampleData.push(newItem);
3820
-
4109
+
3821
4110
  return res.status(201).json({
3822
4111
  data: newItem,
3823
4112
  message: '${className} created successfully'
@@ -3834,22 +4123,22 @@ ${camelCaseApiName}API.put('/:id',
3834
4123
  (req, res) => {
3835
4124
  const { id } = req.params;
3836
4125
  const itemIndex = sampleData.findIndex(item => item.id === id);
3837
-
4126
+
3838
4127
  if (itemIndex === -1) {
3839
4128
  return res.status(404).json({
3840
4129
  _error: '${className} not found',
3841
4130
  code: 'NOT_FOUND'
3842
4131
  });
3843
4132
  }
3844
-
4133
+
3845
4134
  const updatedItem = {
3846
4135
  ...sampleData[itemIndex],
3847
4136
  ...req.body,
3848
4137
  updatedAt: new Date().toISOString()
3849
4138
  };
3850
-
4139
+
3851
4140
  sampleData[itemIndex] = updatedItem;
3852
-
4141
+
3853
4142
  return {
3854
4143
  data: updatedItem,
3855
4144
  message: '${className} updated successfully'
@@ -3864,16 +4153,16 @@ ${camelCaseApiName}API.put('/:id',
3864
4153
  ${camelCaseApiName}API.delete('/:id', (req, res) => {
3865
4154
  const { id } = req.params;
3866
4155
  const itemIndex = sampleData.findIndex(item => item.id === id);
3867
-
4156
+
3868
4157
  if (itemIndex === -1) {
3869
4158
  return res.status(404).json({
3870
4159
  _error: '${className} not found',
3871
4160
  code: 'NOT_FOUND'
3872
4161
  });
3873
4162
  }
3874
-
4163
+
3875
4164
  const deletedItem = sampleData.splice(itemIndex, 1)[0];
3876
-
4165
+
3877
4166
  return {
3878
4167
  data: deletedItem,
3879
4168
  message: '${className} deleted successfully'
@@ -3894,7 +4183,7 @@ export default ${camelCaseApiName}API;
3894
4183
  // Usage example:
3895
4184
  // import express from 'express';
3896
4185
  // import ${camelCaseApiName}API from './api/${apiName}.js';
3897
- //
4186
+ //
3898
4187
  // const app = express();
3899
4188
  // app.use(express.json());
3900
4189
  // app.use('/api', ${camelCaseApiName}API.toExpress());
@@ -3915,7 +4204,7 @@ function generateRPCAPI(apiName, originalName) {
3915
4204
  /**
3916
4205
  * ${className} RPC API
3917
4206
  * Remote Procedure Call API for ${apiName}
3918
- *
4207
+ *
3919
4208
  * Base URL: /rpc/${apiName}
3920
4209
  */
3921
4210
 
@@ -3938,10 +4227,10 @@ sampleData.set('2', { id: '2', name: 'Sample ${className} 2', createdAt: new Dat
3938
4227
  ${camelCaseApiName}RPC.post('/list', (req, res) => {
3939
4228
  const { params = {} } = req.body;
3940
4229
  const { limit = 10, offset = 0 } = params;
3941
-
4230
+
3942
4231
  const items = Array.from(sampleData.values())
3943
4232
  .slice(offset, offset + limit);
3944
-
4233
+
3945
4234
  return {
3946
4235
  jsonrpc: '2.0',
3947
4236
  result: {
@@ -3956,7 +4245,7 @@ ${camelCaseApiName}RPC.post('/list', (req, res) => {
3956
4245
  * RPC Method: ${apiName}.get
3957
4246
  * Get a specific ${apiName} item
3958
4247
  */
3959
- ${camelCaseApiName}RPC.post('/get',
4248
+ ${camelCaseApiName}RPC.post('/get',
3960
4249
  withValidation({
3961
4250
  type: 'object',
3962
4251
  properties: {
@@ -3973,7 +4262,7 @@ ${camelCaseApiName}RPC.post('/get',
3973
4262
  (req, res) => {
3974
4263
  const { params } = req.body;
3975
4264
  const item = sampleData.get(params.id);
3976
-
4265
+
3977
4266
  if (!item) {
3978
4267
  return {
3979
4268
  jsonrpc: '2.0',
@@ -3984,7 +4273,7 @@ ${camelCaseApiName}RPC.post('/get',
3984
4273
  id: req.body.id
3985
4274
  };
3986
4275
  }
3987
-
4276
+
3988
4277
  return {
3989
4278
  jsonrpc: '2.0',
3990
4279
  result: item,
@@ -4015,16 +4304,16 @@ ${camelCaseApiName}RPC.post('/create',
4015
4304
  (req, res) => {
4016
4305
  const { params } = req.body;
4017
4306
  const id = String(Date.now());
4018
-
4307
+
4019
4308
  const newItem = {
4020
4309
  id,
4021
4310
  ...params,
4022
4311
  createdAt: new Date(),
4023
4312
  updatedAt: new Date()
4024
4313
  };
4025
-
4314
+
4026
4315
  sampleData.set(id, newItem);
4027
-
4316
+
4028
4317
  return {
4029
4318
  jsonrpc: '2.0',
4030
4319
  result: newItem,
@@ -4056,7 +4345,7 @@ ${camelCaseApiName}RPC.post('/update',
4056
4345
  (req, res) => {
4057
4346
  const { params } = req.body;
4058
4347
  const existing = sampleData.get(params.id);
4059
-
4348
+
4060
4349
  if (!existing) {
4061
4350
  return {
4062
4351
  jsonrpc: '2.0',
@@ -4067,15 +4356,15 @@ ${camelCaseApiName}RPC.post('/update',
4067
4356
  id: req.body.id
4068
4357
  };
4069
4358
  }
4070
-
4359
+
4071
4360
  const updated = {
4072
4361
  ...existing,
4073
4362
  ...params,
4074
4363
  updatedAt: new Date()
4075
4364
  };
4076
-
4365
+
4077
4366
  sampleData.set(params.id, updated);
4078
-
4367
+
4079
4368
  return {
4080
4369
  jsonrpc: '2.0',
4081
4370
  result: updated,
@@ -4105,7 +4394,7 @@ ${camelCaseApiName}RPC.post('/delete',
4105
4394
  (req, res) => {
4106
4395
  const { params } = req.body;
4107
4396
  const item = sampleData.get(params.id);
4108
-
4397
+
4109
4398
  if (!item) {
4110
4399
  return {
4111
4400
  jsonrpc: '2.0',
@@ -4116,9 +4405,9 @@ ${camelCaseApiName}RPC.post('/delete',
4116
4405
  id: req.body.id
4117
4406
  };
4118
4407
  }
4119
-
4408
+
4120
4409
  sampleData.delete(params.id);
4121
-
4410
+
4122
4411
  return {
4123
4412
  jsonrpc: '2.0',
4124
4413
  result: { success: true, deleted: item },
@@ -4132,17 +4421,17 @@ export default ${camelCaseApiName}RPC;
4132
4421
  }
4133
4422
  function generateTestContent3(apiName, originalName) {
4134
4423
  const className = toPascalCase3(originalName);
4135
- return `import { test } from 'node:test';
4136
- import assert from 'node:assert';
4424
+ return `import { describe, it, expect } from 'vitest';
4137
4425
  import ${apiName}API from './${apiName}.js';
4138
4426
 
4139
- test('${className} API should be defined', () => {
4140
- assert(typeof ${apiName}API === 'object');
4141
- assert(typeof ${apiName}API.get === 'function');
4142
- assert(typeof ${apiName}API.post === 'function');
4427
+ describe('${className} API', () => {
4428
+ it('should be defined', () => {
4429
+ expect(typeof ${apiName}API).toBe('object');
4430
+ expect(typeof ${apiName}API.get).toBe('function');
4431
+ expect(typeof ${apiName}API.post).toBe('function');
4143
4432
  });
4144
4433
 
4145
- test('${className} API should handle GET requests', async () => {
4434
+ it('should handle GET requests', async () => {
4146
4435
  const mockReq = {
4147
4436
  query: {}
4148
4437
  };
@@ -4150,15 +4439,15 @@ test('${className} API should handle GET requests', async () => {
4150
4439
  status: (code) => mockRes,
4151
4440
  json: (data) => data
4152
4441
  };
4153
-
4442
+
4154
4443
  // This is a basic test structure
4155
4444
  // In a real test, you'd use a testing framework like supertest
4156
- assert(true); // Placeholder
4445
+ expect(true).toBe(true); // Placeholder
4157
4446
  });
4158
4447
 
4159
4448
  // Add more specific tests for your API endpoints
4160
4449
  // Example:
4161
- // test('POST /${apiName} should create new item', async () => {
4450
+ // it('POST /${apiName} should create new item', async () => {
4162
4451
  // // Test implementation
4163
4452
  // });
4164
4453
  //
@@ -4290,19 +4579,19 @@ import { Command as Command3 } from "commander";
4290
4579
  import ora3 from "ora";
4291
4580
  import picocolors3 from "picocolors";
4292
4581
  import { execSync as execSync2 } from "child_process";
4293
- import { existsSync as existsSync6, readFileSync } from "fs";
4294
- import { join as join5 } from "path";
4582
+ import { existsSync as existsSync6, readFileSync as readFileSync2 } from "fs";
4583
+ import { join as join6 } from "path";
4295
4584
  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) => {
4296
4585
  console.log(picocolors3.cyan("\u{1F3D7}\uFE0F Building Coherent.js project..."));
4297
4586
  console.log();
4298
- const packageJsonPath = join5(process.cwd(), "package.json");
4587
+ const packageJsonPath = join6(process.cwd(), "package.json");
4299
4588
  if (!existsSync6(packageJsonPath)) {
4300
4589
  console.error(picocolors3.red("\u274C No package.json found. Are you in a project directory?"));
4301
4590
  process.exit(1);
4302
4591
  }
4303
4592
  let packageJson;
4304
4593
  try {
4305
- packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
4594
+ packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
4306
4595
  } catch {
4307
4596
  console.error(picocolors3.red("\u274C Failed to read package.json"));
4308
4597
  process.exit(1);
@@ -4397,19 +4686,19 @@ import { Command as Command4 } from "commander";
4397
4686
  import ora4 from "ora";
4398
4687
  import picocolors4 from "picocolors";
4399
4688
  import { spawn } from "child_process";
4400
- import { existsSync as existsSync7, readFileSync as readFileSync2 } from "fs";
4401
- import { join as join6 } from "path";
4689
+ import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
4690
+ import { join as join7 } from "path";
4402
4691
  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) => {
4403
4692
  console.log(picocolors4.cyan("\u{1F680} Starting Coherent.js development server..."));
4404
4693
  console.log();
4405
- const packageJsonPath = join6(process.cwd(), "package.json");
4694
+ const packageJsonPath = join7(process.cwd(), "package.json");
4406
4695
  if (!existsSync7(packageJsonPath)) {
4407
4696
  console.error(picocolors4.red("\u274C No package.json found. Are you in a project directory?"));
4408
4697
  process.exit(1);
4409
4698
  }
4410
4699
  let packageJson;
4411
4700
  try {
4412
- packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
4701
+ packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
4413
4702
  } catch {
4414
4703
  console.error(picocolors4.red("\u274C Failed to read package.json"));
4415
4704
  process.exit(1);
@@ -4509,11 +4798,11 @@ import { Command as Command5 } from "commander";
4509
4798
  import prompts3 from "prompts";
4510
4799
  import ora5 from "ora";
4511
4800
  import picocolors5 from "picocolors";
4512
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
4801
+ import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
4513
4802
  import { resolve as resolve5 } from "path";
4514
4803
 
4515
4804
  // src/analyzers/component-analyzer.js
4516
- import { readFileSync as readFileSync3, existsSync as existsSync8 } from "fs";
4805
+ import { readFileSync as readFileSync4, existsSync as existsSync8 } from "fs";
4517
4806
  import { resolve as resolve3 } from "path";
4518
4807
 
4519
4808
  // ../../node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
@@ -4727,7 +5016,7 @@ function expand_(str, isTop) {
4727
5016
  return expansions;
4728
5017
  }
4729
5018
 
4730
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/assert-valid-pattern.js
5019
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/assert-valid-pattern.js
4731
5020
  var MAX_PATTERN_LENGTH = 1024 * 64;
4732
5021
  var assertValidPattern = (pattern) => {
4733
5022
  if (typeof pattern !== "string") {
@@ -4738,7 +5027,7 @@ var assertValidPattern = (pattern) => {
4738
5027
  }
4739
5028
  };
4740
5029
 
4741
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/brace-expressions.js
5030
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/brace-expressions.js
4742
5031
  var posixClasses = {
4743
5032
  "[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
4744
5033
  "[:alpha:]": ["\\p{L}\\p{Nl}", true],
@@ -4847,12 +5136,15 @@ var parseClass = (glob2, position) => {
4847
5136
  return [comb, uflag, endPos - pos, true];
4848
5137
  };
4849
5138
 
4850
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/unescape.js
4851
- var unescape = (s, { windowsPathsNoEscape = false } = {}) => {
4852
- return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
5139
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/unescape.js
5140
+ var unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true } = {}) => {
5141
+ if (magicalBraces) {
5142
+ return windowsPathsNoEscape ? s.replace(/\[([^\/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, "$1$2").replace(/\\([^\/])/g, "$1");
5143
+ }
5144
+ return windowsPathsNoEscape ? s.replace(/\[([^\/\\{}])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^\/\\{}])\]/g, "$1$2").replace(/\\([^\/{}])/g, "$1");
4853
5145
  };
4854
5146
 
4855
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/ast.js
5147
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/ast.js
4856
5148
  var types = /* @__PURE__ */ new Set(["!", "?", "+", "*", "@"]);
4857
5149
  var isExtglobType = (c) => types.has(c);
4858
5150
  var startNoTraversal = "(?!(?:^|/)\\.\\.?(?:$|/))";
@@ -5203,7 +5495,7 @@ var AST = class _AST {
5203
5495
  if (this.#root === this)
5204
5496
  this.#fillNegs();
5205
5497
  if (!this.type) {
5206
- const noEmpty = this.isStart() && this.isEnd();
5498
+ const noEmpty = this.isStart() && this.isEnd() && !this.#parts.some((s) => typeof s !== "string");
5207
5499
  const src = this.#parts.map((p) => {
5208
5500
  const [re, _, hasMagic2, uflag] = typeof p === "string" ? _AST.#parseGlob(p, this.#hasMagic, noEmpty) : p.toRegExpSource(allowDot);
5209
5501
  this.#hasMagic = this.#hasMagic || hasMagic2;
@@ -5313,10 +5605,7 @@ var AST = class _AST {
5313
5605
  }
5314
5606
  }
5315
5607
  if (c === "*") {
5316
- if (noEmpty && glob2 === "*")
5317
- re += starNoEmpty;
5318
- else
5319
- re += star;
5608
+ re += noEmpty && glob2 === "*" ? starNoEmpty : star;
5320
5609
  hasMagic2 = true;
5321
5610
  continue;
5322
5611
  }
@@ -5331,12 +5620,15 @@ var AST = class _AST {
5331
5620
  }
5332
5621
  };
5333
5622
 
5334
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/escape.js
5335
- var escape = (s, { windowsPathsNoEscape = false } = {}) => {
5623
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/escape.js
5624
+ var escape = (s, { windowsPathsNoEscape = false, magicalBraces = false } = {}) => {
5625
+ if (magicalBraces) {
5626
+ return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, "[$&]") : s.replace(/[?*()[\]\\{}]/g, "\\$&");
5627
+ }
5336
5628
  return windowsPathsNoEscape ? s.replace(/[?*()[\]]/g, "[$&]") : s.replace(/[?*()[\]\\]/g, "\\$&");
5337
5629
  };
5338
5630
 
5339
- // ../../node_modules/.pnpm/minimatch@10.0.3/node_modules/minimatch/dist/esm/index.js
5631
+ // ../../node_modules/.pnpm/minimatch@10.1.1/node_modules/minimatch/dist/esm/index.js
5340
5632
  var minimatch = (p, pattern, options = {}) => {
5341
5633
  assertValidPattern(pattern);
5342
5634
  if (!options.nocomment && pattern.charAt(0) === "#") {
@@ -5973,16 +6265,27 @@ var Minimatch = class {
5973
6265
  pp[i] = twoStar;
5974
6266
  }
5975
6267
  } else if (next === void 0) {
5976
- pp[i - 1] = prev + "(?:\\/|" + twoStar + ")?";
6268
+ pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + ")?";
5977
6269
  } else if (next !== GLOBSTAR) {
5978
6270
  pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next;
5979
6271
  pp[i + 1] = GLOBSTAR;
5980
6272
  }
5981
6273
  });
5982
- return pp.filter((p) => p !== GLOBSTAR).join("/");
6274
+ const filtered = pp.filter((p) => p !== GLOBSTAR);
6275
+ if (this.partial && filtered.length >= 1) {
6276
+ const prefixes = [];
6277
+ for (let i = 1; i <= filtered.length; i++) {
6278
+ prefixes.push(filtered.slice(0, i).join("/"));
6279
+ }
6280
+ return "(?:" + prefixes.join("|") + ")";
6281
+ }
6282
+ return filtered.join("/");
5983
6283
  }).join("|");
5984
6284
  const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
5985
6285
  re = "^" + open + re + close + "$";
6286
+ if (this.partial) {
6287
+ re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
6288
+ }
5986
6289
  if (this.negate)
5987
6290
  re = "^(?!" + re + ").+$";
5988
6291
  try {
@@ -6054,10 +6357,10 @@ minimatch.Minimatch = Minimatch;
6054
6357
  minimatch.escape = escape;
6055
6358
  minimatch.unescape = unescape;
6056
6359
 
6057
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/glob.js
6058
- import { fileURLToPath as fileURLToPath2 } from "node:url";
6360
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/glob.js
6361
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
6059
6362
 
6060
- // ../../node_modules/.pnpm/lru-cache@11.2.1/node_modules/lru-cache/dist/esm/index.js
6363
+ // ../../node_modules/.pnpm/lru-cache@11.2.2/node_modules/lru-cache/dist/esm/index.js
6061
6364
  var defaultPerf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
6062
6365
  var warned = /* @__PURE__ */ new Set();
6063
6366
  var PROCESS = typeof process === "object" && !!process ? process : {};
@@ -7103,7 +7406,8 @@ var LRUCache = class _LRUCache {
7103
7406
  return fetchFail(ac.signal.reason);
7104
7407
  }
7105
7408
  const bf2 = p;
7106
- if (this.#valList[index] === p) {
7409
+ const vl = this.#valList[index];
7410
+ if (vl === p || ignoreAbort && updateCache && vl === void 0) {
7107
7411
  if (v2 === void 0) {
7108
7412
  if (bf2.__staleWhileFetching !== void 0) {
7109
7413
  this.#valList[index] = bf2.__staleWhileFetching;
@@ -7457,9 +7761,9 @@ var LRUCache = class _LRUCache {
7457
7761
  }
7458
7762
  };
7459
7763
 
7460
- // ../../node_modules/.pnpm/path-scurry@2.0.0/node_modules/path-scurry/dist/esm/index.js
7764
+ // ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
7461
7765
  import { posix, win32 } from "node:path";
7462
- import { fileURLToPath } from "node:url";
7766
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
7463
7767
  import { lstatSync, readdir as readdirCB, readdirSync, readlinkSync, realpathSync as rps } from "fs";
7464
7768
  import * as actualFS from "node:fs";
7465
7769
  import { lstat, readdir, readlink, realpath } from "node:fs/promises";
@@ -8342,7 +8646,7 @@ var Minipass = class extends EventEmitter {
8342
8646
  }
8343
8647
  };
8344
8648
 
8345
- // ../../node_modules/.pnpm/path-scurry@2.0.0/node_modules/path-scurry/dist/esm/index.js
8649
+ // ../../node_modules/.pnpm/path-scurry@2.0.1/node_modules/path-scurry/dist/esm/index.js
8346
8650
  var realpathSync = rps.native;
8347
8651
  var defaultFS = {
8348
8652
  lstatSync,
@@ -8387,7 +8691,7 @@ var ENOREALPATH = 512;
8387
8691
  var ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
8388
8692
  var TYPEMASK = 1023;
8389
8693
  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;
8390
- var normalizeCache = /* @__PURE__ */ new Map();
8694
+ var normalizeCache = new LRUCache({ max: 2 ** 12 });
8391
8695
  var normalize = (s) => {
8392
8696
  const c = normalizeCache.get(s);
8393
8697
  if (c)
@@ -8396,7 +8700,7 @@ var normalize = (s) => {
8396
8700
  normalizeCache.set(s, n);
8397
8701
  return n;
8398
8702
  };
8399
- var normalizeNocaseCache = /* @__PURE__ */ new Map();
8703
+ var normalizeNocaseCache = new LRUCache({ max: 2 ** 12 });
8400
8704
  var normalizeNocase = (s) => {
8401
8705
  const c = normalizeNocaseCache.get(s);
8402
8706
  if (c)
@@ -8553,6 +8857,7 @@ var PathBase = class {
8553
8857
  get parentPath() {
8554
8858
  return (this.parent || this).fullpath();
8555
8859
  }
8860
+ /* c8 ignore start */
8556
8861
  /**
8557
8862
  * Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
8558
8863
  * this property refers to the *parent* path, not the path object itself.
@@ -8562,6 +8867,7 @@ var PathBase = class {
8562
8867
  get path() {
8563
8868
  return this.parentPath;
8564
8869
  }
8870
+ /* c8 ignore stop */
8565
8871
  /**
8566
8872
  * Do not create new Path objects directly. They should always be accessed
8567
8873
  * via the PathScurry class or other methods on the Path class.
@@ -9464,7 +9770,7 @@ var PathScurryBase = class {
9464
9770
  constructor(cwd = process.cwd(), pathImpl, sep2, { nocase, childrenCacheSize = 16 * 1024, fs = defaultFS } = {}) {
9465
9771
  this.#fs = fsFromOption(fs);
9466
9772
  if (cwd instanceof URL || cwd.startsWith("file://")) {
9467
- cwd = fileURLToPath(cwd);
9773
+ cwd = fileURLToPath2(cwd);
9468
9774
  }
9469
9775
  const cwdPath = pathImpl.resolve(cwd);
9470
9776
  this.roots = /* @__PURE__ */ Object.create(null);
@@ -10068,7 +10374,7 @@ var PathScurryDarwin = class extends PathScurryPosix {
10068
10374
  var Path = process.platform === "win32" ? PathWin32 : PathPosix;
10069
10375
  var PathScurry = process.platform === "win32" ? PathScurryWin32 : process.platform === "darwin" ? PathScurryDarwin : PathScurryPosix;
10070
10376
 
10071
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/pattern.js
10377
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/pattern.js
10072
10378
  var isPatternList = (pl) => pl.length >= 1;
10073
10379
  var isGlobList = (gl) => gl.length >= 1;
10074
10380
  var Pattern = class _Pattern {
@@ -10233,7 +10539,7 @@ var Pattern = class _Pattern {
10233
10539
  }
10234
10540
  };
10235
10541
 
10236
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/ignore.js
10542
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/ignore.js
10237
10543
  var defaultPlatform2 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
10238
10544
  var Ignore = class {
10239
10545
  relative;
@@ -10320,7 +10626,7 @@ var Ignore = class {
10320
10626
  }
10321
10627
  };
10322
10628
 
10323
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/processor.js
10629
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/processor.js
10324
10630
  var HasWalkedCache = class _HasWalkedCache {
10325
10631
  store;
10326
10632
  constructor(store = /* @__PURE__ */ new Map()) {
@@ -10541,7 +10847,7 @@ var Processor = class _Processor {
10541
10847
  }
10542
10848
  };
10543
10849
 
10544
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/walker.js
10850
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/walker.js
10545
10851
  var makeIgnore = (ignore, opts) => typeof ignore === "string" ? new Ignore([ignore], opts) : Array.isArray(ignore) ? new Ignore(ignore, opts) : ignore;
10546
10852
  var GlobUtil = class {
10547
10853
  path;
@@ -10868,7 +11174,7 @@ var GlobStream = class extends GlobUtil {
10868
11174
  }
10869
11175
  };
10870
11176
 
10871
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/glob.js
11177
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/glob.js
10872
11178
  var defaultPlatform3 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
10873
11179
  var Glob = class {
10874
11180
  absolute;
@@ -10929,7 +11235,7 @@ var Glob = class {
10929
11235
  if (!opts.cwd) {
10930
11236
  this.cwd = "";
10931
11237
  } else if (opts.cwd instanceof URL || opts.cwd.startsWith("file://")) {
10932
- opts.cwd = fileURLToPath2(opts.cwd);
11238
+ opts.cwd = fileURLToPath3(opts.cwd);
10933
11239
  }
10934
11240
  this.cwd = opts.cwd || "";
10935
11241
  this.root = opts.root;
@@ -11068,7 +11374,7 @@ var Glob = class {
11068
11374
  }
11069
11375
  };
11070
11376
 
11071
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/has-magic.js
11377
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/has-magic.js
11072
11378
  var hasMagic = (pattern, options = {}) => {
11073
11379
  if (!Array.isArray(pattern)) {
11074
11380
  pattern = [pattern];
@@ -11080,7 +11386,7 @@ var hasMagic = (pattern, options = {}) => {
11080
11386
  return false;
11081
11387
  };
11082
11388
 
11083
- // ../../node_modules/.pnpm/glob@11.0.3/node_modules/glob/dist/esm/index.js
11389
+ // ../../node_modules/.pnpm/glob@11.1.0/node_modules/glob/dist/esm/index.js
11084
11390
  function globStreamSync(pattern, options = {}) {
11085
11391
  return new Glob(pattern, options).streamSync();
11086
11392
  }
@@ -11242,7 +11548,7 @@ async function analyzeComponentFile(filePath, _options = {}) {
11242
11548
  });
11243
11549
  return analysis;
11244
11550
  }
11245
- const content = readFileSync3(resolve3(filePath), "utf-8");
11551
+ const content = readFileSync4(resolve3(filePath), "utf-8");
11246
11552
  analysis.size = Buffer.byteLength(content, "utf8");
11247
11553
  analysis.lines = content.split("\n").length;
11248
11554
  const syntaxAnalysis = analyzeSyntax(content, filePath);
@@ -11603,7 +11909,7 @@ async function analyzeHydration(options = {}) {
11603
11909
  }
11604
11910
 
11605
11911
  // src/validators/project-validator.js
11606
- import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
11912
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
11607
11913
  import { resolve as resolve4 } from "path";
11608
11914
  async function validateProject(_options = {}) {
11609
11915
  const validation = {
@@ -11670,7 +11976,7 @@ function validatePackageJson() {
11670
11976
  const issues = [];
11671
11977
  const recommendations = [];
11672
11978
  try {
11673
- const packageJson = JSON.parse(readFileSync4("package.json", "utf-8"));
11979
+ const packageJson = JSON.parse(readFileSync5("package.json", "utf-8"));
11674
11980
  const requiredFields = ["name", "version", "description"];
11675
11981
  requiredFields.forEach((field) => {
11676
11982
  const hasField = packageJson[field];
@@ -11954,7 +12260,7 @@ async function analyzeConfiguration(_options = {}) {
11954
12260
  };
11955
12261
  if (existsSync10("package.json")) {
11956
12262
  try {
11957
- const packageJson = JSON.parse(readFileSync5("package.json", "utf-8"));
12263
+ const packageJson = JSON.parse(readFileSync6("package.json", "utf-8"));
11958
12264
  const hasCoherentDeps = Object.keys(packageJson.dependencies || {}).some((dep) => dep.startsWith("@coherent.js/"));
11959
12265
  if (!hasCoherentDeps) {
11960
12266
  analysis.summary.issues.push("No Coherent.js dependencies found");
@@ -12098,12 +12404,12 @@ async function generateHTMLReport(result) {
12098
12404
  }
12099
12405
 
12100
12406
  // src/index.js
12101
- var __filename = fileURLToPath3(import.meta.url);
12102
- var __dirname = dirname2(__filename);
12407
+ var __filename = fileURLToPath4(import.meta.url);
12408
+ var __dirname = dirname3(__filename);
12103
12409
  var version = "1.0.1";
12104
12410
  try {
12105
- const packagePath = join7(__dirname, "..", "package.json");
12106
- const packageJson = JSON.parse(readFileSync6(packagePath, "utf-8"));
12411
+ const packagePath = join8(__dirname, "..", "package.json");
12412
+ const packageJson = JSON.parse(readFileSync7(packagePath, "utf-8"));
12107
12413
  version = packageJson.version;
12108
12414
  } catch {
12109
12415
  }