Open-Source Wikis

/

Bun

/

Systems

/

Code generation

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, JSGlobConstructor classes 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:

  1. 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.
  2. Bun ships JSC builtins. Some Bun modules are JSC builtins (compiled by JSC's builtin compiler) rather than plain modules. bundle-functions.ts produces the right header shape for that compiler.
  3. 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/.h per *.classes.ts file.
  • 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 systemscripts/build.ts and CMake.
  • C++ side — Generated files are included from src/bun.js/bindings/.
  • Zig side — Generated declarations are included via build.zig's codegen_path option.
  • 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.ts next to its implementation. Run bun bd.
  • To change the schema, edit src/codegen/class-definitions.ts (consumers) and src/codegen/generate-classes.ts (emitter).
  • To add a new builtin function, drop a TS file in src/js/builtins/ and add it to the bundle-functions.ts whitelist.
  • To debug "missing class" errors, look at ZigGeneratedClasses.cpp for 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.

Code generation – Bun wiki | Factory