mycontext-cli 2.0.7 → 2.0.8
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 +84 -0
- package/dist/commands/generate-components.d.ts.map +1 -1
- package/dist/commands/generate-components.js +72 -29
- package/dist/commands/generate-components.js.map +1 -1
- package/dist/commands/refine.d.ts +33 -0
- package/dist/commands/refine.d.ts.map +1 -1
- package/dist/commands/refine.js +329 -0
- package/dist/commands/refine.js.map +1 -1
- package/dist/config/ai-providers.json +20 -148
- package/dist/config/dependencies.json +4 -4
- package/dist/package.json +1 -1
- package/dist/utils/envExampleGenerator.d.ts.map +1 -1
- package/dist/utils/envExampleGenerator.js +94 -38
- package/dist/utils/envExampleGenerator.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,14 @@ mycontext build-app --interactive
|
|
|
56
56
|
- **Build validation** before moving forward
|
|
57
57
|
- **Automatic retries** with error context (max 3 attempts)
|
|
58
58
|
|
|
59
|
+
### ✅ UI Specification System
|
|
60
|
+
|
|
61
|
+
- **Plain-English specs** from component descriptions
|
|
62
|
+
- **JSON-to-spec conversion** for structured input
|
|
63
|
+
- **Built-in templates** for common patterns (cards, forms, buttons)
|
|
64
|
+
- **Detailed implementation guidance** with accessibility & responsive requirements
|
|
65
|
+
- **Integrated workflow** with component generation
|
|
66
|
+
|
|
59
67
|
### ✅ Visual Preview
|
|
60
68
|
|
|
61
69
|
- **Figma-like component board** for visual testing
|
|
@@ -81,6 +89,14 @@ mycontext preview <type> # Preview components/app
|
|
|
81
89
|
mycontext build-app # Build complete application
|
|
82
90
|
```
|
|
83
91
|
|
|
92
|
+
### UI Specification
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
mycontext refine spec <component> --desc "description" # Generate UI spec from description
|
|
96
|
+
mycontext refine spec <component> --json-file <path> # Generate UI spec from JSON
|
|
97
|
+
mycontext generate-components all --verbose # Auto-generate specs with components
|
|
98
|
+
```
|
|
99
|
+
|
|
84
100
|
### Setup & Configuration
|
|
85
101
|
|
|
86
102
|
```bash
|
|
@@ -121,11 +137,65 @@ my-app/
|
|
|
121
137
|
│ ├── 05-component-list.json # Generated component list
|
|
122
138
|
│ └── .env # API keys
|
|
123
139
|
├── components/ # Generated components
|
|
140
|
+
│ └── dashboard/
|
|
141
|
+
│ ├── RevenueCard.tsx # Component file
|
|
142
|
+
│ ├── RevenueCard.spec.md # UI specification
|
|
143
|
+
│ └── index.ts # Export file
|
|
124
144
|
├── actions/ # Server actions (if full-stack)
|
|
125
145
|
├── app/ # Next.js routes (if full-stack)
|
|
126
146
|
└── package.json
|
|
127
147
|
```
|
|
128
148
|
|
|
149
|
+
## 📋 UI Specification Example
|
|
150
|
+
|
|
151
|
+
Generate detailed, plain-English specifications from simple descriptions:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
mycontext refine spec RevenueCard --desc "A card showing total revenue prominently with percentage change"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Output:**
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
📋 UI Specification for RevenueCard
|
|
161
|
+
|
|
162
|
+
📝 Compact Specification:
|
|
163
|
+
**RevenueCard Component - Compact Spec**
|
|
164
|
+
|
|
165
|
+
**Visual Hierarchy:**
|
|
166
|
+
- Primary: Total Revenue, $125,430
|
|
167
|
+
- Secondary: +12.5% from last month
|
|
168
|
+
|
|
169
|
+
**Layout:** vertical arrangement
|
|
170
|
+
**Spacing:** medium spacing between elements
|
|
171
|
+
**Colors:** primary, success theme
|
|
172
|
+
|
|
173
|
+
📋 Detailed Specification:
|
|
174
|
+
**RevenueCard Component - Detailed Implementation Spec**
|
|
175
|
+
|
|
176
|
+
**Component Overview:**
|
|
177
|
+
- Name: RevenueCard
|
|
178
|
+
- Type: card
|
|
179
|
+
- Description: A card component displaying revenue metrics...
|
|
180
|
+
|
|
181
|
+
**Visual Hierarchy:**
|
|
182
|
+
1. **title**: Total Revenue
|
|
183
|
+
- Prominence: medium (medium (~16px))
|
|
184
|
+
2. **value**: $125,430
|
|
185
|
+
- Prominence: high (large (~32px))
|
|
186
|
+
3. **subtitle**: +12.5% from last month
|
|
187
|
+
- Prominence: low (small (~12px))
|
|
188
|
+
|
|
189
|
+
**Accessibility Requirements:**
|
|
190
|
+
- All interactive elements must have aria-label or aria-labelledby
|
|
191
|
+
- Focus management: tab order follows visual hierarchy
|
|
192
|
+
- Color contrast: minimum 4.5:1 ratio for text
|
|
193
|
+
|
|
194
|
+
**Responsive Adjustments:**
|
|
195
|
+
- Mobile (< 768px): Reduce spacing to 12px, stack vertically
|
|
196
|
+
- Desktop (> 768px): Standard spacing, maintain layout
|
|
197
|
+
```
|
|
198
|
+
|
|
129
199
|
## 🆚 MyContext vs Others
|
|
130
200
|
|
|
131
201
|
| Feature | MyContext | Lovable | v0.dev |
|
|
@@ -134,6 +204,7 @@ my-app/
|
|
|
134
204
|
| **Validation Gates** | 12+ checkpoints | None | None |
|
|
135
205
|
| **Build Validation** | Every component | None | None |
|
|
136
206
|
| **TypeScript Guarantee** | 100% | No | No |
|
|
207
|
+
| **UI Specifications** | Plain-English | None | None |
|
|
137
208
|
| **Pricing** | BYOK ($0-20/mo) | $20-200/mo | Usage-based |
|
|
138
209
|
| **Deployment** | Anywhere | Limited | Vercel only |
|
|
139
210
|
|
|
@@ -159,6 +230,19 @@ mycontext setup # Reconfigure API keys
|
|
|
159
230
|
mycontext health-check # Verify setup
|
|
160
231
|
```
|
|
161
232
|
|
|
233
|
+
**"UI Spec Generation Failed"**
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Check if templates exist
|
|
237
|
+
ls src/templates/ui-spec-templates.json
|
|
238
|
+
|
|
239
|
+
# Generate spec with verbose output
|
|
240
|
+
mycontext refine spec ComponentName --desc "description" --verbose
|
|
241
|
+
|
|
242
|
+
# Use JSON input instead of description
|
|
243
|
+
mycontext refine spec ComponentName --json-file component.json
|
|
244
|
+
```
|
|
245
|
+
|
|
162
246
|
## 📚 Documentation
|
|
163
247
|
|
|
164
248
|
- [Getting Started](https://github.com/farajabien/mycontext-cli#quick-start)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-components.d.ts","sourceRoot":"","sources":["../../src/commands/generate-components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAW1C,UAAU,yBAA0B,SAAQ,cAAc;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,mBAAmB,GAAG,cAAc,GAAG,WAAW,CAAC;CACvE;AAID,qBAAa,yBAAyB;IACpC,OAAO,CAAC,EAAE,CAA2B;IACrC,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,kBAAkB,CAAoC;IAC9D,OAAO,CAAC,gBAAgB,CAYtB;IACF,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;YAaR,eAAe;YAiBf,kCAAkC;
|
|
1
|
+
{"version":3,"file":"generate-components.d.ts","sourceRoot":"","sources":["../../src/commands/generate-components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAW1C,UAAU,yBAA0B,SAAQ,cAAc;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,mBAAmB,GAAG,cAAc,GAAG,WAAW,CAAC;CACvE;AAID,qBAAa,yBAAyB;IACpC,OAAO,CAAC,EAAE,CAA2B;IACrC,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,kBAAkB,CAAoC;IAC9D,OAAO,CAAC,gBAAgB,CAYtB;IACF,OAAO,CAAC,WAAW,CAAa;IAGhC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;YAaR,eAAe;YAiBf,kCAAkC;IA0MhD,OAAO,CAAC,6BAA6B;IAoBrC,OAAO,CAAC,oBAAoB;IAc5B,OAAO,CAAC,sBAAsB;IAIxB,OAAO,CACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC;YAqGF,oBAAoB;IA+GlC,OAAO,CAAC,iBAAiB;YAsBX,qBAAqB;YAyKrB,sBAAsB;IAsGpC;;OAEG;YACW,kCAAkC;IA0EhD;;OAEG;YACW,gBAAgB;YAqChB,iBAAiB;IA2Q/B;;OAEG;YACW,+BAA+B;YA6F/B,cAAc;IAgD5B,OAAO,CAAC,uBAAuB;YAiFjB,oBAAoB;IAoBlC;;OAEG;YACW,mBAAmB;YAsEnB,qBAAqB;YAsCrB,cAAc;YAyDd,kBAAkB;YAgClB,mBAAmB;YAoDnB,qBAAqB;IA+InC;;;OAGG;YACW,iBAAiB;IAyF/B,OAAO,CAAC,mBAAmB;YA6Bb,kBAAkB;IA6BhC;;OAEG;YACW,4BAA4B;IAiK1C;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,sBAAsB;IA6B9B;;OAEG;YACW,iCAAiC;IA+B/C;;OAEG;YACW,qBAAqB;IAwBnC;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA6ChC;;OAEG;YACW,cAAc;IA0C5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAgC3B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAa7B;;OAEG;YACW,kBAAkB;IAUhC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA2CjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;CA+B1B"}
|
|
@@ -436,7 +436,9 @@ class GenerateComponentsCommand {
|
|
|
436
436
|
}
|
|
437
437
|
const componentList = JSON.parse(await this.fs.readFile(componentListPath));
|
|
438
438
|
// Check if complete architecture generation is requested
|
|
439
|
-
if (options.completeArchitecture ||
|
|
439
|
+
if (options.completeArchitecture ||
|
|
440
|
+
options.serverActions ||
|
|
441
|
+
options.routes) {
|
|
440
442
|
await this.generateCompleteArchitecture(componentList, options, spinner, userId);
|
|
441
443
|
return;
|
|
442
444
|
}
|
|
@@ -804,6 +806,31 @@ class GenerateComponentsCommand {
|
|
|
804
806
|
}
|
|
805
807
|
const fileBase = this.getComponentBaseName(component);
|
|
806
808
|
const componentPath = path.join(groupDir, `${fileBase}.tsx`);
|
|
809
|
+
// Generate UI specification before writing component
|
|
810
|
+
if (options.verbose) {
|
|
811
|
+
console.log(chalk_1.default.blue(`📋 Generating UI specification for ${component.name}...`));
|
|
812
|
+
try {
|
|
813
|
+
const { RefineCommand } = await Promise.resolve().then(() => __importStar(require("./refine")));
|
|
814
|
+
const refineCommand = new RefineCommand();
|
|
815
|
+
const uiSpec = await refineCommand.generateUISpec({
|
|
816
|
+
componentName: component.name,
|
|
817
|
+
description: component.description,
|
|
818
|
+
outputFormat: "compact",
|
|
819
|
+
template: "custom",
|
|
820
|
+
verbose: false,
|
|
821
|
+
});
|
|
822
|
+
// Write UI spec to file
|
|
823
|
+
const specPath = path.join(groupDir, `${fileBase}.spec.md`);
|
|
824
|
+
const specContent = `# UI Specification for ${component.name}\n\n${uiSpec.compactSpec}\n\n---\n\n${uiSpec.detailedSpec}`;
|
|
825
|
+
await this.fs.writeFile(specPath, specContent);
|
|
826
|
+
if (options.verbose) {
|
|
827
|
+
console.log(chalk_1.default.green(` ✓ UI specification generated: ${specPath}`));
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
catch (error) {
|
|
831
|
+
console.log(chalk_1.default.yellow(` ⚠️ UI spec generation failed: ${error}`));
|
|
832
|
+
}
|
|
833
|
+
}
|
|
807
834
|
// Fix common identifier issues (spaces in names) in generated code
|
|
808
835
|
const safeName = this.getComponentBaseName(component);
|
|
809
836
|
const fixedCode = codeResult.code
|
|
@@ -1572,7 +1599,9 @@ export default function PreviewPage() {
|
|
|
1572
1599
|
}
|
|
1573
1600
|
// Build complete generation queue with actions, routes, and documentation
|
|
1574
1601
|
const queue = await this.architectureEngine.buildCompleteGenerationQueue(rootComponent);
|
|
1575
|
-
spinner.success({
|
|
1602
|
+
spinner.success({
|
|
1603
|
+
text: `Architecture plan ready: ${queue.length} components with actions and routes`,
|
|
1604
|
+
});
|
|
1576
1605
|
console.log(chalk_1.default.blue("\n📋 Architecture Overview:"));
|
|
1577
1606
|
console.log(chalk_1.default.gray(` • Total Components: ${queue.length}`));
|
|
1578
1607
|
console.log(chalk_1.default.gray(` • Total Server Actions: ${queue.reduce((acc, item) => acc + item.serverActions.length, 0)}`));
|
|
@@ -1581,8 +1610,9 @@ export default function PreviewPage() {
|
|
|
1581
1610
|
// Create complete architecture plan
|
|
1582
1611
|
const architecturePlan = await this.architectureEngine.createCompleteArchitecturePlan(rootComponent, {
|
|
1583
1612
|
name: this.contextArtifacts.prd ? "Project" : "Application",
|
|
1584
|
-
description: this.contextArtifacts.prd?.split(
|
|
1585
|
-
|
|
1613
|
+
description: this.contextArtifacts.prd?.split("\n")[0] ||
|
|
1614
|
+
"Full-stack application",
|
|
1615
|
+
architecture: options.architectureType || "nextjs-app-router",
|
|
1586
1616
|
});
|
|
1587
1617
|
// Save architecture plan
|
|
1588
1618
|
const planPath = path.join(process.cwd(), ".mycontext", "architecture-plan.json");
|
|
@@ -1625,7 +1655,7 @@ export default function PreviewPage() {
|
|
|
1625
1655
|
console.log(chalk_1.default.gray(` • ${totalActions} server actions in ${actionsDir}`));
|
|
1626
1656
|
}
|
|
1627
1657
|
if (options.completeArchitecture || options.routes) {
|
|
1628
|
-
const totalRoutes = new Set(queue.flatMap(item => item.routes.map(r => r.path))).size;
|
|
1658
|
+
const totalRoutes = new Set(queue.flatMap((item) => item.routes.map((r) => r.path))).size;
|
|
1629
1659
|
console.log(chalk_1.default.gray(` • ${totalRoutes} routes in ${appDir}`));
|
|
1630
1660
|
}
|
|
1631
1661
|
console.log(chalk_1.default.blue("\n📖 Next Steps:"));
|
|
@@ -1639,7 +1669,7 @@ export default function PreviewPage() {
|
|
|
1639
1669
|
*/
|
|
1640
1670
|
convertToEnhancedComponent(componentList) {
|
|
1641
1671
|
// Find root component
|
|
1642
|
-
const rootKey = Object.keys(componentList).find(key => key !== "metadata");
|
|
1672
|
+
const rootKey = Object.keys(componentList).find((key) => key !== "metadata");
|
|
1643
1673
|
if (!rootKey)
|
|
1644
1674
|
return null;
|
|
1645
1675
|
const root = componentList[rootKey];
|
|
@@ -1656,7 +1686,7 @@ export default function PreviewPage() {
|
|
|
1656
1686
|
tags: [],
|
|
1657
1687
|
routes: [],
|
|
1658
1688
|
actions: [],
|
|
1659
|
-
children: {}
|
|
1689
|
+
children: {},
|
|
1660
1690
|
};
|
|
1661
1691
|
if (node.children) {
|
|
1662
1692
|
Object.entries(node.children).forEach(([childName, childData]) => {
|
|
@@ -1671,7 +1701,7 @@ export default function PreviewPage() {
|
|
|
1671
1701
|
async generateComponentWithArchitecture(item, options, userId) {
|
|
1672
1702
|
// Use existing generateComponent logic but return only the code
|
|
1673
1703
|
const { orchestrator } = await Promise.resolve().then(() => __importStar(require("../agents/orchestrator/SubAgentOrchestrator")));
|
|
1674
|
-
const codeResult = await orchestrator.executeAgent("CodeGenSubAgent", {
|
|
1704
|
+
const codeResult = (await orchestrator.executeAgent("CodeGenSubAgent", {
|
|
1675
1705
|
component: item.component,
|
|
1676
1706
|
group: { name: "Generated" },
|
|
1677
1707
|
options: {
|
|
@@ -1684,10 +1714,10 @@ export default function PreviewPage() {
|
|
|
1684
1714
|
stackConfig: this.stackConfig,
|
|
1685
1715
|
serverActions: item.serverActions,
|
|
1686
1716
|
routes: item.routes,
|
|
1687
|
-
actions: item.actions
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
});
|
|
1717
|
+
actions: item.actions,
|
|
1718
|
+
},
|
|
1719
|
+
},
|
|
1720
|
+
}));
|
|
1691
1721
|
return codeResult.code;
|
|
1692
1722
|
}
|
|
1693
1723
|
/**
|
|
@@ -1696,7 +1726,7 @@ export default function PreviewPage() {
|
|
|
1696
1726
|
async generateServerActions(queue, actionsDir) {
|
|
1697
1727
|
// Group actions by component
|
|
1698
1728
|
const actionsByComponent = new Map();
|
|
1699
|
-
queue.forEach(item => {
|
|
1729
|
+
queue.forEach((item) => {
|
|
1700
1730
|
if (item.serverActions.length > 0) {
|
|
1701
1731
|
actionsByComponent.set(item.component.name, item.serverActions);
|
|
1702
1732
|
}
|
|
@@ -1719,21 +1749,26 @@ import { db } from '@/lib/db';
|
|
|
1719
1749
|
import { z } from 'zod';
|
|
1720
1750
|
import { revalidatePath } from 'next/cache';
|
|
1721
1751
|
`;
|
|
1722
|
-
const actionCode = actions
|
|
1723
|
-
|
|
1752
|
+
const actionCode = actions
|
|
1753
|
+
.map((action) => {
|
|
1754
|
+
const params = action.parameters
|
|
1755
|
+
.map((p) => `${p.name}${p.required ? "" : "?"}: ${p.type}`)
|
|
1756
|
+
.join(", ");
|
|
1724
1757
|
return `
|
|
1725
1758
|
/**
|
|
1726
1759
|
* ${action.description}
|
|
1727
1760
|
*
|
|
1728
|
-
* @param {${action.parameters
|
|
1761
|
+
* @param {${action.parameters
|
|
1762
|
+
.map((p) => `${p.type}`)
|
|
1763
|
+
.join(", ")}} ${action.parameters.map((p) => p.name).join(", ")}
|
|
1729
1764
|
* @returns {Promise<${action.returns}>}
|
|
1730
1765
|
*/
|
|
1731
1766
|
export async function ${action.name}(${params}): Promise<${action.returns}> {
|
|
1732
1767
|
try {
|
|
1733
1768
|
// TODO: Implement ${action.name}
|
|
1734
|
-
${action.database ? `// Database: ${action.database}` :
|
|
1735
|
-
${action.validation ? `// Validation: ${action.validation}` :
|
|
1736
|
-
${action.middleware ? `// Middleware: ${action.middleware.join(
|
|
1769
|
+
${action.database ? `// Database: ${action.database}` : ""}
|
|
1770
|
+
${action.validation ? `// Validation: ${action.validation}` : ""}
|
|
1771
|
+
${action.middleware ? `// Middleware: ${action.middleware.join(", ")}` : ""}
|
|
1737
1772
|
|
|
1738
1773
|
throw new Error('Not implemented');
|
|
1739
1774
|
} catch (error) {
|
|
@@ -1741,7 +1776,8 @@ export async function ${action.name}(${params}): Promise<${action.returns}> {
|
|
|
1741
1776
|
throw error;
|
|
1742
1777
|
}
|
|
1743
1778
|
}`;
|
|
1744
|
-
})
|
|
1779
|
+
})
|
|
1780
|
+
.join("\n");
|
|
1745
1781
|
return `${imports}\n${actionCode}\n`;
|
|
1746
1782
|
}
|
|
1747
1783
|
/**
|
|
@@ -1750,10 +1786,13 @@ export async function ${action.name}(${params}): Promise<${action.returns}> {
|
|
|
1750
1786
|
async generateRoutes(queue, appDir, architectureType) {
|
|
1751
1787
|
const routeMap = new Map();
|
|
1752
1788
|
// Collect unique routes
|
|
1753
|
-
queue.forEach(item => {
|
|
1789
|
+
queue.forEach((item) => {
|
|
1754
1790
|
item.routes.forEach((route) => {
|
|
1755
1791
|
if (!routeMap.has(route.path)) {
|
|
1756
|
-
routeMap.set(route.path, {
|
|
1792
|
+
routeMap.set(route.path, {
|
|
1793
|
+
...route,
|
|
1794
|
+
components: [item.component.name],
|
|
1795
|
+
});
|
|
1757
1796
|
}
|
|
1758
1797
|
else {
|
|
1759
1798
|
const existing = routeMap.get(route.path);
|
|
@@ -1762,15 +1801,15 @@ export async function ${action.name}(${params}): Promise<${action.returns}> {
|
|
|
1762
1801
|
});
|
|
1763
1802
|
});
|
|
1764
1803
|
for (const [routePath, route] of routeMap.entries()) {
|
|
1765
|
-
const routeDir = path.join(appDir, routePath ===
|
|
1804
|
+
const routeDir = path.join(appDir, routePath === "/" ? "" : routePath);
|
|
1766
1805
|
await this.fs.ensureDir(routeDir);
|
|
1767
1806
|
// Generate page.tsx
|
|
1768
|
-
const pagePath = path.join(routeDir,
|
|
1807
|
+
const pagePath = path.join(routeDir, "page.tsx");
|
|
1769
1808
|
const pageContent = this.generatePageContent(route);
|
|
1770
1809
|
await this.fs.writeFile(pagePath, pageContent);
|
|
1771
1810
|
// Generate layout.tsx if specified
|
|
1772
1811
|
if (route.layout) {
|
|
1773
|
-
const layoutPath = path.join(routeDir,
|
|
1812
|
+
const layoutPath = path.join(routeDir, "layout.tsx");
|
|
1774
1813
|
const layoutContent = this.generateLayoutContent(route);
|
|
1775
1814
|
await this.fs.writeFile(layoutPath, layoutContent);
|
|
1776
1815
|
}
|
|
@@ -1781,13 +1820,17 @@ export async function ${action.name}(${params}): Promise<${action.returns}> {
|
|
|
1781
1820
|
* Generate page content for route
|
|
1782
1821
|
*/
|
|
1783
1822
|
generatePageContent(route) {
|
|
1784
|
-
const isDynamic = route.type ===
|
|
1785
|
-
const params = isDynamic ?
|
|
1823
|
+
const isDynamic = route.type === "dynamic";
|
|
1824
|
+
const params = isDynamic ? "{ params }: { params: { id: string } }" : "";
|
|
1786
1825
|
return `import { ${route.components[0]} } from '@/components/.mycontext/${this.toKebabCase(route.components[0])}/${route.components[0]}';
|
|
1787
|
-
${route.actions
|
|
1826
|
+
${route.actions
|
|
1827
|
+
.map((action) => `import { ${action} } from '@/actions/${this.toKebabCase(action)}';`)
|
|
1828
|
+
.join("\n")}
|
|
1788
1829
|
|
|
1789
1830
|
export default async function Page(${params}) {
|
|
1790
|
-
${isDynamic
|
|
1831
|
+
${isDynamic
|
|
1832
|
+
? `// Fetch data using ${route.actions[0] || "getData"}(params.id)`
|
|
1833
|
+
: ""}
|
|
1791
1834
|
|
|
1792
1835
|
return (
|
|
1793
1836
|
<div className="container mx-auto py-8">
|