
Revertir bytenode .jsc (caché de código V8) a JavaScript — estático, Rust puro, sin V8/Node parcheado. Node 8→26 / V8 5.8–14.6; 25k .jsc probados, 0 fallos.
Revierte archivos .jsc compilados con bytenode a JavaScript.
Solo análisis estático: un único binario en Rust puro — sin V8 parcheado, sin runtime de Node, sin red.
Compatible con Node 8.0.0 → 26.10.0 (510 versiones / 36 versiones menores de V8); ≈ 25k archivos .jsc pasan las
pruebas con 0 fallos (31 líneas de Node × 41 fixtures, compilados con los flags de bytenode 1.7.0); dos
capas de optimización (plegado de registros → propagación de copias de swc) hacen legible el código descompilado.
English · 中文
Contenido: Aspectos destacados · Inicio rápido · Instalación · Uso · Referencia de la CLI · Versiones compatibles · Cómo funciona · Verificación · Estructura del repositorio · Limitaciones · Contribuir
--runtime añade los stubs __runtime para que el resultado se ejecute bajo node;
--verify lo somete a node --check.JSCD_NO_OPT=1 muestra la forma sin procesar.ReferenceError.$ cat hello.js
function greet(name) {
return "hello " + name;
}
console.log(greet("world"));
$ npm i -g bytenode && bytenode -c hello.js # Node 20.20.2 in this transcript
$ xxd -l 48 hello.jsc
00000000: cc05 dec0 0bc2 e400 9200 0000 e521 2eaa .............!..
00000010: f002 0000 0000 0000 011c 5401 2006 a860 ..........T. ..`
00000020: 0000 0000 0600 0000 010c 4c60 0000 0000 ..........L`....
$ jscd hello.jsc
console.log(greet("world"));
function greet(a0) {
return "hello " + a0;
}
$ jscd hello.jsc --runtime > hello.out.js && node hello.out.js
hello world
Los primeros bytes son la magia de la caché de código en little-endian (cc 05 de c0 = 0xc0de05cc);
jscd info hello.jsc decodifica todo el encabezado (ejemplo en Usage).
La salida anterior es lo que resulta después de ambas capas de optimización. JSCD_NO_OPT=1 jscd hello.jsc
muestra en su lugar la traducción sin procesar — el reordenamiento de registros de V8, una instrucción a la vez.
En Node 22+ (V8 12.4+) algunos nombres de propiedades integradas residen en el heap de solo lectura. Para las 29 versiones
menores de V8 cubiertas por la matriz de comportamiento, jscd incluye una tabla de nombres (tables/ro_map_*) y los resuelve
automáticamente — en macOS, donde se extrajeron esas tablas: los índices del heap de solo lectura son
específicos de la plataforma, así que en otros sistemas construye la tuya con jscd ro-map y pasa --ro-map
(JSCD_NO_RO_MAP=1 desactiva la tabla integrada). Sin una tabla, dichos nombres aparecen como marcadores
<ro0_…> — nunca como el nombre incorrecto.
macOS / Linux — Homebrew
brew install ejfkdev/tap/jscd
Windows — Scoop
scoop bucket add ejfkdev https://github.com/ejfkdev/scoop-bucket
scoop install jscd
Directamente desde la URL del manifiesto, sin añadir primero el bucket:
scoop install https://raw.githubusercontent.com/ejfkdev/scoop-bucket/main/bucket/jscd.json
scoop install ejfkdev/scoop-bucket/jscdno funciona: Scoop resuelvebucket/appcontra los buckets que ya has añadido, no contra una rutaowner/repo.
Binarios precompilados — cada release etiquetado incluye ejecutables listos para usar (Linux / macOS / Windows × x64 / arm64; Linux amd64 es una compilación estática con musl, Linux y Windows están comprimidos con UPX):
Descarga uno directamente desde la página de releases (sin archivo, sin instalador — el archivo es el ejecutable):
curl -fLO https://github.com/ejfkdev/jscd/releases/download/v0.1.0/jscd-v0.1.0-linux-amd64
chmod +x jscd-v0.1.0-linux-amd64
./jscd-v0.1.0-linux-amd64 --version
cargo (cualquier plataforma con Rust 1.96+)
cargo install jscd # build from crates.io
cargo binstall jscd # or fetch the release binary instead of compiling (cargo-binstall)
Desde el código fuente
cargo install --git https://github.com/ejfkdev/jscd # latest main
git clone https://github.com/ejfkdev/jscd && cd jscd
cargo build --release # -> target/release/jscd
cargo install --path . # ...or install that build into ~/.cargo/bin
Requiere Rust 1.96+ (swc, el optimizador de JS, necesita un rustc reciente). Sin dependencias del sistema.
scripts/release.sh vX.Y.Z ejecuta las comprobaciones de publicación (cargo test --release,
clippy --all-targets -- -D warnings, y el smoke de extremo a extremo scripts/ci_smoke.sh — fixtures
compilados a .jsc reales, descompilados, verificados sintácticamente y comparados en ejecución), luego publica una etiqueta anotada
cuyo mensaje se convierte en la descripción del GitHub Release. La etiqueta activa
.github/workflows/release.yml, que reconstruye los seis binarios básicos listados arriba. Luego
cargo publish a crates.io (release.sh mantiene la etiqueta y la versión de Cargo.toml sincronizadas), y
python3 scripts/update_readme_help.py para actualizar la ayuda de la CLI de abajo; el
Homebrew tap y el
Scoop bucket recogen la nueva versión en su ejecución diaria
de actualización automática.
jscd app.jsc # decompile one file to stdout
jscd app.jsc app.js # ...to a file
jscd dist/ # every .jsc under dist/ → dist-out/ (tree mirrored)
jscd dist/ out/ # ...into out/ instead
jscd info app.jsc # header fields, detected Node/V8 version
jscd disasm --filter main app.jsc
jscd ro-map probe.jsc > m.json # build a read-only-heap name table
jscd --help # bilingual help (-h, `help`, `help <SUBCOMMAND>`)