morphkit-cli 0.1.0
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/LICENSE +21 -0
- package/README.md +449 -0
- package/dist/index.js +30940 -0
- package/package.json +60 -0
- package/templates/swift/app-entry.swift.ts +46 -0
- package/templates/swift/model.swift.ts +72 -0
- package/templates/swiftui/navigation.swift.ts +118 -0
- package/templates/swiftui/networking.swift.ts +145 -0
- package/templates/swiftui/view.swift.ts +230 -0
- package/templates/xcode-project/assets.ts +112 -0
- package/templates/xcode-project/info-plist.ts +115 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AshlrAI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
# Morphkit
|
|
2
|
+
|
|
3
|
+
> Your React app → Native iOS. In seconds.
|
|
4
|
+
|
|
5
|
+
Morphkit is a semantic AI agent that understands your TypeScript/React web app's *intent* — not just its code — and generates a production-quality SwiftUI Xcode project. It parses your components, routes, state, and API calls, builds a framework-agnostic semantic model, then emits idiomatic Swift targeting iOS 17+.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/morphkit)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
**[morphkit.dev](https://morphkit.dev)** | **[GitHub](https://github.com/ashlrai/morphkit)** | **[Issues](https://github.com/ashlrai/morphkit/issues)**
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Install dependencies
|
|
18
|
+
bun install
|
|
19
|
+
|
|
20
|
+
# Analyze your web app and see the semantic model
|
|
21
|
+
bunx morphkit analyze ./my-nextjs-app
|
|
22
|
+
|
|
23
|
+
# Generate a full SwiftUI Xcode project
|
|
24
|
+
bunx morphkit generate ./my-nextjs-app --output ./ios-app
|
|
25
|
+
|
|
26
|
+
# Open in Xcode
|
|
27
|
+
open ./ios-app/MyNextjsApp/Package.swift
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That's it. Three commands from web app to Xcode project.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## What Gets Generated
|
|
35
|
+
|
|
36
|
+
Morphkit produces a complete, buildable Swift Package with this structure:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
ios-app/
|
|
40
|
+
├── Package.swift # Swift Package manifest (iOS 17+)
|
|
41
|
+
├── MyApp/
|
|
42
|
+
│ ├── MyAppApp.swift # @main app entry point
|
|
43
|
+
│ ├── ContentView.swift # Root navigation (TabView + NavigationStack)
|
|
44
|
+
│ ├── Info.plist # App configuration
|
|
45
|
+
│ ├── Assets.xcassets/ # Colors, app icon placeholders
|
|
46
|
+
│ ├── Models/ # Codable structs from your TS interfaces
|
|
47
|
+
│ ├── Views/ # SwiftUI views from your React components
|
|
48
|
+
│ ├── Navigation/ # Router, routes enum, tab configuration
|
|
49
|
+
│ ├── Networking/ # Typed URLSession API client
|
|
50
|
+
│ └── State/ # @Observable stores from your state management
|
|
51
|
+
├── Tests/
|
|
52
|
+
│ └── MyAppTests.swift # Test stubs
|
|
53
|
+
└── README.md # Generated project documentation
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Every generated file includes a source mapping comment tracing back to the original web file:
|
|
57
|
+
|
|
58
|
+
```swift
|
|
59
|
+
// Generated by Morphkit from: types/product.ts
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
- **Semantic understanding** — Morphkit doesn't do string replacement. It builds an intermediate *semantic model* that captures what your app does, then generates native code from that understanding.
|
|
67
|
+
- **Full TypeScript type extraction** — Interfaces, type aliases, enums, and union types are converted to `Codable` Swift structs and enums with full fidelity.
|
|
68
|
+
- **React component analysis** — Detects layout patterns (list, detail, form, dashboard, settings) and generates the appropriate SwiftUI view composition.
|
|
69
|
+
- **Route-to-navigation mapping** — Next.js App Router file-based routes become `TabView`, `NavigationStack`, and deep link handlers.
|
|
70
|
+
- **State management translation** — `useState`, Zustand stores, Redux, and Context patterns map to `@Observable` classes and `@State` bindings.
|
|
71
|
+
- **API client generation** — `fetch` calls and API routes become a typed `URLSession` networking layer with `async/await`.
|
|
72
|
+
- **Confidence scoring** — Every generated file is tagged high/medium/low confidence so you know what to review first.
|
|
73
|
+
- **Preview data factories** — `#if DEBUG` extensions with `.preview()` methods for every model, so SwiftUI previews work out of the box.
|
|
74
|
+
- **AI-enhanced analysis (optional)** — Connect xAI Grok for deeper intent extraction, smarter component mapping, and navigation planning.
|
|
75
|
+
- **Zero runtime dependencies** — Generated Swift code uses only Foundation and SwiftUI. No third-party pods or packages.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## How It Works
|
|
80
|
+
|
|
81
|
+
Morphkit runs a three-stage pipeline:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
85
|
+
│ 1. Analyze │ → │ 2. Semantic │ → │ 3. Generate │
|
|
86
|
+
│ │ │ Model │ │ │
|
|
87
|
+
│ ts-morph │ │ Zod-validated │ │ SwiftUI views │
|
|
88
|
+
│ AST parsing │ │ app description │ │ Swift models │
|
|
89
|
+
│ Route scan │ │ Platform adapt │ │ Navigation │
|
|
90
|
+
│ State scan │ │ │ │ Networking │
|
|
91
|
+
│ API scan │ │ │ │ State stores │
|
|
92
|
+
└─────────────┘ └──────────────────┘ └─────────────────┘
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Stage 1: Analyze** — Uses [ts-morph](https://ts-morph.com) to parse your TypeScript AST. Extracts components, routes, state patterns, API calls, types, and framework metadata. Detects Next.js App Router, Pages Router, or plain React.
|
|
96
|
+
|
|
97
|
+
**Stage 2: Semantic Model** — Builds a framework-agnostic `SemanticAppModel` (validated with Zod schemas) that describes *what* the app does: its entities, screens, navigation flows, state management, API endpoints, auth patterns, and theme. An optional platform adapter then maps web patterns to iOS equivalents.
|
|
98
|
+
|
|
99
|
+
**Stage 3: Generate** — Five specialized generators emit Swift code from the semantic model: views, models, navigation, networking, and state. The output is a complete Swift Package that opens directly in Xcode.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Example
|
|
104
|
+
|
|
105
|
+
Given this TypeScript in your Next.js app:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// types/product.ts
|
|
109
|
+
export interface Product {
|
|
110
|
+
id: string;
|
|
111
|
+
name: string;
|
|
112
|
+
description: string;
|
|
113
|
+
price: number;
|
|
114
|
+
imageUrl: string;
|
|
115
|
+
category: string;
|
|
116
|
+
inStock: boolean;
|
|
117
|
+
rating?: number;
|
|
118
|
+
createdAt: Date;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type SortOrder = 'price-asc' | 'price-desc' | 'name' | 'rating';
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Morphkit generates:
|
|
125
|
+
|
|
126
|
+
```swift
|
|
127
|
+
// Generated by Morphkit from: types/product.ts
|
|
128
|
+
|
|
129
|
+
import Foundation
|
|
130
|
+
|
|
131
|
+
struct Product: Codable, Identifiable, Hashable {
|
|
132
|
+
let id: String
|
|
133
|
+
var name: String
|
|
134
|
+
var description: String
|
|
135
|
+
var price: Double
|
|
136
|
+
var imageUrl: String
|
|
137
|
+
var category: String
|
|
138
|
+
var inStock: Bool
|
|
139
|
+
var rating: Double?
|
|
140
|
+
var createdAt: Date
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
enum SortOrder: String, Codable, CaseIterable {
|
|
144
|
+
case priceAsc = "price-asc"
|
|
145
|
+
case priceDesc = "price-desc"
|
|
146
|
+
case name
|
|
147
|
+
case rating
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// MARK: - Preview Data
|
|
151
|
+
|
|
152
|
+
#if DEBUG
|
|
153
|
+
extension Product {
|
|
154
|
+
static func preview() -> Product {
|
|
155
|
+
Product(
|
|
156
|
+
id: "preview-1",
|
|
157
|
+
name: "Sample Product",
|
|
158
|
+
description: "A sample product for previewing",
|
|
159
|
+
price: 29.99,
|
|
160
|
+
imageUrl: "https://picsum.photos/200",
|
|
161
|
+
category: "Sample",
|
|
162
|
+
inStock: true,
|
|
163
|
+
rating: nil,
|
|
164
|
+
createdAt: .now
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
#endif
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
And your `app/products/page.tsx` list component becomes a native SwiftUI view:
|
|
172
|
+
|
|
173
|
+
```swift
|
|
174
|
+
// Generated by Morphkit from: app/products/page.tsx
|
|
175
|
+
|
|
176
|
+
import SwiftUI
|
|
177
|
+
|
|
178
|
+
struct ProductsView: View {
|
|
179
|
+
@State private var products: [Product] = []
|
|
180
|
+
@State private var searchQuery: String = ""
|
|
181
|
+
@State private var sortOrder: SortOrder = .priceAsc
|
|
182
|
+
@State private var isLoading: Bool = false
|
|
183
|
+
@State private var errorMessage: String?
|
|
184
|
+
|
|
185
|
+
var body: some View {
|
|
186
|
+
List {
|
|
187
|
+
ForEach(products) { product in
|
|
188
|
+
NavigationLink(value: AppRoute.productsDetail(id: product.id)) {
|
|
189
|
+
HStack(spacing: 12) {
|
|
190
|
+
AsyncImage(url: URL(string: product.imageUrl)) { image in
|
|
191
|
+
image.resizable().aspectRatio(contentMode: .fill)
|
|
192
|
+
} placeholder: {
|
|
193
|
+
Image(systemName: "photo.circle.fill")
|
|
194
|
+
.foregroundStyle(.secondary)
|
|
195
|
+
}
|
|
196
|
+
.frame(width: 44, height: 44)
|
|
197
|
+
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
198
|
+
VStack(alignment: .leading, spacing: 4) {
|
|
199
|
+
Text(product.name)
|
|
200
|
+
.font(.headline)
|
|
201
|
+
Text(product.category)
|
|
202
|
+
.font(.subheadline)
|
|
203
|
+
.foregroundStyle(.secondary)
|
|
204
|
+
Text(product.price, format: .currency(code: "USD"))
|
|
205
|
+
.font(.subheadline)
|
|
206
|
+
.fontWeight(.semibold)
|
|
207
|
+
}
|
|
208
|
+
Spacer()
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
.searchable(text: $searchQuery)
|
|
214
|
+
.refreshable { await loadData() }
|
|
215
|
+
.navigationTitle("Products")
|
|
216
|
+
.task { await loadData() }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private func loadData() async {
|
|
220
|
+
isLoading = true
|
|
221
|
+
defer { isLoading = false }
|
|
222
|
+
do {
|
|
223
|
+
products = try await APIClient.shared.fetchProduct()
|
|
224
|
+
} catch {
|
|
225
|
+
errorMessage = error.localizedDescription
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The root `ContentView.swift` wires everything together with tab-based navigation:
|
|
232
|
+
|
|
233
|
+
```swift
|
|
234
|
+
// Generated by Morphkit
|
|
235
|
+
|
|
236
|
+
import SwiftUI
|
|
237
|
+
|
|
238
|
+
struct ContentView: View {
|
|
239
|
+
@State private var router = Router()
|
|
240
|
+
|
|
241
|
+
var body: some View {
|
|
242
|
+
TabView(selection: $router.selectedTab) {
|
|
243
|
+
NavigationStack {
|
|
244
|
+
HomeView()
|
|
245
|
+
.navigationDestination(for: AppRoute.self) { route in
|
|
246
|
+
routeView(for: route)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
.tabItem {
|
|
250
|
+
Label(AppTab.home.title, systemImage: AppTab.home.systemImage)
|
|
251
|
+
}
|
|
252
|
+
.tag(AppTab.home)
|
|
253
|
+
// ... Products, Cart tabs
|
|
254
|
+
}
|
|
255
|
+
.environment(router)
|
|
256
|
+
.onOpenURL { url in
|
|
257
|
+
router.handleDeepLink(url)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## CLI Reference
|
|
266
|
+
|
|
267
|
+
### `morphkit analyze <path>`
|
|
268
|
+
|
|
269
|
+
Analyze a web app and output its semantic model as JSON.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
bunx morphkit analyze ./my-app
|
|
273
|
+
bunx morphkit analyze ./my-app --output model.json
|
|
274
|
+
bunx morphkit analyze ./my-app --verbose
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
| Option | Description |
|
|
278
|
+
|--------|-------------|
|
|
279
|
+
| `-o, --output <file>` | Write the semantic model JSON to a file instead of stdout |
|
|
280
|
+
| `-v, --verbose` | Show detailed analysis output (component counts, route counts, etc.) |
|
|
281
|
+
|
|
282
|
+
### `morphkit generate <path>`
|
|
283
|
+
|
|
284
|
+
Generate a complete SwiftUI Xcode project from a web app.
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
bunx morphkit generate ./my-app
|
|
288
|
+
bunx morphkit generate ./my-app --output ./ios-app --name ShopKit
|
|
289
|
+
bunx morphkit generate ./my-app --model model.json
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
| Option | Description |
|
|
293
|
+
|--------|-------------|
|
|
294
|
+
| `-o, --output <dir>` | Output directory for the iOS project (default: `./ios-app`) |
|
|
295
|
+
| `-n, --name <name>` | App name — must be PascalCase (default: from `package.json`) |
|
|
296
|
+
| `--model <file>` | Use a pre-built semantic model JSON instead of re-analyzing |
|
|
297
|
+
| `-v, --verbose` | Show detailed generation output |
|
|
298
|
+
|
|
299
|
+
### `morphkit preview <path>`
|
|
300
|
+
|
|
301
|
+
Preview what would be generated without writing any files to disk.
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
bunx morphkit preview ./my-app
|
|
305
|
+
bunx morphkit preview ./my-app --screen Products
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
| Option | Description |
|
|
309
|
+
|--------|-------------|
|
|
310
|
+
| `-s, --screen <name>` | Preview only files matching a specific screen name |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Configuration
|
|
315
|
+
|
|
316
|
+
### Environment Variables
|
|
317
|
+
|
|
318
|
+
| Variable | Required | Description |
|
|
319
|
+
|----------|----------|-------------|
|
|
320
|
+
| `XAI_API_KEY` | No | xAI API key for AI-enhanced analysis. When set, Morphkit uses Grok (`grok-4-1-fast-reasoning`) for deeper intent extraction, component mapping, navigation planning, and state architecture recommendations. Without it, Morphkit falls back to heuristic-based analysis. |
|
|
321
|
+
|
|
322
|
+
### AI Enhancement (Optional)
|
|
323
|
+
|
|
324
|
+
When `XAI_API_KEY` is set, Morphkit can use xAI Grok to:
|
|
325
|
+
|
|
326
|
+
- **Analyze intent** — understand *why* a component exists, not just what it renders
|
|
327
|
+
- **Map components** — intelligently match React patterns to SwiftUI equivalents
|
|
328
|
+
- **Plan navigation** — decide whether tabs, stacks, or mixed patterns are most idiomatic
|
|
329
|
+
- **Architect state** — recommend `@Observable` store structure based on your Zustand/Redux/Context patterns
|
|
330
|
+
- **Generate code** — produce more nuanced SwiftUI for complex screen layouts
|
|
331
|
+
|
|
332
|
+
The AI layer is fully optional. All core functionality works without it.
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Supported Frameworks
|
|
337
|
+
|
|
338
|
+
| Framework | Status | Notes |
|
|
339
|
+
|-----------|--------|-------|
|
|
340
|
+
| Next.js App Router | Supported | Full support for file-based routing, layouts, loading states, API routes |
|
|
341
|
+
| Next.js Pages Router | Planned | Route detection works; component analysis coming |
|
|
342
|
+
| React + Vite | Planned | Component and state extraction works; routing TBD |
|
|
343
|
+
| React + CRA | Planned | Same as Vite support |
|
|
344
|
+
|
|
345
|
+
### Supported Web Patterns
|
|
346
|
+
|
|
347
|
+
| Web Pattern | iOS Equivalent |
|
|
348
|
+
|-------------|----------------|
|
|
349
|
+
| `useState` | `@State` |
|
|
350
|
+
| Zustand stores | `@Observable` classes |
|
|
351
|
+
| Redux stores | `@Observable` singletons via `@Environment` |
|
|
352
|
+
| React Context | `@Environment` with custom `EnvironmentKey` |
|
|
353
|
+
| React Query / SWR | `async/await` with `.task { }` |
|
|
354
|
+
| `fetch` / `axios` | Typed `URLSession` via `APIClient` |
|
|
355
|
+
| Next.js file routing | `NavigationStack` + `TabView` |
|
|
356
|
+
| Dynamic routes (`[id]`) | `.navigationDestination(for:)` |
|
|
357
|
+
| CSS / Tailwind | SwiftUI modifiers + theme configuration |
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Architecture
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
src/
|
|
365
|
+
├── index.ts # CLI entry (Commander.js + chalk + ora)
|
|
366
|
+
├── analyzer/ # Stage 1: Web app analysis
|
|
367
|
+
│ ├── repo-scanner.ts # File discovery, framework detection
|
|
368
|
+
│ ├── ast-parser.ts # TypeScript AST parsing (ts-morph)
|
|
369
|
+
│ ├── component-extractor # React component analysis
|
|
370
|
+
│ ├── route-extractor # Next.js route tree extraction
|
|
371
|
+
│ ├── state-extractor # State management detection
|
|
372
|
+
│ └── api-extractor # API endpoint extraction
|
|
373
|
+
├── semantic/ # Stage 2: Semantic model
|
|
374
|
+
│ ├── model.ts # Zod schemas (single source of truth for all types)
|
|
375
|
+
│ ├── builder.ts # Analyzer output → SemanticAppModel
|
|
376
|
+
│ └── adapter.ts # Web patterns → iOS patterns
|
|
377
|
+
├── generator/ # Stage 3: SwiftUI code generation
|
|
378
|
+
│ ├── swiftui-generator # View generation (List, Form, Detail, Dashboard)
|
|
379
|
+
│ ├── model-generator # Swift Codable structs from entities
|
|
380
|
+
│ ├── navigation-generator # TabView, NavigationStack, Router
|
|
381
|
+
│ ├── networking-generator # URLSession API client
|
|
382
|
+
│ └── project-generator # Xcode project orchestrator
|
|
383
|
+
└── ai/ # AI integration (optional)
|
|
384
|
+
├── grok-client.ts # OpenAI SDK → xAI endpoint
|
|
385
|
+
├── structured-output.ts # Zod schemas for AI responses
|
|
386
|
+
└── prompts/ # Intent, component, code gen prompts
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
The `SemanticAppModel` (defined as Zod schemas in `src/semantic/model.ts`) is the central contract. Everything before it is analysis; everything after it is generation. This separation means you can swap out the analyzer (to support Vue, Angular, etc.) or the generator (to target Kotlin/Compose, Flutter, etc.) without touching the other side.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Development
|
|
394
|
+
|
|
395
|
+
### Prerequisites
|
|
396
|
+
|
|
397
|
+
- [Bun](https://bun.sh) 1.0+
|
|
398
|
+
- Node.js 20+ (alternative runtime)
|
|
399
|
+
- TypeScript 5.7+
|
|
400
|
+
|
|
401
|
+
### Setup
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
git clone https://github.com/ashlrai/morphkit.git
|
|
405
|
+
cd morphkit
|
|
406
|
+
bun install
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Commands
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# Run all tests (53 tests, 376 assertions)
|
|
413
|
+
bun test
|
|
414
|
+
|
|
415
|
+
# TypeScript strict type checking
|
|
416
|
+
bun run typecheck
|
|
417
|
+
|
|
418
|
+
# Run against a local web app
|
|
419
|
+
bun run src/index.ts analyze ./path-to-app
|
|
420
|
+
bun run src/index.ts generate ./path-to-app --output ./ios-output
|
|
421
|
+
bun run src/index.ts preview ./path-to-app
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
### Test Suite
|
|
425
|
+
|
|
426
|
+
The test suite covers the full pipeline with a sample Next.js e-commerce app (`test/__fixtures__/sample-nextjs-app/`):
|
|
427
|
+
|
|
428
|
+
- **Analyzer tests** — AST parsing, component extraction, route detection, state pattern recognition
|
|
429
|
+
- **Semantic tests** — Model building, type mapping, adapter transformations
|
|
430
|
+
- **Generator tests** — Swift model output, view generation, navigation, networking
|
|
431
|
+
- **E2E tests** — Full pipeline from source scan to generated Xcode project
|
|
432
|
+
- **Swift quality tests** — Validates generated code compiles and follows iOS conventions
|
|
433
|
+
|
|
434
|
+
```
|
|
435
|
+
53 pass | 0 fail | 376 expect() calls
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Project Conventions
|
|
439
|
+
|
|
440
|
+
- All types are Zod schemas first, TypeScript types inferred via `z.infer<>` (see `src/semantic/model.ts`)
|
|
441
|
+
- Generated Swift targets iOS 17+ (`@Observable`, not `ObservableObject`; `#Preview`, not `PreviewProvider`)
|
|
442
|
+
- Entity names are PascalCase, variables camelCase in generated Swift
|
|
443
|
+
- Every generated file carries confidence scoring and source provenance
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## License
|
|
448
|
+
|
|
449
|
+
MIT — [AshlrAI](https://ashlr.ai)
|