oven-sh/bun
Code generation
src/codegen/ holds TypeScript scripts that run as part of bun bd to produce Zig and C++ source from declarative descriptions. Generation happens automatically — you do not run these scripts by hand.
What gets generated
| Script | Output | Source of truth |
|---|---|---|
generate-classes.ts |
build/<profile>/codegen/ZigGeneratedClasses*.{cpp,h} and per-class JS<Name>.{cpp,h} |
**/*.classes.ts files (e.g. src/bun.js/api/Glob.classes.ts) |
generate-jssink.ts |
build/<profile>/codegen/JSSink.{cpp,h} |
hard-coded sink list in the script |
bundle-modules.ts |
C++ headers with embedded JS source for each node:*, bun:*, thirdparty/*, internal/* module |
src/js/{node,bun,thirdparty,internal}/*.ts |
bundle-functions.ts |
C++ headers for each JSC builtin function | src/js/builtins/*.ts |
cppbind.ts |
Zig bindings for C++ functions tagged [[ZIG_EXPORT(...)]] |
C++ source files |
bindgen.ts + bindgenv2/ |
Cross-language type-aware exports | **/*.bind.ts files |
internal-module-registry-scanner.ts |
A numeric registry mapping module IDs → factories | The set of files under src/js/ |
generate-node-errors.ts |
C++ + JS scaffolding for node: error classes (ERR_INVALID_ARG_TYPE, ...) |
A node-error spec |
generate-compact-string-table.ts |
Compact static string tables used in hot paths | Inline declarations |
generate-js2native.ts |
Native callbacks reachable from JS via $cpp markers |
$cpp(...) annotations in src/js/ |
bake-codegen.ts |
Bake-specific bundles (incremental visualizer, etc.) | src/bake/client/*.ts |
client-js.ts |
Inline JS shipped to the dev-server browser client | Bake client TS files |
helpers.ts |
Shared utilities used by other scripts | — |
replacements.ts |
The $intrinsic → @intrinsic replacement table |
Manual list |
When generation runs
scripts/build.ts invokes the codegen scripts as a CMake target before the Zig step. Outputs land in build/<profile>/codegen/ and are picked up by build.zig via the codegen_path build option (default build/debug/codegen).
If you modify a *.classes.ts, *.bind.ts, or any file under src/js/, the next bun bd will detect it and regenerate. The Zig compiler treats the generated files as inputs and rebuilds the code that depends on them.
*.classes.ts schema
The class definition format is in src/codegen/class-definitions.ts. A typical entry:
export default [
define({
name: 'Glob',
construct: true,
finalize: true,
klass: {
// static methods
},
proto: {
match: { fn: 'match', length: 1 },
matchSync: { fn: 'matchSync', length: 1 },
scan: { fn: 'scan', length: 0 },
scanSync: { fn: 'scanSync', length: 0 },
},
}),
];The generator emits:
- C++:
JSGlob,JSGlobPrototype,JSGlobConstructorclasses plus their structures. - C++:
JSGlob__match,JSGlob__matchSync, ... thunks that downcast and call into Zig. - Zig: extern function declarations that the implementation file (
glob.zig) provides. - Registration in
ZigGeneratedClasses.cpp.
*.bind.ts (bindgen v2)
Bindgen v2 is for one-off cross-language calls that don't justify a full class. A Foo.bind.ts file describes a function signature and which side defines it. The codegen produces matching extern declarations for the consuming side.
Example: src/bun.js/bindgen_test.bind.ts declares a test function; the implementation is in src/bun.js/bindgen_test.zig.
[[ZIG_EXPORT]] and cppbind.ts
C++ functions can be marked:
[[ZIG_EXPORT(check_slow)]] extern "C" int Bun__doSomething(...) { ... }cppbind.ts parses the markers and emits Zig-side declarations so the function is callable from Zig with type-checked arguments. The "check_slow" mode runs an exception-scope sanity check on debug builds.
Why so much codegen?
Three drivers:
- JSC class shape is verbose. A constructor, prototype, instance, structure, iso subspace, hash table, and registration all have to line up. Hand-writing this is error-prone; the generator keeps them consistent.
- Bun ships JSC builtins. Some Bun modules are JSC builtins (compiled by JSC's builtin compiler) rather than plain modules.
bundle-functions.tsproduces the right header shape for that compiler. - Cross-language safety. Zig and C++ disagree on calling conventions, struct layout, and exception semantics. Generated glue makes the transitions explicit and stable.
Build outputs
The default build/debug/codegen/ directory contains:
ZigGeneratedClasses.cpp/.h— registration of every class.- One
<Name>.cpp/.hper*.classes.tsfile. - One module bundle header per
src/js/{node,bun,thirdparty,internal}/*.ts. InternalModuleRegistry*.h— module ID table.JSSink.cpp/.h— generated stream sinks (FileSink,ArrayBufferSink,BunHTTPResponseSink, ...).
Integration points
- Build system —
scripts/build.tsand CMake. - C++ side — Generated files are included from
src/bun.js/bindings/. - Zig side — Generated declarations are included via
build.zig'scodegen_pathoption. - Runtime — Generated module bundles are loaded by
src/bun.js/HardcodedModule.zig/InternalModuleRegistry.cpp.
Entry points for modification
- To add a class, write
Foo.classes.tsnext to its implementation. Runbun bd. - To change the schema, edit
src/codegen/class-definitions.ts(consumers) andsrc/codegen/generate-classes.ts(emitter). - To add a new builtin function, drop a TS file in
src/js/builtins/and add it to thebundle-functions.tswhitelist. - To debug "missing class" errors, look at
ZigGeneratedClasses.cppfor a registration of the new class.
Key source files
| File | Purpose |
|---|---|
src/codegen/generate-classes.ts |
The class generator. |
src/codegen/class-definitions.ts |
The class-definition schema. |
src/codegen/bundle-modules.ts |
JS module bundler. |
src/codegen/bundle-functions.ts |
JSC builtin compiler input shape. |
src/codegen/cppbind.ts |
C++ → Zig export generator. |
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.