Real repos · pinned commits · compiler-judged

    The JavaScript → TypeScriptmigration benchmark

    We migrated five real open-source codebases with Refactyl, with airbnb/ts-migrate, and with a raw LLM, then let the TypeScript compiler judge every output. No cherry-picking: these are the numbers.

    This benchmark measures the JavaScript to TypeScript migration. Run yours free, up to 100 files, no credit card.

    ts-migrate: 0 of 5 repos

    The 600K-downloads/month incumbent failed to convert a single file on any repo. It crashes on modern Node, abandoned in practice, not just on paper.

    Raw LLMs hide errors behind “any”

    The same model, prompted naively, floods code with any (up to 40/KLOC), silencing the compiler instead of typing the code. Error count alone is a gameable metric.

    Refactyl wins both metrics at once

    Fewer compiler errors AND 3–30× lower any-density on all five repos. The compiler-feedback repair loop fixes errors with real types, not escapes.

    Results

    Judge: npm install + tsc --noEmit on each tool's delivered output. errors = remaining TypeScript compiler errors (lower is better). any/KLOC = explicit any per 1,000 lines of produced TypeScript (lower is better; it measures whether the code is actually typed).

    These are single-pass counts (one transform, then measure) so you can see the raw model output before our repair loop touches it. The shipped product runs Verify & Repair until tsc is clean or the file is honestly flagged.

    RepositoryRefactyl
    errors · any/KLOC
    Raw gpt-4.1-mini
    errors · any/KLOC
    ts-migrate
    expressjs/multer @ v1.4.5-lts.17 · 10.340 · 25.3also broke npm installdid not run
    winstonjs/winston @ v3.13.042 · 4.993 · 39.7did not run
    debug-js/debug @ 4.3.422 · 0.944 · 28.2did not run
    websockets/ws @ 8.17.090 · 8.9133 · 18.9did not run
    expressjs/serve-static @ v1.15.01 · 0.010 · 3.8did not run

    Run of July 3, 2026. Repos cloned at the pinned tags shown; test/bench directories intentionally remain JavaScript in phase one (standard migration practice) for every tool equally. “did not run” = ts-migrate-full crashed before converting any file.

    Why we publish two numbers

    Any tool can reach “zero errors” by writing const user: any everywhere. That was ts-migrate's documented approach (any + @ts-expect-error by design), and it's what raw LLM prompting drifts toward. You end up with files that compile but aren't typed: no autocomplete, no refactoring safety, no caught bugs.

    So we hold every tool to both standards at once: how many compiler errors remain, and how much of the “typing” is actually escape hatches. Refactyl's pipeline is built for that combination: deterministic transforms for the known-in-advance changes, model conversion for the judgement calls, and a compiler-feedback loop that repairs each file against its real tsc errors with precise types (never @ts-ignore, never any as a fix).

    The same loop runs inside every Refactyl migration you start. The benchmark measures the product, not a demo build.

    Methodology (reproducible)

    Run it on your codebase

    Upload a repo, get compiler-verified TypeScript back: typed signatures and real interfaces, not any-everywhere. Your first migration is free.

    Vue 2→3 · Real repos · @vue/compiler-sfc judged

    The Vue 2 → Vue 3migration benchmark

    We migrated five real open-source Vue 2 codebases with Refactyl, with vue-codemod, and with a raw LLM, then let @vue/compiler-sfc judge every output. Same dual-metric philosophy as the JS→TS bench: correctness and hidden-migration density.

    See the full Vue 2 to Vue 3 migration page. Run yours free, up to 100 files, no credit card.

    vue-codemod: incomplete coverage

    The official Vue 3 codemod handles basic cases but misses template-compile failures. Like ts-migrate, it produces outputs that pass lint but fail the real template compiler gate.

    Raw LLM hides Vue 2 behind v2 residue

    The naive LLM outputs SFCs that compile, but leaves beforeDestroy, this.$on(), and this.$set() in place. The v2 residue metric catches this; SFC errors alone do not.

    Refactyl: compiler-clean + low residue

    Deterministic breaking-change rules cover the API surface; the SFC gate validates every file; the CSS transition rename post-pass catches what AI skips. Both metrics move together.

    Results

    Judge: npm install --ignore-scripts + @vue/compiler-sfc parse + compileTemplate() on each tool's delivered output. SFC errors = files that fail template compilation (lower is better). v2 residue/KLOC = count of Vue 2 API patterns still present per 1,000 lines of .vue output (lower is better; measures how much Vue 2 surface the tool quietly left in place).

    Benchmark run in progress. Numbers will appear here once published. cd backend && npx tsx bench-vue.ts all

    Why two metrics for Vue too

    The Vue 3 template compiler catches broken syntax, but it doesn't catch Vue 2 API calls that were silently removed. A component that calls this.$on() or uses beforeDestroy will compile cleanly with @vue/compiler-sfc, then fail at runtime when Vue 3's event bus is gone and the lifecycle hook is never called.

    So we hold every tool to both: does the SFC compile, and how much Vue 2 API surface did it leave in place. A tool that converts the template syntax but keeps this.$set() throughout the script looks clean on SFC errors and is a latent bug on v2 residue.

    Refactyl's Vue 2→3 engine applies breaking-change rules as deterministic transforms first (not LLM guesses), then validates every file against the real compiler. The CSS transition-class renames (v-enter v-enter-from) run as a deterministic regex post-pass because models reliably skip <style> blocks.

    Migrate your Vue 2 project

    Every converted .vue file validated by @vue/compiler-sfc before handoff. Options API preserved. Your first migration is free.