
Reverta arquivos .jsc do bytenode (cache de código V8) para JavaScript — estático, Rust puro, sem V8/Node modificado. Node 8→26 / V8 5.8–14.6; 25k .jsc testados, 0 falhas.
Reverter arquivos .jsc compilados com bytenode de volta para JavaScript.
Apenas análise estática: um binário puro em Rust — sem V8 modificado, sem runtime Node, sem rede.
Suporta Node 8.0.0 → 26.10.0 (510 versões / 36 minors do V8); ≈ 25k arquivos .jsc passam nos
testes com 0 falhas (31 linhas do Node × 41 fixtures, compilados com as flags do bytenode 1.7.0); duas
camadas de otimização (register folding → propagação de cópia do swc) tornam o código descompilado legível.
English · 中文
Conteúdo: Destaques · Início rápido · Instalação · Uso · Referência da CLI · Versões suportadas · Como funciona · Verificação · Estrutura do repositório · Limitações · Contribuindo
--runtime adiciona os stubs __runtime para que o resultado rode sob node;
--verify o submete a node --check.JSCD_NO_OPT=1 mostra a forma bruta.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
Os primeiros bytes são o magic do code-cache em little-endian (cc 05 de c0 = 0xc0de05cc);
jscd info hello.jsc decodifica todo o cabeçalho (exemplo em Usage).
A saída acima é o que resulta após ambas as camadas de otimização. JSCD_NO_OPT=1 jscd hello.jsc
mostra a tradução bruta — o embaralhamento de registradores do V8, uma instrução de cada vez.
No Node 22+ (V8 12.4+), alguns nomes de propriedades internas residem no heap somente leitura. Para as 29
versões menores do V8 cobertas pela matriz de comportamento, o jscd inclui uma tabela de nomes (tables/ro_map_*) e os resolve
automaticamente — no macOS, onde essas tabelas foram extraídas: os índices do heap somente leitura são
específicos da plataforma, portanto em outros sistemas construa a sua própria com jscd ro-map e passe --ro-map
(JSCD_NO_RO_MAP=1 desativa a tabela embutida). Sem uma tabela, tais nomes aparecem como placeholders <ro0_…>
— nunca como o nome errado.
macOS / Linux — Homebrew
brew install ejfkdev/tap/jscd
Windows — Scoop
scoop bucket add ejfkdev https://github.com/ejfkdev/scoop-bucket
scoop install jscd
Diretamente da URL do manifesto, sem adicionar o bucket primeiro:
scoop install https://raw.githubusercontent.com/ejfkdev/scoop-bucket/main/bucket/jscd.json
scoop install ejfkdev/scoop-bucket/jscdnão funciona: o Scoop resolvebucket/appem relação aos buckets que você já adicionou, não em relação a um caminhoowner/repo.
Binários pré-compilados — cada release com tag inclui executáveis simples, prontos para executar (Linux / macOS / Windows × x64 / arm64; Linux amd64 é uma build estática musl, Linux e Windows são comprimidos com UPX):
Pegue um diretamente da página de release (sem arquivo, sem instalador — o arquivo é o executável):
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 (qualquer plataforma com Rust 1.96+)
cargo install jscd # build from crates.io
cargo binstall jscd # or fetch the release binary instead of compiling (cargo-binstall)
Da fonte
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
Requer Rust 1.96+ (swc, o otimizador de JS, precisa de um rustc recente). Sem dependências de sistema.
scripts/release.sh vX.Y.Z executa os portões de lançamento (cargo test --release,
clippy --all-targets -- -D warnings, e o smoke end-to-end scripts/ci_smoke.sh — fixtures
compiladas para .jsc reais, descompiladas, com verificação de sintaxe e comparação de execução), depois envia uma tag anotada
cuja mensagem se torna a descrição do GitHub Release. A tag aciona
.github/workflows/release.yml, que reconstrói os seis binários bare listados acima. Depois
cargo publish para o crates.io (release.sh mantém a tag e a versão do Cargo.toml em sincronia), e
python3 scripts/update_readme_help.py para atualizar a ajuda da CLI abaixo; o
Homebrew tap e o
Scoop bucket capturam o novo lançamento na sua execução diária
de atualização 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>`)