/** * This is the public API for `bind.ts` files * It is aliased as `import {} from 'bindgen'` * @see https://bun.com/docs/project/bindgen */ import { dictionaryImpl, isFunc, isType, oneOfImpl, registerFunction, TypeImpl, type TypeKind, } from "./bindgen-lib-internal"; /** A type definition for argument parsing. See `bindgen.md` for usage details. */ export type Type< /** T = JavaScript type that the Type represents */ T, /** K = "kind" a string pertaining to the `t.` that created this type. affects method listing */ K extends TypeKind = TypeKind, /** F = "flags" defining if the value is optional. null = not set, false = required, true = optional. */ F extends TypeFlag = null, > = F extends null ? Props : F extends true ? { [isType]: true | [T, K, F]; nonNull: Type; } : { [isType]: true | [T, K, F] }; type TypeFlag = boolean | "opt-nonnull" | null; interface BaseTypeProps { [isType]: true | [T, K]; /** * Optional means the value may be omitted from a parameter definition. * Parameters are required by default. */ optional: Type; /** * When this is used as a dictionary value, this makes that parameter * required. Dictionary entries are optional by default. */ required: Type, K, false>; /** Implies `optional`, this sets a default value if omitted */ default(def: T): Type; } interface NumericTypeProps extends BaseTypeProps { /** * Applies [Clamp] semantics * https://webidl.spec.whatwg.org/#Clamp * If a custom numeric range is provided, it will be used instead of the built-in clamp rules. */ clamp(min?: T, max?: T): Type; /** * Applies [EnforceRange] semantics * https://webidl.spec.whatwg.org/#EnforceRange * If a custom numeric range is provided, it will be used instead of the built-in enforce rules. */ enforceRange(min?: T, max?: T): Type; /** * Equivalent to calling Node.js' `validateInteger(val, prop, min, max)` */ validateInteger(min?: T, max?: T): Type; } interface I32TypeProps extends NumericTypeProps { /** * Equivalent to calling Node.js' `validateInt32(val, prop, min, max)` */ validateInt32(min?: number, max?: number): Type; } interface U32TypeProps extends NumericTypeProps { /** * Equivalent to calling Node.js' `validateUint32(val, prop, min, max)` */ validateUint32(min?: number, max?: number): Type; } interface F64TypeProps extends NumericTypeProps { /** * Throws an error if the input is non-finite (NaN, ±Infinity) */ finite: Type; /** * Equivalent to calling Node.js' `validateNumber(val, prop, min, max)` */ validateNumber(min?: number, max?: number): Type; } // If an entry does not exist, then `BaseTypeProps` is assumed. // T = JavaScript type that the Type represents interface TypePropsMap { // Integer types are always numbers, so T is not passed ["u8"]: NumericTypeProps; ["i8"]: NumericTypeProps; ["u16"]: NumericTypeProps; ["i16"]: NumericTypeProps; ["u32"]: U32TypeProps; ["i32"]: I32TypeProps; ["u64"]: NumericTypeProps; ["i64"]: NumericTypeProps; // F64 is always a number, so T is not passed. ["f64"]: F64TypeProps; } type PropertyMapKeys = keyof TypePropsMap; type Props = K extends PropertyMapKeys ? TypePropsMap[K] : BaseTypeProps; export type AcceptedDictionaryTypeKind = Exclude; function builtinType() { return (kind: K) => new TypeImpl(kind, undefined as any, {}) as Type as Type; } /** Contains all primitive types provided by the bindings generator */ export namespace t { /** * Can only be used as an argument type. * Tells the code generator to pass `*JSC.JSGlobalObject` as a parameter */ export const globalObject = builtinType()("globalObject"); /** * Can only be used as an argument type. * Tells the code generator to pass `*JSC.VirtualMachine` as a parameter */ export const zigVirtualMachine = builtinType()("zigVirtualMachine"); /** * Provides the raw JSValue from the JavaScriptCore API. Avoid using this if * possible. This indicates the bindings generator is incapable of processing * your use case. */ export const any = builtinType()("any"); /** Void function type */ export const undefined = builtinType()("undefined"); /** Does not throw on parse. Equivalent to `!!value` */ export const boolean = builtinType()("boolean"); /** Throws if the value is not a boolean. */ export const strictBoolean = builtinType()("strictBoolean"); /** * Equivalent to IDL's `unrestricted double`, allowing NaN and Infinity. * To restrict to finite values, use `f64.finite`. */ export const f64 = builtinType()("f64"); export const u8 = builtinType()("u8"); export const u16 = builtinType()("u16"); export const u32 = builtinType()("u32"); export const u64 = builtinType()("u64"); export const i8 = builtinType()("i8"); export const i16 = builtinType()("i16"); export const i32 = builtinType()("i32"); export const i64 = builtinType()("i64"); export const usize = builtinType()("usize"); /** * The DOMString type corresponds to strings. * * @note A DOMString value might include unmatched surrogate code points. * Use USVString if this is not desirable. * * @see https://webidl.spec.whatwg.org/#idl-DOMString */ export const DOMString = builtinType()("DOMString"); /** * The {@link USVString} type corresponds to scalar value strings. Depending on the * context, these can be treated as sequences of code units or scalar values. * * Specifications should only use USVString for APIs that perform text * processing and need a string of scalar values to operate on. Most APIs that * use strings should instead be using {@link DOMString}, which does not make any * interpretations of the code units in the string. When in doubt, use * {@link DOMString} * * @see https://webidl.spec.whatwg.org/#idl-USVString */ export const USVString = builtinType()("USVString"); /** * The ByteString type corresponds to byte sequences. * * WARNING: Specifications should only use ByteString for interfacing with * protocols that use bytes and strings interchangeably, such as HTTP. In * general, strings should be represented with {@link DOMString} values, even * if it is expected that values of the string will always be in ASCII or some * 8-bit character encoding. Sequences or frozen arrays with octet or byte * elements, {@link Uint8Array}, or {@link Int8Array} should be used for * holding 8-bit data rather than `ByteString`. * * https://webidl.spec.whatwg.org/#idl-ByteString */ export const ByteString = builtinType()("ByteString"); /** * DOMString but encoded as `[]const u8` * * ```ts * // foo.bind.ts * import { fn, t } from "bindgen"; * * export const foo = fn({ * args: { bar: t.UTF8String }, * }) * ``` * * ```zig * // foo.zig * pub fn foo(bar: []const u8) void { * // ... * } * ``` */ export const UTF8String = builtinType()("UTF8String"); /** An array or iterable type of T */ export function sequence(itemType: Type): Type, "sequence"> { return new TypeImpl("sequence", { element: itemType as TypeImpl, repr: "slice", }); } /** Object with arbitrary keys but a specific value type */ export function record(valueType: Type): Type, "record"> { return new TypeImpl("record", { value: valueType as TypeImpl, repr: "kv-slices", }); } /** * Reference a type by string name instead of by object reference. This is * required in some siutations like {@link Request} which can take an existing * request object in as itself. */ export function ref(name: string): Type { return new TypeImpl("ref", name); } /** * Reference an external class type that is not defined with `bindgen`, * from either WebCore, JavaScriptCore, or Bun. */ export function externalClass(name: string): Type { return new TypeImpl("ref", name); } export function oneOf[]>( ...types: T ): Type< { [K in keyof T]: T[K] extends Type ? U : never; }[number], "oneOf" > { return oneOfImpl(types as unknown[] as TypeImpl[]); } export function dictionary>>( fields: R, ): Type< { [K in keyof R]?: R[K] extends Type ? T : never; }, "dictionary" > { return dictionaryImpl(fields as Record); } /** Create an enum from a list of strings. */ export function stringEnum( ...values: T ): Type< { [K in keyof T]: K; }[number], "stringEnum" > { return new TypeImpl("stringEnum", values.sort()); } /** * Equivalent to `stringEnum`, but using an enum sourced from the given Zig * file. Use this to get an enum type that can have functions added. */ export function zigEnum(file: string, impl: string): Type { return new TypeImpl("zigEnum", { file, impl }); } } interface FuncOptionsWithVariant extends FuncMetadata { /** * Declare a function with multiple overloads. Each overload gets its own * native function named "name`n`" where `n` is the 1-based index of the * overload. * * ## Example * ```ts * // foo.bind.ts * import { fn } from "bindgen"; * * export const foo = fn({ * variants: [ * { * args: { a: t.i32 }, * ret: t.i32, * }, * { * args: { a: t.i32, b: t.i32 }, * ret: t.boolean, * } * ] * }); * ``` * * ```zig * // foo.zig * pub fn foo1(a: i32) i32 { * return a; * } * * pub fn foo2(a: i32, b: i32) bool { * return a == b; * } * ``` */ variants: FuncVariant[]; } type FuncWithoutOverloads = FuncMetadata & FuncVariant; type FuncOptions = FuncOptionsWithVariant | FuncWithoutOverloads; export interface FuncMetadata { /** * The namespace where the implementation is, by default it's in the root. */ implNamespace?: string; /** * TODO: * Automatically generate code to expose this function on a well-known object */ exposedOn?: ExposedOn; } export type FuncReference = { [isFunc]: true }; export type ExposedOn = "JSGlobalObject" | "BunObject"; export interface FuncVariant { /** Ordered record. Cannot include ".required" types since required is the default. */ args: Record>; ret: Type; } export function fn(opts: FuncOptions) { return registerFunction(opts) as FuncReference; }