Skip to content

Repository files navigation

⚠️ Warning: This project is not yet stable and may undergo significant changes before reaching version 1.0.0. We strongly advise against using it in production environments.

DashScript

GitHub Contributor Covenant

JavaScript/TypeScript ergonomics, Rust performance, native + wasm + napi outputs. DashScript compiles JavaScript/TypeScript to idiomatic Rust — shipped as a native binary, with WebAssembly and napi targets on the same mapping table — pursuing maximum test262 conformance, the WinterTC Minimum Common Web API, and a bridge between the npm and cargo ecosystems. Static-first, graceful degradation: oxc parses .ts/.tsx/.js/.jsx/.mjs/.cjs, the static translator maps the ESM surface, and whatever it cannot lower statically (CommonJS require/module.exports, dynamic reflection, Web API edges) degrades to the embedded QuickJS engine — so compatibility holds.

Packages

Package Version Description
dashscript npm The ds toolchain in one package — translates oxc AST → Rust, package.jsonCargo.toml, bindgen, CLI, editor types.

Quick Start

Install

# one package — provides the `ds` command
$ pnpm add -g dashscript

# or as a standalone binary
$ cargo install dashscript

No separate Rust install. DashScript manages its own pinned Rust toolchain — downloaded on first use like an npm dependency — so pnpm add dashscript is all you need.

Write .ts, compile to a native binary

// main.ts — TypeScript-flavored source
function greet(name: string): string {
  return `Hello, ${name}!`;
}

const message: string = greet("DashScript");
$ ds main.ts                      # run a file directly (like `node a.js`)
$ ds build main.ts                # → dist/<name> — a native binary (default)
$ ds build main.ts --target rust  # → dist/<name>/ — the translated Rust crate

ds main.ts runs a .ts file directly — translate → compile (cached) → run, like node a.js. ds build parses .ts with oxc, translates the AST to idiomatic Rust, and ships a native binary in dist/<name>. Pass --target rust to stop at the translated crate instead:

// generated by DashScript (--target rust)
fn greet(name: &str) -> String {
    format!("Hello, {name}!")
}

fn main() {
    let message: String = greet("DashScript");
}

Run

$ ds run <script>    # run a package.json script (like `pnpm run`)

ds run runs a shell command from package.json scripts through the system shell, like pnpm run. (ds run is always explicit — running a file is ds <file.ts>.)

Declare dependencies — package.jsonCargo.toml

DashScript projects use a package.json — the one manifest every JS tool already reads. Standard npm fields map straight to cargo: bin declares executables (one project compiles to several binaries); main[lib]; Rust crate deps under dashscript.cargo.dependencies[dependencies] (npm dependencies stay JS deps, never reaching Cargo.toml). On ds build, the package lowers to a Cargo.toml:

{
  "name": "my-app",
  "bin": {
    "serve": "serve.ts",
    "migrate": "migrate.ts"
  },
  "dashscript": {
    "target": "bin",
    "cargo": {
      "dependencies": {
        "serde": "1.0",
        "tokio": "1.0"
      }
    }
  }
}

Use a Rust crate with full type hints

# fetch the crate — no .d.ts stub; types come straight from the crate source
$ ds add cargo:serde

ds add cargo:<crate> fetches the crate and records it in package.json, with no .d.ts stub — Rust is statically typed, so the crate's own source (in ~/.cargo) is the complete type truth, read directly by the editor the way rust-analyzer reads its deps. For a local Rust file, ds add <file>.rs runs bindgen to emit a .d.ts beside it. No separate ds gen step.

Check & format

ds check is the composite — translatability plus a format check (vp check style); ds lint checks translatability alone; ds fmt formats in place. With no argument each runs over every .ts in the project, and ds check --fix writes the fix. All built in-process on the parsed AST (no external oxlint/oxfmt):

$ ds check          # lint + format check, whole project (like `vp check`)
$ ds check --fix    # ...and write formatting fixes
$ ds lint           # translatability check only
$ ds fmt            # format every .ts in place

The emitted Rust is finally verified with cargo check / cargo clippy on the generated project.

Roadmap

DashScript maps a TypeScript-flavored surface to Rust semantics, growing incrementally as real demand drives each mapping — never speculatively.

  • Language coverage — the full Rust type/memory-safety model (ownership, borrowing, lifetimes, traits), with TypeScript as the presentation only. Today: most of the JavaScript/TypeScript surface (auto clone/borrow/narrowing bridge the gaps); the residual tail degrades to the embedded QuickJS engine rather than failing.
  • Standard libraries — ES built-ins (Math/String/Array/Object/Number, … — largely mapped today), then the node: stdlib (node:crypto, node:zlib, node:fs, …). Web APIs are tracked separately under WinterTC below.
  • Compatibility — degrade, don't reject — a construct the static translator can't lower runs under an embedded QuickJS engine at the function granularity (inheriting full ECMAScript semantics) instead of failing, so existing TS/JS keeps working without a rewrite. Reflection (typeof/instanceof/Object.keys) resolves at compile time where the type is known — zero-cost, no dynamic value model — so only the residual dynamic cases degrade.
  • Package integration — every package is a crate. A workspace member or an npm dependency lowers to its own cargo crate, referenced by a path dependency (use office_open_xml::X) — node_modules-style layering, not bundling. DashScript translates each .ts/.js/.mjs/.cjs file directly (no rolldown/esbuild): cargo's workspace + path dependency is already the Rust ecosystem's node_modules, and .js packages take the same static-translate-first path as .ts. Today: workspace members build as independent crates; npm-package independent crates and .js static-first are in progress.
  • WinterTC Minimum Common Web API — the Ecma TC55 (formerly WinterCG) Minimum Common Web Platform API (shared by Node, Deno, Bun, Cloudflare Workers), on the same static-first + per-function degrade model as the ECMAScript core: each Web API maps to a Rust crate first (static, zero-cost), and an edge the static translator cannot lower takes the per-function engine path with the Web API registered as a builtin (same Rust impl). Synchronous APIs map first (URL, URLSearchParams, TextEncoder, Headers, Blob, FormData, SubtleCrypto, … today); asynchronous ones (fetch, setTimeout, Streams) introduce a tokio runtime and a thread model. Conformance is a WPT subset, run static-first with per-function engine degrade (mirroring test262).
  • More outputswasm and napi targets (Rust compiled to WebAssembly / napi-rs), so .ts ships to the web and Node ecosystems. The static segment (including compile-time reflection) lowers to plain wasm — no engine bundled for the common case; only the degraded minority pulls in QuickJS-wasm (Javy proves rquickjs compiles to wasm32-wasip1).
  • Developer experienceds test, editor/LSP integration, conformance fixtures.
  • Self-hosting (north star) — rewrite the toolchain in .ts itself, reaching oxc (and any Rust crate) through bindgen.

Development

Prerequisites

  • Node.js 18.x or higher
  • pnpm 9.x or higher (recommended package manager)
  • Rust — managed by DashScript (a pinned toolchain is downloaded on demand); no separate install needed to use DashScript
  • Git for version control

Getting Started

  1. Clone the repository:

    git clone https://github.com/DemoMacro/dashscript.git
    cd dashscript
  2. Install dependencies:

    pnpm install
  3. Build all packages:

    pnpm build

Development Commands

pnpm build                       # Build all packages
cd packages/<pkg> && pnpm build  # Build one package
vp check                         # Lint & format

Contributing

We welcome contributions! See CONTRIBUTING.md for the full contribution workflow, coding standards, and PR checklist.

Support & Community

License

This project is licensed under the MIT License - see the LICENSE file for details.


Built with ❤️ by Demo Macro

About

JavaScript/TypeScript ergonomics, Rust performance, native + wasm + napi outputs.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages