gmoonc 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/{index.js → index.cjs} +65 -35
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -46,6 +46,16 @@ Your dashboard is now available at:
|
|
|
46
46
|
|
|
47
47
|
The dashboard code is in `src/gmoonc/` and is independent. You can remove `gmoonc` from `package.json` if desired.
|
|
48
48
|
|
|
49
|
+
## Changelog
|
|
50
|
+
|
|
51
|
+
### 0.0.9
|
|
52
|
+
- Fix: ensure BrowserRouter import when patched into App.tsx
|
|
53
|
+
|
|
54
|
+
### 0.0.8
|
|
55
|
+
- Fix: BIN corrected to use CommonJS (.cjs) for Windows compatibility
|
|
56
|
+
- Fix: Router patch now ensures BrowserRouter import is always present
|
|
57
|
+
- Fix: Route order corrected (NotFound "*" route is always last)
|
|
58
|
+
|
|
49
59
|
## Uninstalling
|
|
50
60
|
|
|
51
61
|
To remove gmoonc:
|
|
@@ -454,30 +454,42 @@ function generateAppRoutes(consumerDir, basePath, routes, appPath, dryRun) {
|
|
|
454
454
|
return { success: true };
|
|
455
455
|
}
|
|
456
456
|
ensureDirectoryExists(appRoutesPath);
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
if (route.path === "/" || route.path === "*") {
|
|
460
|
-
routeElements.push(` { path: "${route.path}", element: <${route.componentName} /> }`);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
routeElements.push(` ...createGmooncRoutes({ basePath })`);
|
|
457
|
+
const indexRoute = routes.find((r) => r.path === "/");
|
|
458
|
+
const notFoundRoute = routes.find((r) => r.path === "*");
|
|
464
459
|
const imports = [
|
|
465
460
|
"import { useRoutes, type RouteObject } from 'react-router-dom';",
|
|
466
461
|
"import { createGmooncRoutes } from './createGmooncRoutes';"
|
|
467
462
|
];
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
463
|
+
if (indexRoute && indexRoute.import) {
|
|
464
|
+
const convertedImport = convertImportToRelative(
|
|
465
|
+
indexRoute.import.line,
|
|
466
|
+
indexRoute.import.from,
|
|
467
|
+
appRoutesDir,
|
|
468
|
+
appDir
|
|
469
|
+
);
|
|
470
|
+
if (!imports.includes(convertedImport)) {
|
|
471
|
+
imports.push(convertedImport);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (notFoundRoute && notFoundRoute.import) {
|
|
475
|
+
const convertedImport = convertImportToRelative(
|
|
476
|
+
notFoundRoute.import.line,
|
|
477
|
+
notFoundRoute.import.from,
|
|
478
|
+
appRoutesDir,
|
|
479
|
+
appDir
|
|
480
|
+
);
|
|
481
|
+
if (!imports.includes(convertedImport)) {
|
|
482
|
+
imports.push(convertedImport);
|
|
479
483
|
}
|
|
480
484
|
}
|
|
485
|
+
const routeElements = [];
|
|
486
|
+
if (indexRoute) {
|
|
487
|
+
routeElements.push(` { path: "${indexRoute.path}", element: <${indexRoute.componentName} /> }`);
|
|
488
|
+
}
|
|
489
|
+
routeElements.push(` ...createGmooncRoutes({ basePath })`);
|
|
490
|
+
if (notFoundRoute) {
|
|
491
|
+
routeElements.push(` { path: "${notFoundRoute.path}", element: <${notFoundRoute.componentName} /> }`);
|
|
492
|
+
}
|
|
481
493
|
const content = `${imports.join("\n")}
|
|
482
494
|
|
|
483
495
|
export function GMooncAppRoutes({ basePath = "${basePath}" }: { basePath?: string }) {
|
|
@@ -552,32 +564,50 @@ function patchBrowserRouter(consumerDir, basePath, dryRun) {
|
|
|
552
564
|
const lines = appContent.split("\n");
|
|
553
565
|
let hasBrowserRouterImport = false;
|
|
554
566
|
let reactRouterImportIndex = -1;
|
|
567
|
+
let reactRouterImportLine = null;
|
|
568
|
+
let quoteStyle = '"';
|
|
555
569
|
for (let i = 0; i < lines.length; i++) {
|
|
556
|
-
const line = lines[i]
|
|
557
|
-
|
|
570
|
+
const line = lines[i];
|
|
571
|
+
const trimmed = line.trim();
|
|
572
|
+
if (trimmed.startsWith("import ") && (trimmed.includes("'") || trimmed.includes('"'))) {
|
|
573
|
+
if (trimmed.includes("'")) quoteStyle = "'";
|
|
574
|
+
else if (trimmed.includes('"')) quoteStyle = '"';
|
|
575
|
+
}
|
|
576
|
+
if (trimmed.includes("from") && trimmed.includes("react-router-dom")) {
|
|
558
577
|
reactRouterImportIndex = i;
|
|
559
|
-
|
|
578
|
+
reactRouterImportLine = line;
|
|
579
|
+
const browserRouterPattern = /\bBrowserRouter\b/;
|
|
580
|
+
if (browserRouterPattern.test(trimmed)) {
|
|
560
581
|
hasBrowserRouterImport = true;
|
|
561
582
|
}
|
|
562
583
|
}
|
|
563
584
|
}
|
|
564
585
|
if (!hasBrowserRouterImport) {
|
|
565
|
-
if (reactRouterImportIndex >= 0) {
|
|
566
|
-
const existingLine =
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
586
|
+
if (reactRouterImportIndex >= 0 && reactRouterImportLine) {
|
|
587
|
+
const existingLine = reactRouterImportLine;
|
|
588
|
+
const indent2 = existingLine.match(/^(\s*)/)?.[1] || "";
|
|
589
|
+
const namedMatch = existingLine.match(/^(\s*)import\s+\{([^}]+)\}\s+from\s+(["'])react-router-dom\2/);
|
|
590
|
+
if (namedMatch) {
|
|
591
|
+
const importListStr = namedMatch[2];
|
|
592
|
+
const quote = namedMatch[3];
|
|
593
|
+
const importItems = importListStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
594
|
+
const hasBrowserRouter = importItems.some(
|
|
595
|
+
(item) => item === "BrowserRouter" || item === "type BrowserRouter" || item.includes("BrowserRouter")
|
|
596
|
+
);
|
|
597
|
+
if (!hasBrowserRouter) {
|
|
598
|
+
importItems.push("BrowserRouter");
|
|
599
|
+
const hasTrailingComma = importListStr.trim().endsWith(",");
|
|
600
|
+
const separator = importListStr.includes(",\n") ? ",\n" : ", ";
|
|
601
|
+
const formatted = importItems.join(separator) + (hasTrailingComma ? "," : "");
|
|
602
|
+
const updatedLine = `${indent2}import { ${formatted} } from ${quote}react-router-dom${quote};`;
|
|
603
|
+
lines[reactRouterImportIndex] = updatedLine;
|
|
604
|
+
}
|
|
576
605
|
} else {
|
|
577
|
-
|
|
606
|
+
const newImportLine = `${indent2}import { BrowserRouter } from ${quoteStyle}react-router-dom${quoteStyle};`;
|
|
607
|
+
lines.splice(reactRouterImportIndex + 1, 0, newImportLine);
|
|
578
608
|
}
|
|
579
609
|
} else {
|
|
580
|
-
const importLine2 = `import { BrowserRouter } from
|
|
610
|
+
const importLine2 = `import { BrowserRouter } from ${quoteStyle}react-router-dom${quoteStyle};`;
|
|
581
611
|
let lastImportIndex2 = -1;
|
|
582
612
|
for (let i = 0; i < lines.length; i++) {
|
|
583
613
|
const line = lines[i].trim();
|
|
@@ -659,7 +689,7 @@ function patchBrowserRouter(consumerDir, basePath, dryRun) {
|
|
|
659
689
|
|
|
660
690
|
// src/cli/index.ts
|
|
661
691
|
var program = new import_commander.Command();
|
|
662
|
-
program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete dashboard into your React project").version("0.0.
|
|
692
|
+
program.name("gmoonc").description("Goalmoon Ctrl (gmoonc): Install complete dashboard into your React project").version("0.0.9").option("--base <path>", "Base path for dashboard routes", "/app").option("--skip-router-patch", "Skip automatic router integration (only copy files and inject CSS)").option("--dry-run", "Show what would be done without making changes").action(async (options) => {
|
|
663
693
|
try {
|
|
664
694
|
logInfo("\u{1F680} Starting gmoonc installer...");
|
|
665
695
|
logInfo("\u{1F4E6} Installing complete dashboard into your React project\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gmoonc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Goalmoon Ctrl (gmoonc): Complete dashboard installer for React projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://gmoonc.com",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
16
|
"bin": {
|
|
17
|
-
"gmoonc": "
|
|
17
|
+
"gmoonc": "dist/index.cjs"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
27
|
"sync:templates": "node scripts/sync-templates.mjs",
|
|
28
|
-
"build": "tsup src/cli/index.ts --format cjs --no-splitting --out-dir dist && node -e \"const fs=require('fs');const path=require('path');const distDir='dist';const files=fs.readdirSync(distDir);const indexFile=files.find(f=>(f.startsWith('index')&&(f.endsWith('.js')||f.endsWith('.cjs'))));if(indexFile){const oldPath=path.join(distDir,indexFile);const newPath=path.join(distDir,'index.
|
|
28
|
+
"build": "tsup src/cli/index.ts --format cjs --no-splitting --out-dir dist && node -e \"const fs=require('fs');const path=require('path');const distDir='dist';const files=fs.readdirSync(distDir);const indexFile=files.find(f=>(f.startsWith('index')&&(f.endsWith('.js')||f.endsWith('.cjs'))));if(indexFile){const oldPath=path.join(distDir,indexFile);const newPath=path.join(distDir,'index.cjs');if(oldPath!==newPath){fs.renameSync(oldPath,newPath);}const content=fs.readFileSync(newPath,'utf8');if(!content.startsWith('#!/usr/bin/env node')){fs.writeFileSync(newPath,'#!/usr/bin/env node\\n'+content)}}\"",
|
|
29
29
|
"clean": "rimraf dist",
|
|
30
30
|
"prepublishOnly": "npm run clean && npm run build",
|
|
31
31
|
"postinstall": "node scripts/block-global-install.cjs"
|