
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
morphkit-cli
Advanced tools
Semantic AI agent that converts TypeScript/React web apps to native SwiftUI iOS apps
Your React app → Native iOS. In seconds.
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+.
morphkit.dev | GitHub | Issues
# Install dependencies
bun install
# Analyze your web app and see the semantic model
bunx morphkit analyze ./my-nextjs-app
# Generate a full SwiftUI Xcode project
bunx morphkit generate ./my-nextjs-app --output ./ios-app
# Open in Xcode
open ./ios-app/MyNextjsApp/Package.swift
That's it. Three commands from web app to Xcode project.
Morphkit produces a complete, buildable Swift Package with this structure:
ios-app/
├── Package.swift # Swift Package manifest (iOS 17+)
├── MyApp/
│ ├── MyAppApp.swift # @main app entry point
│ ├── ContentView.swift # Root navigation (TabView + NavigationStack)
│ ├── Info.plist # App configuration
│ ├── Assets.xcassets/ # Colors, app icon placeholders
│ ├── Models/ # Codable structs from your TS interfaces
│ ├── Views/ # SwiftUI views from your React components
│ ├── Navigation/ # Router, routes enum, tab configuration
│ ├── Networking/ # Typed URLSession API client
│ └── State/ # @Observable stores from your state management
├── Tests/
│ └── MyAppTests.swift # Test stubs
└── README.md # Generated project documentation
Every generated file includes a source mapping comment tracing back to the original web file:
// Generated by Morphkit from: types/product.ts
Codable Swift structs and enums with full fidelity.TabView, NavigationStack, and deep link handlers.useState, Zustand stores, Redux, and Context patterns map to @Observable classes and @State bindings.fetch calls and API routes become a typed URLSession networking layer with async/await.#if DEBUG extensions with .preview() methods for every model, so SwiftUI previews work out of the box.Morphkit runs a three-stage pipeline:
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ 1. Analyze │ → │ 2. Semantic │ → │ 3. Generate │
│ │ │ Model │ │ │
│ ts-morph │ │ Zod-validated │ │ SwiftUI views │
│ AST parsing │ │ app description │ │ Swift models │
│ Route scan │ │ Platform adapt │ │ Navigation │
│ State scan │ │ │ │ Networking │
│ API scan │ │ │ │ State stores │
└─────────────┘ └──────────────────┘ └─────────────────┘
Stage 1: Analyze — Uses ts-morph 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.
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.
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.
Given this TypeScript in your Next.js app:
// types/product.ts
export interface Product {
id: string;
name: string;
description: string;
price: number;
imageUrl: string;
category: string;
inStock: boolean;
rating?: number;
createdAt: Date;
}
export type SortOrder = 'price-asc' | 'price-desc' | 'name' | 'rating';
Morphkit generates:
// Generated by Morphkit from: types/product.ts
import Foundation
struct Product: Codable, Identifiable, Hashable {
let id: String
var name: String
var description: String
var price: Double
var imageUrl: String
var category: String
var inStock: Bool
var rating: Double?
var createdAt: Date
}
enum SortOrder: String, Codable, CaseIterable {
case priceAsc = "price-asc"
case priceDesc = "price-desc"
case name
case rating
}
// MARK: - Preview Data
#if DEBUG
extension Product {
static func preview() -> Product {
Product(
id: "preview-1",
name: "Sample Product",
description: "A sample product for previewing",
price: 29.99,
imageUrl: "https://picsum.photos/200",
category: "Sample",
inStock: true,
rating: nil,
createdAt: .now
)
}
}
#endif
And your app/products/page.tsx list component becomes a native SwiftUI view:
// Generated by Morphkit from: app/products/page.tsx
import SwiftUI
struct ProductsView: View {
@State private var products: [Product] = []
@State private var searchQuery: String = ""
@State private var sortOrder: SortOrder = .priceAsc
@State private var isLoading: Bool = false
@State private var errorMessage: String?
var body: some View {
List {
ForEach(products) { product in
NavigationLink(value: AppRoute.productsDetail(id: product.id)) {
HStack(spacing: 12) {
AsyncImage(url: URL(string: product.imageUrl)) { image in
image.resizable().aspectRatio(contentMode: .fill)
} placeholder: {
Image(systemName: "photo.circle.fill")
.foregroundStyle(.secondary)
}
.frame(width: 44, height: 44)
.clipShape(RoundedRectangle(cornerRadius: 8))
VStack(alignment: .leading, spacing: 4) {
Text(product.name)
.font(.headline)
Text(product.category)
.font(.subheadline)
.foregroundStyle(.secondary)
Text(product.price, format: .currency(code: "USD"))
.font(.subheadline)
.fontWeight(.semibold)
}
Spacer()
}
}
}
}
.searchable(text: $searchQuery)
.refreshable { await loadData() }
.navigationTitle("Products")
.task { await loadData() }
}
private func loadData() async {
isLoading = true
defer { isLoading = false }
do {
products = try await APIClient.shared.fetchProduct()
} catch {
errorMessage = error.localizedDescription
}
}
}
The root ContentView.swift wires everything together with tab-based navigation:
// Generated by Morphkit
import SwiftUI
struct ContentView: View {
@State private var router = Router()
var body: some View {
TabView(selection: $router.selectedTab) {
NavigationStack {
HomeView()
.navigationDestination(for: AppRoute.self) { route in
routeView(for: route)
}
}
.tabItem {
Label(AppTab.home.title, systemImage: AppTab.home.systemImage)
}
.tag(AppTab.home)
// ... Products, Cart tabs
}
.environment(router)
.onOpenURL { url in
router.handleDeepLink(url)
}
}
}
morphkit analyze <path>Analyze a web app and output its semantic model as JSON.
bunx morphkit analyze ./my-app
bunx morphkit analyze ./my-app --output model.json
bunx morphkit analyze ./my-app --verbose
| Option | Description |
|---|---|
-o, --output <file> | Write the semantic model JSON to a file instead of stdout |
-v, --verbose | Show detailed analysis output (component counts, route counts, etc.) |
morphkit generate <path>Generate a complete SwiftUI Xcode project from a web app.
bunx morphkit generate ./my-app
bunx morphkit generate ./my-app --output ./ios-app --name ShopKit
bunx morphkit generate ./my-app --model model.json
| Option | Description |
|---|---|
-o, --output <dir> | Output directory for the iOS project (default: ./ios-app) |
-n, --name <name> | App name — must be PascalCase (default: from package.json) |
--model <file> | Use a pre-built semantic model JSON instead of re-analyzing |
-v, --verbose | Show detailed generation output |
morphkit preview <path>Preview what would be generated without writing any files to disk.
bunx morphkit preview ./my-app
bunx morphkit preview ./my-app --screen Products
| Option | Description |
|---|---|
-s, --screen <name> | Preview only files matching a specific screen name |
| Variable | Required | Description |
|---|---|---|
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. |
When XAI_API_KEY is set, Morphkit can use xAI Grok to:
@Observable store structure based on your Zustand/Redux/Context patternsThe AI layer is fully optional. All core functionality works without it.
| Framework | Status | Notes |
|---|---|---|
| Next.js App Router | Supported | Full support for file-based routing, layouts, loading states, API routes |
| Next.js Pages Router | Planned | Route detection works; component analysis coming |
| React + Vite | Planned | Component and state extraction works; routing TBD |
| React + CRA | Planned | Same as Vite support |
| Web Pattern | iOS Equivalent |
|---|---|
useState | @State |
| Zustand stores | @Observable classes |
| Redux stores | @Observable singletons via @Environment |
| React Context | @Environment with custom EnvironmentKey |
| React Query / SWR | async/await with .task { } |
fetch / axios | Typed URLSession via APIClient |
| Next.js file routing | NavigationStack + TabView |
Dynamic routes ([id]) | .navigationDestination(for:) |
| CSS / Tailwind | SwiftUI modifiers + theme configuration |
src/
├── index.ts # CLI entry (Commander.js + chalk + ora)
├── analyzer/ # Stage 1: Web app analysis
│ ├── repo-scanner.ts # File discovery, framework detection
│ ├── ast-parser.ts # TypeScript AST parsing (ts-morph)
│ ├── component-extractor # React component analysis
│ ├── route-extractor # Next.js route tree extraction
│ ├── state-extractor # State management detection
│ └── api-extractor # API endpoint extraction
├── semantic/ # Stage 2: Semantic model
│ ├── model.ts # Zod schemas (single source of truth for all types)
│ ├── builder.ts # Analyzer output → SemanticAppModel
│ └── adapter.ts # Web patterns → iOS patterns
├── generator/ # Stage 3: SwiftUI code generation
│ ├── swiftui-generator # View generation (List, Form, Detail, Dashboard)
│ ├── model-generator # Swift Codable structs from entities
│ ├── navigation-generator # TabView, NavigationStack, Router
│ ├── networking-generator # URLSession API client
│ └── project-generator # Xcode project orchestrator
└── ai/ # AI integration (optional)
├── grok-client.ts # OpenAI SDK → xAI endpoint
├── structured-output.ts # Zod schemas for AI responses
└── prompts/ # Intent, component, code gen prompts
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.
git clone https://github.com/ashlrai/morphkit.git
cd morphkit
bun install
# Run all tests (53 tests, 376 assertions)
bun test
# TypeScript strict type checking
bun run typecheck
# Run against a local web app
bun run src/index.ts analyze ./path-to-app
bun run src/index.ts generate ./path-to-app --output ./ios-output
bun run src/index.ts preview ./path-to-app
The test suite covers the full pipeline with a sample Next.js e-commerce app (test/__fixtures__/sample-nextjs-app/):
53 pass | 0 fail | 376 expect() calls
z.infer<> (see src/semantic/model.ts)@Observable, not ObservableObject; #Preview, not PreviewProvider)MIT — AshlrAI
FAQs
Semantic AI agent that converts TypeScript/React web apps to native SwiftUI iOS apps
The npm package morphkit-cli receives a total of 12 weekly downloads. As such, morphkit-cli popularity was classified as not popular.
We found that morphkit-cli demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.