Sign in

    ts

    TypeScript/JavaScript interpreter and compiler to WebAssembly

    typescript
    javascript
    interpreter
    wasm
    Download zip
    Author
    Version
    0.1.4
    License
    Apache-2.0
    Last updated
    5 months ago
    Downloads
    1K

    #typescript.mbt

    Status: Experimental

    A TypeScript/JavaScript subset parser, interpreter, and Wasm codegen written in MoonBit. The goal is to run as much of ECMAScript (via test262) as possible, with a fallback to the interpreter when codegen is too limited.

    #Parser Scope

    The parser accepts a JS/TS subset and produces a lowered AST.

    • Declarations: function, class (lowered), let/const/var (with types)
    • Statements: block, if, while, do/while (lowered), for, for-of, for-in (parsed as for-of), break/continue, return, throw, try/catch/finally, switch
    • Expressions: literals, variables, unary/binary/ternary, new, calls, property/index access, assignments, arrow functions, function expressions, arrays/objects, yield, await
    • Types: number, int, boolean, string, void, any, array, named types, function types, interface field lists
    • Class: lowered into constructor/prototype assignments

    Not supported (parse errors or explicit skips):
    • ES modules (import/export) - parsed but not fully executed
    • with statement (deprecated)
    • Private fields (#field)

    #Interpreter Scope

    The interpreter executes the AST directly and is the main path for test262.

    • Control flow: if, while, for, for-of (arrays/strings/iterables), break/continue, return, throw, try/catch/finally, switch
    • Functions: declarations, expressions, arrows, closures, generators, async functions, async generators
    • Objects/Arrays: property access, assignment, deletion, spread
    • Special: eval (direct), new, super (limited), __proto__

    #Built-in Objects

    ObjectSupport Level
    ObjectGood - keys, values, entries, assign, defineProperty, etc.
    ArrayGood - most methods including iteration
    StringGood - most methods
    NumberGood
    MathGood
    FunctionPartial - no dynamic Function()
    DateMinimal - basic operations
    RegExpMinimal - literal parsing incomplete
    PromisePartial - async/await works
    ProxyPartial - basic traps
    ReflectPartial
    JSONGood - parse, stringify
    consoleGood - log

    test262 harness: assert.*, $262.*, $DONE, $ERROR, $DONOTEVALUATE

    #test262 Compatibility

    See TODO.md for detailed status.

    #Pass Rate by Category (2026-02-01)

    Pass Rate = Passed / (Passed + Failed), excluding skipped tests. Tests related to eval, Function constructor, and with statement are excluded.

    CategoryPassedFailedSkippedTotalPass Rate
    Math29135132789.3%
    language/statements6,5321,2307638,52584.1%
    language/expressions5,9831,7012,65310,33777.8%
    Boolean381305174.5%
    Number24984233574.8%
    Promise459180063971.8%
    String7964127121565.9%
    Function2851547050964.9%
    Object1671171228341149.4%
    Date2693101559446.5%

    #Not Tested / Not Supported

    • Intl402 - Internationalization API
    • Temporal - Temporal API
    • with statement - Deprecated feature
    • Dynamic eval - Advanced eval features
    • ES Modules - Parser accepts but not executed

    #Partial Support

    • TypedArray - Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array
    • BigInt - Basic operations

    #Experimental Wasm Codegen Scope

    The experimental Wasm codegen intentionally supports a strict subset and errors on dynamic JS features. It currently uses wasm-gc for arrays and structs.

    • Statements: let/const, assignments, if, while, do-while, for, for-of (arrays), switch, break/continue, return, block/expr statements
    • Expressions: literals, variables, arithmetic/comparison/bitwise, string +, array access/length, struct field access, new Array(size), new <interface> struct allocation, ternary, nullish coalescing (??)
    • experimental wasm-gc: GC arrays, GC structs, generator state machines

    Explicitly unsupported in codegen:
    • throw, try/catch/finally
    • typeof, void, delete
    • Object literals, closures (arrow/function expressions)
    • Dynamic call expressions

    #Package Bridge Scaffolds

    This repo now supports both directions of package scaffold generation. See examples/ for runnable demos of both directions.

    #Unified CLI

    For the common "generate everything for this package" path, use the unified CLI. It accepts either a MoonBit package name / pkg.generated.mbti path or a TypeScript entrypoint / installed package specifier.

    # MoonBit -> TypeScript. Run `moon info` first so pkg.generated.mbti exists. # This creates temporary MoonBit glue code, runs `moon build --target js`, # and emits a TypeScript package backed by the built JS output. tsmbt --input mizchi/foo --out dist # TypeScript -> MoonBit. For bare npm-style inputs, the runtime module spec # defaults to the input specifier. tsmbt --input neverthrow --out dist --direction ts-to-mbt # File input also works; pass the runtime module when it differs from the # declaration entry path. tsmbt --input path/to/entry.d.ts --module-spec /runtime/module.js --out dist --direction ts-to-mbt

    --direction auto is the default. It resolves MoonBit package names by scanning for matching pkg.generated.mbti files under the current project, and resolves bare TypeScript inputs through the TypeScript package resolver. The MoonBit -> TypeScript unified path emits facade glue by default, builds it with moon build --target js, and copies the built JS to index.js; pass --no-facade to emit only top-level free-function glue.

    #MoonBit -> TypeScript

    Start from a root pkg.generated.mbti for a real MoonBit source package and emit:

    • index.js copied from the temporary glue package's moon build --target js output
    • package.json with types / exports metadata for the emitted declaration package
    • AUTOLINK_DIAGNOSTICS.md listing public methods/constructors omitted from link.js.exports
    • recursive .d.ts files with local MoonBit package imports rewritten to sibling relative imports

    The temporary glue package contains generated wrapper functions and link.js.exports, is built with moon build --target js, and is removed after the built JS is copied to index.js.

    moon run src -- emit-typescript-scaffold-from-mbti src/pkg.generated.mbti out/ts-pkg # optional: rewrite external MoonBit package imports to publishable TS specifiers moon run src -- emit-typescript-scaffold-from-mbti src/pkg.generated.mbti out/ts-pkg import-rewrites.json # opt-in: also emit top-level MoonBit wrappers for omitted root-local methods/constructors moon run src -- emit-typescript-facade-scaffold-from-mbti src/pkg.generated.mbti out/ts-pkg

    Lower-level commands are also available:

    # only link.js.exports JSON moon run src -- emit-js-link-config-from-mbti src/pkg.generated.mbti # only recursive .d.ts package moon run src -- emit-typescript-package-from-mbti src/pkg.generated.mbti out/ts-pkg # single .d.ts from one .mbti file without recursive rewrite moon run src -- emit-typescript-from-mbti src/pkg.generated.mbti

    Current export model:

    • JS autolink is generated from top-level public free functions only.
    • Runtime-inaccessible method / namespace declarations are stripped from scaffold .d.ts output unless wrapper glue is generated for them.
    • Scaffold output includes AUTOLINK_DIAGNOSTICS.md so omitted public members are explicit.
    • emit-typescript-facade-scaffold-from-mbti is an opt-in variant that adds generated top-level wrappers for root-package local non-generic methods and constructors to the temporary glue package, then exposes those wrappers from the built index.js and index.d.ts.
    • The temporary moon.pkg.json and wrapper .mbt files are build inputs only; they are not written to the final TypeScript package.
    • Recursive .mbti resolution only rewrites imports that stay under the same root package prefix. External imports remain bare specifiers.
    • emit-typescript-package-from-mbti and emit-typescript-scaffold-from-mbti accept an optional JSON object for external import rewrites, for example { "moonbitlang/core/debug": "demo-debug" }.
    • Generated package.json names are derived from the MoonBit package path, for example demo/pkg -> @demo/pkg and mizchi/ts/analysis -> @mizchi/ts-analysis.

    #TypeScript -> MoonBit

    Start from a TypeScript entrypoint and emit a MoonBit bridge scaffold:

    moon run src -- emit-moonbit-scaffold-from-ts path/to/entry.d.ts /runtime/module.js out/moonbit-pkg

    Lower-level commands are also available:

    # full bridge package moon run src -- emit-moonbit-bridge-package path/to/entry.d.ts /runtime/module.js out/moonbit-pkg # inspect generated decl/ffi/bridge snippets without writing a package moon run src -- emit-moonbit-bridge path/to/entry.d.ts /runtime/module.js moon run src -- emit-moonbit-js-ffi path/to/entry.d.ts /runtime/module.js moon run src -- emit-moonbit-decl path/to/entry.d.ts

    The TS -> MoonBit path resolves exported surface recursively through local package structure and package exports, but the generated MoonBit package still targets the exported top-level surface rather than arbitrary internal module state.

    • Namespace exports are emitted as opaque getter-style bindings such as get_shapes() -> Shapes.
    • Ambiguous re-exports no longer block scaffold generation. They are widened/omitted the same way as the lower-level emitters, and the scaffold writes SCAFFOLD_DIAGNOSTICS.md so the dropped surface is explicit.
    • Generated bridge packages preserve camelCase top-level export names in their public MoonBit API, even when the internal JS extern binding is lowered to snake_case.

    #Development

    # Check for errors moon check --deny-warn # Run tests moon test --target native # Verify high-level scaffold commands end-to-end just verify-scaffolds # Format code moon fmt # Run test262 (requires test262 repo in ./test262) moon run src -- test262 test262.allowlist.txt # Experimental AOT compilation (wasm-gc) just experimental-aot-check # Check AOT compilability just experimental-aot-compile # Compile fixtures to wasm just experimental-aot-test # Run with wasmtime

    #License

    Apache-2.0

    ProjectBenchmarkCorpus

    type ProjectBenchmarkCorpus derive(
    Debug
    )

    ProjectBenchmarkCorpusRun

    type ProjectBenchmarkCorpusRun derive(
    Debug
    )

    ProjectBenchmarkFailure

    type ProjectBenchmarkFailure derive(
    Debug
    )

    ProjectBenchmarkResult

    type ProjectBenchmarkResult derive(
    Debug
    )

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io