This document is for maintainers and contributors to Bun, and describes internal implementation
details.
*.bind.ts to find function and class definition, and generates glue code to
interop between JavaScript and native code.
There are currently other code generators and systems that achieve similar
purposes. The following will all eventually be completely phased out in favor of
this one:
- “Classes generator”, converting
*.classes.tsfor custom classes. - “JS2Native”, allowing ad-hoc calls from
src/jsto native code.
Creating JS Functions in Zig
Given a file implementing a simple function, such asadd
src/bun.js/math.zig
.bind.ts function. The binding file goes next to the Zig file.
bun.gen.math.jsAdd, which is the native
function implementation. To pass to JavaScript, use
bun.gen.math.createAddCallback(global). JS files in src/js/ may use
$bindgenFn("math.bind.ts", "add") to get a handle to the implementation.
Strings
The type for receiving strings is one oft.DOMString, t.ByteString, and t.USVString. These map directly to their WebIDL counterparts, and have slightly different conversion logic. Bindgen will pass BunString to native code in all cases.
When in doubt, use DOMString.
t.UTF8String can be used in place of t.DOMString, but will call bun.String.toUTF8. The native callback gets []const u8 (WTF-8 data) passed to native code, freeing it after the function returns.
TLDRs from WebIDL spec:
- ByteString can only contain valid latin1 characters. It is not safe to assume bun.String is already in 8-bit format, but it is extremely likely.
- USVString will not contain invalid surrogate pairs, aka text that can be represented correctly in UTF-8.
- DOMString is the loosest but also most recommended strategy.
Function Variants
Avariants can specify multiple variants (also known as overloads).
t.dictionary
A dictionary is a definition for a JavaScript object, typically as a function inputs. For function outputs, it is usually a smarter idea to declare a class type to add functions and destructuring.
Enumerations
To use WebIDL’s enumeration type, use either:t.stringEnum: Create and codegen a new enum type.t.zigEnum: Derive a bindgen type off of an existing enum in the codebase.
stringEnum as used in fmt.zig / bun:internal-for-testing
Deriving enums from Zig code
TODO: zigEnumt.oneOf
A oneOf is a union between two or more types. It is represented by union(enum) in Zig.
TODO:
Attributes
There are set of attributes that can be chained ontot.* types. On all types there are:
.required, in dictionary parameters only.optional, in function arguments only.default(T)
Integer Attributes
Integer types allow customizing the overflow behavior withclamp or enforceRange
validateInteger, validateNumber, and more are available. Use these when implementing Node.js APIs, so the error messages match 1:1 what Node would do.
Unlike enforceRange, which is taken from WebIDL, validate* functions are much more strict on the input they accept. For example, Node’s numerical validator check typeof value === 'number', while WebIDL uses ToNumber for lossy conversion.