# EX Script — Migration from TypeScript

## Goals

`ex migrate` converts an existing TypeScript project to EX Script:

1. **Convert common syntax** — mechanical, high-confidence rewrites.
2. **Simplify redundant types** — drop what the checker can infer.
3. **Migrate config** — map tsconfig intent to EX defaults or manifest options.
4. **Identify incompatible patterns** — a report, not silent breakage.
5. **Suggest EX equivalents** — idiomatic rewrites the converter can't do safely.
6. **Preserve behavior** — conversions never change runtime semantics; where
   behavior would differ, the pattern is reported instead.

## The conversion table

| TypeScript | EX Script | Confidence |
|---|---|---|
| `const x: T = v` | `let x = v` (inferred; `mut` if later reassigned) | high |
| `let x = v` | `let mut x = v` | high |
| `function f(a: string): number { return x; }` | `fun f(a: String) -> Int { x }` | high |
| `(a: number) => b` | `fun (a: Int) { b }` | high |
| `interface X { ... }` | `contract X { ... }` | high |
| `type X = { a: string }` | `struct X { a: String }` | high |
| `type X = A \| B` (object unions) | `type X = A \| B` variants (tagged) | medium* |
| `enum` | `enum` | high |
| `string \| undefined` | `String?` | high |
| `null` | optional `?` or removed (see report) | medium |
| `x ?? y` | `x or y` | high |
| `x?.y` | `x?.y` | high |
| `import { f } from "./m"` | `from "./m.xan" import f` | high |
| `import * as m from "pkg"` | `import pkg:m | js:pkg` | high |
| `unknown` | `Any` | high |
| `any` | `Any` + boundary report | medium |
| `as T` | report (`.require`/`schema` suggested) | low — reported |
| `throw new Error(...)` | `raise "..."` (in `!` functions) | medium |
| `try/catch` around own code | `match` on `Result` | reported |
| `class` | `class` (same shape) | high |
| `Promise<T>` return | `async fun ... -> T` (with `await` preserved) | high |
| `Array<T>` / `T[]` | `List<T>` | high |
| `Record<K, V>` | `Map<K, V>` | medium |
| generics `<T>` | `<T>` (same) | high |
| tsconfig `strict: true` | default (strict is the only mode) | high |

\* Object unions become tagged `type` variants with an added `tag` field;
untagged unions without a discriminant are reported for manual review.

## Mechanics

- `ex migrate [path]` walks `.ts`/`.tsx` files (TSX is reported, not converted
  in the prototype), parses each with the TypeScript compiler API, and emits
  `.xan` equivalents.
- Source maps: the converted file keeps `// migrated from src/foo.ts` and the
  migration report maps each conversion to the original line.
- `ex migrate` never overwrites: output goes to `ex-out/` unless `--in-place`.
- After conversion, `ex check` runs on the result; any diagnostics are added to
  the report with their fixes.

## The migration report

`ex migrate --report` produces `MIGRATION.md` listing, per file:

- converted constructs (count by category),
- incompatible patterns (with the EX idiom that replaces them),
- suggestions (optional improvements: schema for `any`-typed API responses,
  `or` for defaults, `!` for fallible functions),
- leftover TSX and dynamic features (planned conversion).

## What is NOT auto-converted (by design)

- Runtime semantics changes: `null` semantics, `throw` propagation, mutation
  patterns. These are reported with the idiomatic EX equivalent and converted
  by hand.
- `this`-heavy OOP and decorators (planned in beta).
- Untagged unions and type gymnastics (`satisfies`, conditional types).
- The report explains each with an example and a suggested rewrite.

## Preserving behavior

The converter's contract: *if a construct converts, its runtime behavior is
identical* (modulo the removal of `null` at boundaries, which is always
reported). Every conversion in the table above satisfies this; the medium/low
rows are never auto-applied, only reported.

## Migration path for a real project

1. `ex migrate src/` — produce `ex-out/` + report.
2. Fix the report items (typically a few hours per medium project).
3. `ex test` — port tests (`describe/it` → `test`; the converter maps common
   Jest/Mocha patterns) and watch everything go green.
4. `ex fmt && ex lint` — canonical formatting and clean lint.
5. Delete tsconfig and the old toolchain configs. `ex run`.