A TypeScript Java .class decompiler for Node.js and browsers.
Why you need this project:
- Decompile directly in your browser.
- Keep files local, with no backend or uploads required.
- Easily integrate into JavaScript tools.
Single JS file: approximately 288 KB, or 88 KB with gzip. No runtime dependencies, WebAssembly or Java installation required.
Supports common control flow, lambdas, nested classes, records and selected Java features through Java 25. Intended as the decompilation engine for the next generation of jar-analyzer.
npm package: @jar-analyzer/jsd, published version 1.2.0.
Load from the CDN and decompile a selected .class file.
<input type="file" accept=".class" />
<pre id="source"></pre>
<script type="module">
import { decompileClassFile } from 'https://cdn.jsdelivr.net/npm/@jar-analyzer/jsd@1.2.0/dist/jsd.min.js';
document.querySelector('input').onchange = async (event) => {
const file = event.target.files[0];
if (!file) return;
const bytes = new Uint8Array(await file.arrayBuffer());
document.getElementById('source').textContent = decompileClassFile(bytes).source;
};
</script>npm install @jar-analyzer/jsdSave as example.mjs and run node example.mjs:
import { readFileSync } from 'node:fs';
import { decompileClassFile } from '@jar-analyzer/jsd';
const result = decompileClassFile(readFileSync('Example.class'));
console.log(result.source);| Test | Cases | CI runtime |
|---|---|---|
| Formatting | — | Node.js 24 |
| Types | — | Node.js 24 |
| Bundle & sizes | — | Node.js 24 |
| Browser layout | 4 | Chrome/Chromium |
| Unit | 354 | Node.js 24 |
| Round-trip: debug | 190 | JDK 8/11/17/21/25 |
| Round-trip: no debug | 190 | JDK 8/17/25 |
| Legacy target checks | 50 | JDK 8/17 |
| Java 9–25: debug | ≤18 | JDK 21/25 |
| Java 9–25: no debug | ≤18 | JDK 21/25 |
| Dynamic bytecode | ≤37 | JDK 11/17/21/25 |
| Value semantics | 9 | JDK 11/17/21/25 |
| Malformed classes | 17 | JDK 11/17/21/25 |
| Package | — | Node.js 20/24 |
| Fuzz | 2,000 | Node.js 24 + JDK 25 |
Legacy fixtures verify recovered sources against both the original target and the current JDK target.
JDK 8 validates Java 6/7 targets; newer JDKs use their oldest supported target when necessary.