diff --git a/.github/workflows/zig.yaml b/.github/workflows/zig.yaml index b1b025ec..b67bfb89 100644 --- a/.github/workflows/zig.yaml +++ b/.github/workflows/zig.yaml @@ -2,6 +2,7 @@ name: Zig-Cross-Compile env: DEBUG: 'napi:*' + TEST_ZIG_CROSS: '1' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -33,7 +34,7 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: 'yarn' - name: Install uses: dtolnay/rust-toolchain@stable @@ -99,7 +100,7 @@ jobs: - name: Setup node uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 cache: 'yarn' - name: Install dependencies run: | diff --git a/crates/backend/src/codegen/fn.rs b/crates/backend/src/codegen/fn.rs index d09a4716..5fb803a3 100644 --- a/crates/backend/src/codegen/fn.rs +++ b/crates/backend/src/codegen/fn.rs @@ -135,11 +135,16 @@ impl TryToTokens for NapiFn { { quote! { #native_call } } else if self.kind == FnKind::Constructor { + let return_from_factory = if self.catch_unwind { + quote! { return Ok(std::ptr::null_mut()); } + } else { + quote! { return std::ptr::null_mut(); } + }; quote! { // constructor function is called from class `factory` // so we should skip the original `constructor` logic if napi::__private::___CALL_FROM_FACTORY.with(|inner| inner.load(std::sync::atomic::Ordering::Relaxed)) { - return std::ptr::null_mut(); + #return_from_factory } #function_call_inner } diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md index 4bb95143..4fb8710f 100644 --- a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md @@ -99,6 +99,14 @@ Generated by [AVA](https://avajs.dev). }␊ export type Blake2bKey = Blake2BKey␊ ␊ + export class CatchOnConstructor {␊ + constructor()␊ + }␊ + ␊ + export class CatchOnConstructor2 {␊ + constructor()␊ + }␊ + ␊ export class ClassWithFactory {␊ name: string␊ static withName(name: string): ClassWithFactory␊ diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap index 30c3aa3f..339b96f0 100644 Binary files a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap differ diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 4eb3865b..5dd3d90c 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -108,6 +108,8 @@ const { arrayBufferPassThrough, JsRepo, CssStyleSheet, + CatchOnConstructor, + CatchOnConstructor2, asyncReduceBuffer, callbackReturnPromise, callbackReturnPromiseAndSpawn, @@ -234,6 +236,24 @@ test('class', (t) => { // @ts-expect-error plusOne.call('') }) + + t.notThrows(() => { + new CatchOnConstructor() + }) + + if (!process.env.TEST_ZIG_CROSS) { + t.throws( + () => { + new CatchOnConstructor2() + }, + (() => + process.env.WASI_TEST + ? undefined + : { + message: 'CatchOnConstructor2 panic', + })(), + ) + } }) test('async self in class', async (t) => { diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 340c29e2..aeaafcc3 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -89,6 +89,14 @@ export class Blake2BKey { } export type Blake2bKey = Blake2BKey +export class CatchOnConstructor { + constructor() +} + +export class CatchOnConstructor2 { + constructor() +} + export class ClassWithFactory { name: string static withName(name: string): ClassWithFactory diff --git a/examples/napi/src/class.rs b/examples/napi/src/class.rs index 8045dd12..a0956262 100644 --- a/examples/napi/src/class.rs +++ b/examples/napi/src/class.rs @@ -432,3 +432,25 @@ impl GetterSetterWithClosures { Ok(Self {}) } } + +#[napi] +pub struct CatchOnConstructor {} + +#[napi] +impl CatchOnConstructor { + #[napi(constructor, catch_unwind)] + pub fn new() -> Self { + Self {} + } +} + +#[napi] +pub struct CatchOnConstructor2 {} + +#[napi] +impl CatchOnConstructor2 { + #[napi(constructor, catch_unwind)] + pub fn new() -> Self { + panic!("CatchOnConstructor2 panic"); + } +}