金色时刻 · 15:48
让好资源,触手可及
AGENT SKILL

implementing-jsc-classes-zig

implementing-jsc-classes-zig 是面向软件开发的 Agent Skill,来自 oven-sh/bun。查看技能说明、操作步骤与使用约定,并通过原项目了解详细用法。

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

SKILL.md

下载 MD ↓
nameimplementing-jsc-classes-zig
descriptionCreates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

Bun's JavaScriptCore Class Bindings Generator

Bridge JavaScript and Zig through .classes.ts definitions and Zig implementations.

Architecture

  1. Zig Implementation (.zig files)
  2. JavaScript Interface Definition (.classes.ts files)
  3. Generated Code (C++/Zig files connecting them)

Class Definition (.classes.ts)

define({
  name: "TextDecoder",
  constructor: true,
  JSType: "object",
  finalize: true,
  proto: {
    decode: { args: 1 },
    encoding: { getter: true, cache: true },
    fatal: { getter: true },
  },
});

Options:

  • name: Class name
  • constructor: Has public constructor
  • JSType: "object", "function", etc.
  • finalize: Needs cleanup
  • proto: Properties/methods
  • cache: Cache property values via WriteBarrier

Zig Implementation

pub const TextDecoder = struct {
    pub const js = JSC.Codegen.JSTextDecoder;
    pub const toJS = js.toJS;
    pub const fromJS = js.fromJS;
    pub const fromJSDirect = js.fromJSDirect;

    encoding: []const u8,
    fatal: bool,

    pub fn constructor(
        globalObject: *JSGlobalObject,
        callFrame: *JSC.CallFrame,
    ) bun.JSError!*TextDecoder {
        return bun.new(TextDecoder, .{ .encoding = "utf-8", .fatal = false });
    }

    pub fn decode(
        this: *TextDecoder,
        globalObject: *JSGlobalObject,
        callFrame: *JSC.CallFrame,
    ) bun.JSError!JSC.JSValue {
        const args = callFrame.arguments();
        if (args.len < 1 or args.ptr[0].isUndefinedOrNull()) {
            return globalObject.throw("Input cannot be null", .{});
        }
        return JSC.JSValue.jsString(globalObject, "result");
    }

    pub fn getEncoding(this: *TextDecoder, globalObject: *JSGlobalObject) JSC.JSValue {
        return JSC.JSValue.createStringFromUTF8(globalObject, this.encoding);
    }

    fn deinit(this: *TextDecoder) void {
        // Release resources
    }

    pub fn finalize(this: *TextDecoder) void {
        this.deinit();
        bun.destroy(this);
    }
};

Key patterns:

  • Use bun.JSError!JSValue return type for error handling
  • Use globalObject not ctx
  • deinit() for cleanup, finalize() called by GC
  • Update src/bun.js/bindings/generated_classes_list.zig

CallFrame Access

const args = callFrame.arguments();
const first_arg = args.ptr[0];  // Access as slice
const argCount = args.len;
const thisValue = callFrame.thisValue();

Property Caching

For cache: true properties, generated accessors:

// Get cached value
pub fn encodingGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
    const result = TextDecoderPrototype__encodingGetCachedValue(thisValue);
    if (result == .zero) return null;
    return result;
}

// Set cached value
pub fn encodingSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
    TextDecoderPrototype__encodingSetCachedValue(thisValue, globalObject, value);
}

Error Handling

pub fn method(this: *MyClass, globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue {
    const args = callFrame.arguments();
    if (args.len < 1) {
        return globalObject.throw("Missing required argument", .{});
    }
    return JSC.JSValue.jsString(globalObject, "Success!");
}

Memory Management

pub fn deinit(this: *TextDecoder) void {
    this._encoding.deref();
    if (this.buffer) |buffer| {
        bun.default_allocator.free(buffer);
    }
}

pub fn finalize(this: *TextDecoder) void {
    JSC.markBinding(@src());
    this.deinit();
    bun.default_allocator.destroy(this);
}

Creating a New Binding

  1. Define interface in .classes.ts:
define({
  name: "MyClass",
  constructor: true,
  finalize: true,
  proto: {
    myMethod: { args: 1 },
    myProperty: { getter: true, cache: true },
  },
});
  1. Implement in .zig:
pub const MyClass = struct {
    pub const js = JSC.Codegen.JSMyClass;
    pub const toJS = js.toJS;
    pub const fromJS = js.fromJS;

    value: []const u8,

    pub const new = bun.TrivialNew(@This());

    pub fn constructor(globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!*MyClass {
        return MyClass.new(.{ .value = "" });
    }

    pub fn myMethod(this: *MyClass, globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue {
        return JSC.JSValue.jsUndefined();
    }

    pub fn getMyProperty(this: *MyClass, globalObject: *JSGlobalObject) JSC.JSValue {
        return JSC.JSValue.jsString(globalObject, this.value);
    }

    pub fn deinit(this: *MyClass) void {}

    pub fn finalize(this: *MyClass) void {
        this.deinit();
        bun.destroy(this);
    }
};
  1. Add to src/bun.js/bindings/generated_classes_list.zig

Generated Components

  • C++ Classes: JSMyClass, JSMyClassPrototype, JSMyClassConstructor
  • Method Bindings: MyClassPrototype__myMethodCallback
  • Property Accessors: MyClassPrototype__myPropertyGetterWrap
  • Zig Bindings: External function declarations, cached value accessors

来源:oven-sh/bun · MIT 许可 · 许可原文 · MD 为来源页保存的历史版本