mycontext-cli 2.0.6 → 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 +94 -9
- 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 +6 -5
- 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/dist/utils/mcpTools.d.ts +22 -21
- package/dist/utils/mcpTools.d.ts.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -20,16 +20,17 @@ mycontext init my-app
|
|
|
20
20
|
# 2. Generate context files (PRD, features, etc.)
|
|
21
21
|
mycontext generate-context-files --description "Your app idea"
|
|
22
22
|
|
|
23
|
-
# 3.
|
|
23
|
+
# 3. Component list is generated automatically
|
|
24
|
+
# 4. Compile PRD (requires approval)
|
|
24
25
|
mycontext compile-prd
|
|
25
26
|
|
|
26
|
-
#
|
|
27
|
+
# 5. Generate components with validation
|
|
27
28
|
mycontext generate-components all --with-tests
|
|
28
29
|
|
|
29
|
-
#
|
|
30
|
+
# 6. Preview components visually
|
|
30
31
|
mycontext preview components
|
|
31
32
|
|
|
32
|
-
#
|
|
33
|
+
# 7. Build complete app when ready
|
|
33
34
|
mycontext build-app --interactive
|
|
34
35
|
```
|
|
35
36
|
|
|
@@ -38,7 +39,7 @@ mycontext build-app --interactive
|
|
|
38
39
|
**Start Small, Scale Gradually:**
|
|
39
40
|
|
|
40
41
|
1. **Context Files** → Define your app (PRD, features, technical specs)
|
|
41
|
-
2. **Component List** → AI generates list of needed components
|
|
42
|
+
2. **Component List** → AI automatically generates list of needed components
|
|
42
43
|
3. **Build Strategy** → Choose how to approach development
|
|
43
44
|
4. **Component Generation** → Build components one by one with validation
|
|
44
45
|
5. **Visual Preview** → See components in browser before integration
|
|
@@ -55,6 +56,14 @@ mycontext build-app --interactive
|
|
|
55
56
|
- **Build validation** before moving forward
|
|
56
57
|
- **Automatic retries** with error context (max 3 attempts)
|
|
57
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
|
+
|
|
58
67
|
### ✅ Visual Preview
|
|
59
68
|
|
|
60
69
|
- **Figma-like component board** for visual testing
|
|
@@ -80,6 +89,14 @@ mycontext preview <type> # Preview components/app
|
|
|
80
89
|
mycontext build-app # Build complete application
|
|
81
90
|
```
|
|
82
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
|
+
|
|
83
100
|
### Setup & Configuration
|
|
84
101
|
|
|
85
102
|
```bash
|
|
@@ -120,11 +137,65 @@ my-app/
|
|
|
120
137
|
│ ├── 05-component-list.json # Generated component list
|
|
121
138
|
│ └── .env # API keys
|
|
122
139
|
├── components/ # Generated components
|
|
140
|
+
│ └── dashboard/
|
|
141
|
+
│ ├── RevenueCard.tsx # Component file
|
|
142
|
+
│ ├── RevenueCard.spec.md # UI specification
|
|
143
|
+
│ └── index.ts # Export file
|
|
123
144
|
├── actions/ # Server actions (if full-stack)
|
|
124
145
|
├── app/ # Next.js routes (if full-stack)
|
|
125
146
|
└── package.json
|
|
126
147
|
```
|
|
127
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
|
+
|
|
128
199
|
## 🆚 MyContext vs Others
|
|
129
200
|
|
|
130
201
|
| Feature | MyContext | Lovable | v0.dev |
|
|
@@ -133,6 +204,7 @@ my-app/
|
|
|
133
204
|
| **Validation Gates** | 12+ checkpoints | None | None |
|
|
134
205
|
| **Build Validation** | Every component | None | None |
|
|
135
206
|
| **TypeScript Guarantee** | 100% | No | No |
|
|
207
|
+
| **UI Specifications** | Plain-English | None | None |
|
|
136
208
|
| **Pricing** | BYOK ($0-20/mo) | $20-200/mo | Usage-based |
|
|
137
209
|
| **Deployment** | Anywhere | Limited | Vercel only |
|
|
138
210
|
|
|
@@ -158,15 +230,28 @@ mycontext setup # Reconfigure API keys
|
|
|
158
230
|
mycontext health-check # Verify setup
|
|
159
231
|
```
|
|
160
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
|
+
|
|
161
246
|
## 📚 Documentation
|
|
162
247
|
|
|
163
|
-
- [Getting Started](https://github.com/farajabien/mycontext-
|
|
164
|
-
- [Component Generation](https://github.com/farajabien/mycontext-
|
|
165
|
-
- [Build Strategies](https://github.com/farajabien/mycontext-
|
|
248
|
+
- [Getting Started](https://github.com/farajabien/mycontext-cli#quick-start)
|
|
249
|
+
- [Component Generation](https://github.com/farajabien/mycontext-cli#commands)
|
|
250
|
+
- [Build Strategies](https://github.com/farajabien/mycontext-cli#philosophy-component-first-development)
|
|
166
251
|
|
|
167
252
|
## 🤝 Contributing
|
|
168
253
|
|
|
169
|
-
|
|
254
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
170
255
|
|
|
171
256
|
## 📄 License
|
|
172
257
|
|
|
@@ -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">
|