mirror of
https://github.com/napi-rs/napi-rs.git
synced 2025-12-08 19:56:07 +00:00
feat(napi): add node_api_create_object_with_properties support for enum creation (#2990)
This commit is contained in:
parent
94a6d37436
commit
e4f5360dcd
2
.github/workflows/asan.yml
vendored
2
.github/workflows/asan.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
# Linux-specific setup
|
||||
|
||||
21
.github/workflows/test-release.yaml
vendored
21
.github/workflows/test-release.yaml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install
|
||||
@ -301,7 +301,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Setup OpenHarmony SDK
|
||||
@ -354,7 +354,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install
|
||||
@ -408,12 +408,11 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
if: matrix.settings.host != 'windows-11-arm'
|
||||
with:
|
||||
targets: ${{ matrix.settings.target }}
|
||||
|
||||
@ -506,7 +505,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
- uses: actions/download-artifact@v6
|
||||
with:
|
||||
@ -555,7 +554,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-and-test-linux-armv7:
|
||||
name: stable - armv7-unknown-linux-gnueabihf - node@20
|
||||
name: stable - armv7-unknown-linux-gnueabihf - node@22
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@ -612,7 +611,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install
|
||||
@ -744,7 +743,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
cache-dependency-path: 'yarn.lock'
|
||||
- name: Install
|
||||
@ -784,7 +783,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@ -824,7 +823,7 @@ jobs:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
- name: Publish
|
||||
run: |
|
||||
|
||||
4
.github/workflows/zig.yaml
vendored
4
.github/workflows/zig.yaml
vendored
@ -36,7 +36,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
@ -118,7 +118,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 22
|
||||
node-version: 24
|
||||
cache: 'yarn'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
"@octokit/rest": "^22.0.1",
|
||||
"clipanion": "^4.0.0-rc.4",
|
||||
"colorette": "^2.0.20",
|
||||
"emnapi": "^1.7.0",
|
||||
"emnapi": "^1.7.1",
|
||||
"es-toolkit": "^1.41.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"obug": "^2.0.0",
|
||||
@ -74,7 +74,7 @@
|
||||
"typanion": "^3.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emnapi/runtime": "^1.7.0",
|
||||
"@emnapi/runtime": "^1.7.1",
|
||||
"@oxc-node/core": "^0.0.34",
|
||||
"@std/toml": "npm:@jsr/std__toml@^1.0.11",
|
||||
"@types/inquirer": "^9.0.9",
|
||||
@ -90,14 +90,11 @@
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emnapi/runtime": "^1.7.0"
|
||||
"@emnapi/runtime": "^1.7.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emnapi/runtime": {
|
||||
"optional": true
|
||||
},
|
||||
"emnapi": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"funding": {
|
||||
|
||||
@ -223,26 +223,35 @@ impl NapiEnum {
|
||||
let js_name_lit = Literal::string(&format!("{}\0", &self.js_name));
|
||||
let register_name = &self.register_name;
|
||||
|
||||
let mut define_properties = vec![];
|
||||
let mut value_conversions = vec![];
|
||||
let mut property_descriptors = vec![];
|
||||
let mut value_names = vec![];
|
||||
|
||||
for variant in self.variants.iter() {
|
||||
for (idx, variant) in self.variants.iter().enumerate() {
|
||||
let name_lit = Literal::string(&format!("{}\0", variant.name));
|
||||
let val_lit: Literal = (&variant.val).into();
|
||||
let value_var = Ident::new(&format!("__enum_value_{}", idx), Span::call_site());
|
||||
|
||||
define_properties.push(quote! {
|
||||
{
|
||||
let name = std::ffi::CStr::from_bytes_with_nul_unchecked(#name_lit.as_bytes());
|
||||
napi::bindgen_prelude::check_status!(
|
||||
napi::bindgen_prelude::sys::napi_set_named_property(
|
||||
env,
|
||||
obj_ptr, name.as_ptr(),
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #val_lit)?
|
||||
),
|
||||
"Failed to defined enum `{}`",
|
||||
#js_name_lit
|
||||
)?;
|
||||
};
|
||||
})
|
||||
value_names.push(value_var.clone());
|
||||
|
||||
// Convert the value first
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #val_lit)?;
|
||||
});
|
||||
|
||||
// Create property descriptor using the pre-computed value
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#name_lit.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::default,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let callback_name = Ident::new(
|
||||
@ -252,6 +261,17 @@ impl NapiEnum {
|
||||
|
||||
let js_mod_ident = js_mod_to_token_stream(self.js_mod.as_ref());
|
||||
|
||||
let object_creation = quote! {
|
||||
// Convert all values first, so error handling works correctly
|
||||
#(#value_conversions)*
|
||||
|
||||
let properties = [
|
||||
#(#property_descriptors),*
|
||||
];
|
||||
|
||||
let obj_ptr = napi::bindgen_prelude::create_object_with_properties(env, &properties)?;
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::all)]
|
||||
@ -259,14 +279,7 @@ impl NapiEnum {
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
let mut obj_ptr = ptr::null_mut();
|
||||
|
||||
napi::bindgen_prelude::check_status!(
|
||||
napi::bindgen_prelude::sys::napi_create_object(env, &mut obj_ptr),
|
||||
"Failed to create napi object"
|
||||
)?;
|
||||
|
||||
#(#define_properties)*
|
||||
#object_creation
|
||||
|
||||
Ok(obj_ptr)
|
||||
}
|
||||
|
||||
@ -482,12 +482,18 @@ impl NapiStruct {
|
||||
let name = &self.name;
|
||||
let name_str = self.name.to_string();
|
||||
|
||||
let mut obj_field_setters = vec![];
|
||||
let mut obj_field_getters = vec![];
|
||||
let mut field_destructions = vec![];
|
||||
|
||||
for field in obj.fields.iter() {
|
||||
// For optimized object creation: separate always-set fields from conditionally-set fields
|
||||
let mut value_conversions = vec![];
|
||||
let mut property_descriptors = vec![];
|
||||
let mut conditional_setters = vec![];
|
||||
let mut value_names = vec![];
|
||||
|
||||
for (idx, field) in obj.fields.iter().enumerate() {
|
||||
let field_js_name = &field.js_name;
|
||||
let field_js_name_lit = Literal::string(&format!("{}\0", field.js_name));
|
||||
let mut ty = field.ty.clone();
|
||||
remove_lifetime_in_type(&mut ty);
|
||||
let is_optional_field = if let syn::Type::Path(syn::TypePath {
|
||||
@ -503,28 +509,60 @@ impl NapiStruct {
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Determine if this field is always set or conditionally set
|
||||
let is_always_set = !is_optional_field || self.use_nullable;
|
||||
|
||||
match &field.name {
|
||||
syn::Member::Named(ident) => {
|
||||
let alias_ident = format_ident!("{}_", ident);
|
||||
field_destructions.push(quote! { #ident: #alias_ident });
|
||||
if is_optional_field {
|
||||
obj_field_setters.push(match self.use_nullable {
|
||||
false => quote! {
|
||||
if #alias_ident.is_some() {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
}
|
||||
},
|
||||
true => quote! {
|
||||
if let Some(#alias_ident) = #alias_ident {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
|
||||
if is_always_set {
|
||||
// This field is always set - use batched approach
|
||||
let value_var = Ident::new(&format!("__obj_value_{}", idx), Span::call_site());
|
||||
value_names.push(value_var.clone());
|
||||
|
||||
if is_optional_field {
|
||||
// Optional with use_nullable=true: set to value or null
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = if let Some(inner) = #alias_ident {
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, inner)?
|
||||
} else {
|
||||
obj.set(#field_js_name, napi::bindgen_prelude::Null)?;
|
||||
}
|
||||
},
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, napi::bindgen_prelude::Null)?
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// Non-optional: always set
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #alias_ident)?;
|
||||
});
|
||||
}
|
||||
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#field_js_name_lit.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::writable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::enumerable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::configurable,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
} else {
|
||||
obj_field_setters.push(quote! { obj.set(#field_js_name, #alias_ident)?; });
|
||||
// Optional with use_nullable=false: conditionally set
|
||||
conditional_setters.push(quote! {
|
||||
if #alias_ident.is_some() {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Getters remain the same
|
||||
if is_optional_field && !self.use_nullable {
|
||||
obj_field_getters.push(quote! {
|
||||
let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
|
||||
@ -547,24 +585,52 @@ impl NapiStruct {
|
||||
syn::Member::Unnamed(i) => {
|
||||
let arg_name = format_ident!("arg{}", i);
|
||||
field_destructions.push(quote! { #arg_name });
|
||||
if is_optional_field {
|
||||
obj_field_setters.push(match self.use_nullable {
|
||||
false => quote! {
|
||||
if #arg_name.is_some() {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
}
|
||||
},
|
||||
true => quote! {
|
||||
if let Some(#arg_name) = #arg_name {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
|
||||
if is_always_set {
|
||||
// This field is always set - use batched approach
|
||||
let value_var = Ident::new(&format!("__obj_value_{}", idx), Span::call_site());
|
||||
value_names.push(value_var.clone());
|
||||
|
||||
if is_optional_field {
|
||||
// Optional with use_nullable=true: set to value or null
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = if let Some(inner) = #arg_name {
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, inner)?
|
||||
} else {
|
||||
obj.set(#field_js_name, napi::bindgen_prelude::Null)?;
|
||||
}
|
||||
},
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, napi::bindgen_prelude::Null)?
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// Non-optional: always set
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #arg_name)?;
|
||||
});
|
||||
}
|
||||
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#field_js_name_lit.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::writable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::enumerable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::configurable,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
} else {
|
||||
obj_field_setters.push(quote! { obj.set(#field_js_name, #arg_name)?; });
|
||||
// Optional with use_nullable=false: conditionally set
|
||||
conditional_setters.push(quote! {
|
||||
if #arg_name.is_some() {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Getters remain the same
|
||||
if is_optional_field && !self.use_nullable {
|
||||
obj_field_getters.push(quote! { let #arg_name: #ty = obj.get(#field_js_name)?; });
|
||||
} else {
|
||||
@ -611,20 +677,48 @@ impl NapiStruct {
|
||||
)
|
||||
};
|
||||
|
||||
// Generate object creation code
|
||||
let object_creation = if conditional_setters.is_empty() {
|
||||
// All fields are always set - use fully batched approach
|
||||
quote! {
|
||||
// Convert all values first, so error handling works correctly
|
||||
#(#value_conversions)*
|
||||
|
||||
let properties = [
|
||||
#(#property_descriptors),*
|
||||
];
|
||||
|
||||
let obj_ptr = napi::bindgen_prelude::create_object_with_properties(env, &properties)?;
|
||||
Ok(obj_ptr)
|
||||
}
|
||||
} else {
|
||||
// Some fields are conditionally set - use batched for always-set, then add conditionals
|
||||
quote! {
|
||||
// Convert all always-set values first
|
||||
#(#value_conversions)*
|
||||
|
||||
let properties = [
|
||||
#(#property_descriptors),*
|
||||
];
|
||||
|
||||
let obj_ptr = napi::bindgen_prelude::create_object_with_properties(env, &properties)?;
|
||||
|
||||
// Wrap in Object for conditional field setters
|
||||
let mut obj = napi::bindgen_prelude::Object::from_raw(env, obj_ptr);
|
||||
|
||||
#(#conditional_setters)*
|
||||
|
||||
Ok(obj_ptr)
|
||||
}
|
||||
};
|
||||
|
||||
let to_napi_value = if obj.object_to_js {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
#to_napi_value_impl {
|
||||
unsafe fn to_napi_value(env: napi::bindgen_prelude::sys::napi_env, val: #name_with_lifetime) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
|
||||
#[allow(unused_variables)]
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
#[allow(unused_mut)]
|
||||
let mut obj = napi::bindgen_prelude::Object::new(&env_wrapper)?;
|
||||
|
||||
let #destructed_fields = val;
|
||||
#(#obj_field_setters)*
|
||||
|
||||
napi::bindgen_prelude::Object::to_napi_value(env, obj)
|
||||
#object_creation
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -865,6 +959,7 @@ impl NapiStruct {
|
||||
let name = &self.name;
|
||||
let name_str = self.name.to_string();
|
||||
let discriminant = structured_enum.discriminant.as_str();
|
||||
let discriminant_null_terminated = format!("{}\0", discriminant);
|
||||
|
||||
let mut variant_arm_setters = vec![];
|
||||
let mut variant_arm_getters = vec![];
|
||||
@ -875,13 +970,38 @@ impl NapiStruct {
|
||||
if let Some(case) = structured_enum.discriminant_case {
|
||||
variant_name_str = to_case(variant_name_str, case);
|
||||
}
|
||||
let mut obj_field_setters = vec![quote! {
|
||||
obj.set(#discriminant, #variant_name_str)?;
|
||||
}];
|
||||
|
||||
let mut obj_field_getters = vec![];
|
||||
let mut field_destructions = vec![];
|
||||
for field in variant.fields.iter() {
|
||||
|
||||
// For optimized object creation
|
||||
let mut value_conversions = vec![];
|
||||
let mut property_descriptors = vec![];
|
||||
let mut conditional_setters = vec![];
|
||||
|
||||
// First property is always the discriminant
|
||||
let discriminant_value_var = Ident::new("__discriminant_value", Span::call_site());
|
||||
value_conversions.push(quote! {
|
||||
let #discriminant_value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #variant_name_str)?;
|
||||
});
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#discriminant_null_terminated.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #discriminant_value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::writable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::enumerable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::configurable,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
|
||||
for (idx, field) in variant.fields.iter().enumerate() {
|
||||
let field_js_name = &field.js_name;
|
||||
let field_js_name_lit = Literal::string(&format!("{}\0", field.js_name));
|
||||
let mut ty = field.ty.clone();
|
||||
remove_lifetime_in_type(&mut ty);
|
||||
let is_optional_field = if let syn::Type::Path(syn::TypePath {
|
||||
@ -897,28 +1017,59 @@ impl NapiStruct {
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Determine if this field is always set or conditionally set
|
||||
let is_always_set = !is_optional_field || self.use_nullable;
|
||||
|
||||
match &field.name {
|
||||
syn::Member::Named(ident) => {
|
||||
let alias_ident = format_ident!("{}_", ident);
|
||||
field_destructions.push(quote! { #ident: #alias_ident });
|
||||
if is_optional_field {
|
||||
obj_field_setters.push(match self.use_nullable {
|
||||
false => quote! {
|
||||
if #alias_ident.is_some() {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
}
|
||||
},
|
||||
true => quote! {
|
||||
if let Some(#alias_ident) = #alias_ident {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
|
||||
if is_always_set {
|
||||
// This field is always set - use batched approach
|
||||
let value_var = Ident::new(&format!("__variant_value_{}", idx), Span::call_site());
|
||||
|
||||
if is_optional_field {
|
||||
// Optional with use_nullable=true: set to value or null
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = if let Some(inner) = #alias_ident {
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, inner)?
|
||||
} else {
|
||||
obj.set(#field_js_name, napi::bindgen_prelude::Null)?;
|
||||
}
|
||||
},
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, napi::bindgen_prelude::Null)?
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// Non-optional: always set
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #alias_ident)?;
|
||||
});
|
||||
}
|
||||
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#field_js_name_lit.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::writable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::enumerable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::configurable,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
} else {
|
||||
obj_field_setters.push(quote! { obj.set(#field_js_name, #alias_ident)?; });
|
||||
// Optional with use_nullable=false: conditionally set
|
||||
conditional_setters.push(quote! {
|
||||
if #alias_ident.is_some() {
|
||||
obj.set(#field_js_name, #alias_ident)?;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Getters remain the same
|
||||
if is_optional_field && !self.use_nullable {
|
||||
obj_field_getters.push(quote! {
|
||||
let #alias_ident: #ty = obj.get(#field_js_name).map_err(|mut err| {
|
||||
@ -941,33 +1092,60 @@ impl NapiStruct {
|
||||
syn::Member::Unnamed(i) => {
|
||||
let arg_name = format_ident!("arg{}", i);
|
||||
field_destructions.push(quote! { #arg_name });
|
||||
if is_optional_field {
|
||||
obj_field_setters.push(match self.use_nullable {
|
||||
false => quote! {
|
||||
if #arg_name.is_some() {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
}
|
||||
},
|
||||
true => quote! {
|
||||
if let Some(#arg_name) = #arg_name {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
|
||||
if is_always_set {
|
||||
// This field is always set - use batched approach
|
||||
let value_var = Ident::new(&format!("__variant_value_{}", idx), Span::call_site());
|
||||
|
||||
if is_optional_field {
|
||||
// Optional with use_nullable=true: set to value or null
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = if let Some(inner) = #arg_name {
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, inner)?
|
||||
} else {
|
||||
obj.set(#field_js_name, napi::bindgen_prelude::Null)?;
|
||||
}
|
||||
},
|
||||
napi::bindgen_prelude::ToNapiValue::to_napi_value(env, napi::bindgen_prelude::Null)?
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// Non-optional: always set
|
||||
value_conversions.push(quote! {
|
||||
let #value_var = napi::bindgen_prelude::ToNapiValue::to_napi_value(env, #arg_name)?;
|
||||
});
|
||||
}
|
||||
|
||||
property_descriptors.push(quote! {
|
||||
napi::bindgen_prelude::sys::napi_property_descriptor {
|
||||
utf8name: std::ffi::CStr::from_bytes_with_nul_unchecked(#field_js_name_lit.as_bytes()).as_ptr(),
|
||||
name: std::ptr::null_mut(),
|
||||
method: None,
|
||||
getter: None,
|
||||
setter: None,
|
||||
value: #value_var,
|
||||
attributes: napi::bindgen_prelude::sys::PropertyAttributes::writable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::enumerable
|
||||
| napi::bindgen_prelude::sys::PropertyAttributes::configurable,
|
||||
data: std::ptr::null_mut(),
|
||||
}
|
||||
});
|
||||
} else {
|
||||
obj_field_setters.push(quote! { obj.set(#field_js_name, #arg_name)?; });
|
||||
// Optional with use_nullable=false: conditionally set
|
||||
conditional_setters.push(quote! {
|
||||
if #arg_name.is_some() {
|
||||
obj.set(#field_js_name, #arg_name)?;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Getters remain the same
|
||||
if is_optional_field && !self.use_nullable {
|
||||
obj_field_getters.push(quote! { let #arg_name: #ty = obj.get(#field_js_name)?; });
|
||||
} else {
|
||||
obj_field_getters.push(quote! {
|
||||
let #arg_name: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi::bindgen_prelude::Error::new(
|
||||
napi::bindgen_prelude::Status::InvalidArg,
|
||||
format!("Missing field `{}`", #field_js_name),
|
||||
))?;
|
||||
});
|
||||
let #arg_name: #ty = obj.get(#field_js_name)?.ok_or_else(|| napi::bindgen_prelude::Error::new(
|
||||
napi::bindgen_prelude::Status::InvalidArg,
|
||||
format!("Missing field `{}`", #field_js_name),
|
||||
))?;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -983,9 +1161,39 @@ impl NapiStruct {
|
||||
}
|
||||
};
|
||||
|
||||
// Generate object creation for this variant
|
||||
let variant_object_creation = if conditional_setters.is_empty() {
|
||||
// All fields are always set - use fully batched approach
|
||||
quote! {
|
||||
#(#value_conversions)*
|
||||
|
||||
let properties = [
|
||||
#(#property_descriptors),*
|
||||
];
|
||||
|
||||
napi::bindgen_prelude::create_object_with_properties(env, &properties)
|
||||
}
|
||||
} else {
|
||||
// Some fields are conditionally set
|
||||
quote! {
|
||||
#(#value_conversions)*
|
||||
|
||||
let properties = [
|
||||
#(#property_descriptors),*
|
||||
];
|
||||
|
||||
let obj_ptr = napi::bindgen_prelude::create_object_with_properties(env, &properties)?;
|
||||
let mut obj = napi::bindgen_prelude::Object::from_raw(env, obj_ptr);
|
||||
|
||||
#(#conditional_setters)*
|
||||
|
||||
Ok(obj_ptr)
|
||||
}
|
||||
};
|
||||
|
||||
variant_arm_setters.push(quote! {
|
||||
#destructed_fields => {
|
||||
#(#obj_field_setters)*
|
||||
#variant_object_creation
|
||||
},
|
||||
});
|
||||
|
||||
@ -1001,15 +1209,9 @@ impl NapiStruct {
|
||||
quote! {
|
||||
impl napi::bindgen_prelude::ToNapiValue for #name {
|
||||
unsafe fn to_napi_value(env: napi::bindgen_prelude::sys::napi_env, val: #name) -> napi::bindgen_prelude::Result<napi::bindgen_prelude::sys::napi_value> {
|
||||
#[allow(unused_variables)]
|
||||
let env_wrapper = napi::bindgen_prelude::Env::from(env);
|
||||
#[allow(unused_mut)]
|
||||
let mut obj = napi::bindgen_prelude::Object::new(&env_wrapper)?;
|
||||
match val {
|
||||
#(#variant_arm_setters)*
|
||||
};
|
||||
|
||||
napi::bindgen_prelude::Object::to_napi_value(env, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ async = ["tokio_rt"]
|
||||
chrono_date = ["chrono", "napi5"]
|
||||
# Enable deprecated types and traits for compatibility
|
||||
compat-mode = []
|
||||
default = ["napi4"]
|
||||
default = ["napi4", "dyn-symbols"]
|
||||
deferred_trace = ["napi4"]
|
||||
error_anyhow = ["anyhow"]
|
||||
experimental = ["napi-sys/experimental"]
|
||||
|
||||
@ -25,25 +25,31 @@ where
|
||||
{
|
||||
unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let env = Env::from(raw_env);
|
||||
#[cfg_attr(feature = "experimental", allow(unused_mut))]
|
||||
#[cfg_attr(feature = "napi10", allow(unused_mut))]
|
||||
let mut obj = Object::new(&env)?;
|
||||
#[cfg(all(
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
let node_version = NODE_VERSION.get().unwrap();
|
||||
for (k, v) in val.into_iter() {
|
||||
#[cfg(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
{
|
||||
if NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
|
||||
if node_version.major >= 20 && node_version.minor >= 18 {
|
||||
fast_set_property(raw_env, obj.0.value, k, v)?;
|
||||
} else {
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
}
|
||||
#[cfg(not(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
)))]
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
@ -91,25 +97,31 @@ where
|
||||
{
|
||||
unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let env = Env::from(raw_env);
|
||||
#[cfg_attr(feature = "experimental", allow(unused_mut))]
|
||||
#[cfg_attr(feature = "napi10", allow(unused_mut))]
|
||||
let mut obj = Object::new(&env)?;
|
||||
#[cfg(all(
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
let node_version = NODE_VERSION.get().unwrap();
|
||||
for (k, v) in val.into_iter() {
|
||||
#[cfg(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
{
|
||||
if crate::bindgen_runtime::NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
|
||||
if node_version.major >= 20 && node_version.minor >= 18 {
|
||||
fast_set_property(raw_env, obj.0.value, k, v)?;
|
||||
} else {
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
}
|
||||
#[cfg(not(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
)))]
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
@ -159,16 +171,22 @@ where
|
||||
{
|
||||
unsafe fn to_napi_value(raw_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
|
||||
let env = Env::from(raw_env);
|
||||
#[cfg_attr(feature = "experimental", allow(unused_mut))]
|
||||
#[cfg_attr(feature = "napi10", allow(unused_mut))]
|
||||
let mut obj = Object::new(&env)?;
|
||||
#[cfg(all(
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
let node_version = NODE_VERSION.get().unwrap();
|
||||
for (k, v) in val.into_iter() {
|
||||
#[cfg(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
{
|
||||
if crate::bindgen_runtime::NODE_VERSION_MAJOR >= 20 && NODE_VERSION_MINOR >= 18 {
|
||||
if node_version.major >= 20 && node_version.minor >= 18 {
|
||||
fast_set_property(raw_env, obj.0.value, k, v)?;
|
||||
} else {
|
||||
obj.set(k.as_ref(), v)?;
|
||||
@ -177,7 +195,7 @@ where
|
||||
#[cfg(not(all(
|
||||
feature = "experimental",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
)))]
|
||||
obj.set(k.as_ref(), v)?;
|
||||
}
|
||||
@ -207,9 +225,9 @@ where
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "experimental",
|
||||
feature = "napi10",
|
||||
feature = "node_version_detect",
|
||||
any(all(target_os = "linux", feature = "dyn-symbols"), target_os = "macos")
|
||||
feature = "dyn-symbols"
|
||||
))]
|
||||
fn fast_set_property<K: AsRef<str>, V: ToNapiValue>(
|
||||
raw_env: sys::napi_env,
|
||||
|
||||
@ -113,3 +113,85 @@ pub unsafe extern "C" fn drop_buffer_slice(
|
||||
drop(Vec::from_raw_parts(finalize_data, len, cap));
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an object with properties
|
||||
///
|
||||
/// When the `experimental` feature is enabled, uses `napi_create_object_with_properties`
|
||||
/// which creates the object with all properties in a single optimized call.
|
||||
/// Otherwise falls back to `napi_create_object` + `napi_define_properties`.
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(feature = "noop"))]
|
||||
#[inline]
|
||||
pub unsafe fn create_object_with_properties(
|
||||
env: sys::napi_env,
|
||||
properties: &[sys::napi_property_descriptor],
|
||||
) -> Result<sys::napi_value> {
|
||||
use crate::check_status;
|
||||
|
||||
let mut obj_ptr = std::ptr::null_mut();
|
||||
|
||||
#[cfg(all(
|
||||
feature = "experimental",
|
||||
feature = "node_version_detect",
|
||||
not(target_family = "wasm")
|
||||
))]
|
||||
{
|
||||
let node_version = NODE_VERSION.get().unwrap();
|
||||
if !properties.is_empty()
|
||||
&& ((node_version.major == 25 && node_version.minor >= 2) || node_version.major > 25)
|
||||
{
|
||||
// Convert property names from C strings to napi_value
|
||||
let mut names: Vec<sys::napi_value> = Vec::with_capacity(properties.len());
|
||||
let mut values: Vec<sys::napi_value> = Vec::with_capacity(properties.len());
|
||||
|
||||
for prop in properties {
|
||||
let mut name_value = std::ptr::null_mut();
|
||||
// utf8name is a null-terminated C string, use -1 to auto-detect length
|
||||
check_status!(
|
||||
sys::napi_create_string_utf8(env, prop.utf8name, -1, &mut name_value),
|
||||
"Failed to create property name string",
|
||||
)?;
|
||||
names.push(name_value);
|
||||
values.push(prop.value);
|
||||
}
|
||||
|
||||
let mut result_obj = std::ptr::null_mut();
|
||||
check_status!(
|
||||
sys::napi_create_object_with_properties(
|
||||
env,
|
||||
std::ptr::null_mut(), // prototype_or_null
|
||||
names.as_ptr(),
|
||||
values.as_ptr(),
|
||||
properties.len(),
|
||||
&mut result_obj,
|
||||
),
|
||||
"Failed to create object with properties",
|
||||
)?;
|
||||
return Ok(result_obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: create object then define properties
|
||||
check_status!(
|
||||
sys::napi_create_object(env, &mut obj_ptr),
|
||||
"Failed to create object",
|
||||
)?;
|
||||
|
||||
if !properties.is_empty() {
|
||||
check_status!(
|
||||
sys::napi_define_properties(env, obj_ptr, properties.len(), properties.as_ptr()),
|
||||
"Failed to define properties",
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(obj_ptr)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature = "noop")]
|
||||
pub unsafe fn create_object_with_properties(
|
||||
_env: sys::napi_env,
|
||||
_properties: &[sys::napi_property_descriptor],
|
||||
) -> Result<sys::napi_value> {
|
||||
Ok(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ use std::ffi::CStr;
|
||||
use std::mem::MaybeUninit;
|
||||
#[cfg(not(feature = "noop"))]
|
||||
use std::ptr;
|
||||
#[cfg(all(not(feature = "noop"), feature = "node_version_detect"))]
|
||||
use std::sync::OnceLock;
|
||||
#[cfg(not(feature = "noop"))]
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
@ -18,6 +20,8 @@ use std::{any::TypeId, collections::HashMap};
|
||||
|
||||
use rustc_hash::FxBuildHasher;
|
||||
|
||||
#[cfg(all(not(feature = "noop"), feature = "node_version_detect"))]
|
||||
use crate::NodeVersion;
|
||||
#[cfg(not(feature = "noop"))]
|
||||
use crate::{check_status, check_status_or_throw, JsError};
|
||||
use crate::{sys, Property, Result};
|
||||
@ -30,12 +34,8 @@ pub type ExportRegisterHookCallback =
|
||||
pub type ModuleExportsCallback =
|
||||
unsafe fn(env: sys::napi_env, exports: sys::napi_value) -> Result<()>;
|
||||
|
||||
#[cfg(feature = "node_version_detect")]
|
||||
pub static mut NODE_VERSION_MAJOR: u32 = 0;
|
||||
#[cfg(feature = "node_version_detect")]
|
||||
pub static mut NODE_VERSION_MINOR: u32 = 0;
|
||||
#[cfg(feature = "node_version_detect")]
|
||||
pub static mut NODE_VERSION_PATCH: u32 = 0;
|
||||
#[cfg(all(not(feature = "noop"), feature = "node_version_detect"))]
|
||||
pub static NODE_VERSION: OnceLock<NodeVersion> = OnceLock::new();
|
||||
|
||||
#[repr(transparent)]
|
||||
pub(crate) struct PersistedPerInstanceHashMap<K, V, S>(RefCell<HashMap<K, V, S>>);
|
||||
@ -109,7 +109,11 @@ static MODULE_CLASS_PROPERTIES: LazyLock<ModuleClassProperty> = LazyLock::new(De
|
||||
static MODULE_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
#[cfg(not(feature = "noop"))]
|
||||
static FIRST_MODULE_REGISTERED: AtomicBool = AtomicBool::new(false);
|
||||
#[cfg(all(feature = "tokio_rt", not(feature = "noop")))]
|
||||
#[cfg(all(
|
||||
feature = "tokio_rt",
|
||||
not(target_family = "wasm"),
|
||||
not(feature = "noop")
|
||||
))]
|
||||
static ENV_CLEANUP_HOOK_ADDED: RwLock<bool> = RwLock::new(false);
|
||||
thread_local! {
|
||||
static REGISTERED_CLASSES: LazyCell<RegisteredClasses> = LazyCell::new(Default::default);
|
||||
@ -253,18 +257,21 @@ pub unsafe extern "C" fn napi_register_module_v1(
|
||||
}
|
||||
#[cfg(feature = "node_version_detect")]
|
||||
{
|
||||
let mut node_version = MaybeUninit::uninit();
|
||||
check_status_or_throw!(
|
||||
env,
|
||||
unsafe { sys::napi_get_node_version(env, node_version.as_mut_ptr()) },
|
||||
"Failed to get node version"
|
||||
);
|
||||
let node_version = *node_version.assume_init();
|
||||
unsafe {
|
||||
NODE_VERSION_MAJOR = node_version.major;
|
||||
NODE_VERSION_MINOR = node_version.minor;
|
||||
NODE_VERSION_PATCH = node_version.patch;
|
||||
};
|
||||
NODE_VERSION.get_or_init(|| {
|
||||
let mut node_version = MaybeUninit::uninit();
|
||||
check_status_or_throw!(
|
||||
env,
|
||||
unsafe { sys::napi_get_node_version(env, node_version.as_mut_ptr()) },
|
||||
"Failed to get node version"
|
||||
);
|
||||
let node_version = *node_version.assume_init();
|
||||
NodeVersion {
|
||||
major: node_version.major,
|
||||
minor: node_version.minor,
|
||||
patch: node_version.patch,
|
||||
release: unsafe { CStr::from_ptr(node_version.release).to_str().unwrap() },
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if MODULE_COUNT.fetch_add(1, Ordering::SeqCst) != 0 {
|
||||
|
||||
@ -12,7 +12,8 @@ rust-version.workspace = true
|
||||
version = "3.1.1"
|
||||
|
||||
[features]
|
||||
dyn-symbols = [] # Deprecated feature
|
||||
default = ["dyn-symbols"]
|
||||
dyn-symbols = ["dep:libloading"]
|
||||
experimental = []
|
||||
napi1 = []
|
||||
napi2 = ["napi1"]
|
||||
@ -29,4 +30,4 @@ napi10 = ["napi9"]
|
||||
independent = true
|
||||
|
||||
[dependencies]
|
||||
libloading = { version = "0.9" }
|
||||
libloading = { version = "0.9", optional = true }
|
||||
|
||||
@ -802,6 +802,15 @@ mod experimental {
|
||||
finalize_data: *mut c_void,
|
||||
finalize_hint: *mut c_void,
|
||||
) -> napi_status;
|
||||
|
||||
fn napi_create_object_with_properties(
|
||||
env: napi_env,
|
||||
prototype_or_null: napi_value,
|
||||
property_names: *const napi_value,
|
||||
property_values: *const napi_value,
|
||||
property_count: usize,
|
||||
result: *mut napi_value,
|
||||
) -> napi_status;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -54,10 +54,8 @@ macro_rules! generate {
|
||||
let symbol: Result<libloading::Symbol<unsafe extern "C" fn ($(_: $ptype,)*)$( -> $rtype)*>, libloading::Error> = host.get(stringify!($name).as_bytes());
|
||||
match symbol {
|
||||
Ok(f) => *f,
|
||||
Err(e) => {
|
||||
#[cfg(debug_assertions)] {
|
||||
eprintln!("Load Node-API [{}] from host runtime failed: {}", stringify!($name), e);
|
||||
}
|
||||
Err(_) => {
|
||||
// ignore error, use the stub function
|
||||
NAPI.$name
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,8 +43,8 @@
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.7.0",
|
||||
"@emnapi/runtime": "^1.7.0",
|
||||
"@emnapi/core": "^1.7.1",
|
||||
"@emnapi/runtime": "^1.7.1",
|
||||
"@tybys/wasm-util": "^0.10.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
36
yarn.lock
36
yarn.lock
@ -104,22 +104,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emnapi/core@npm:^1.1.0, @emnapi/core@npm:^1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "@emnapi/core@npm:1.7.0"
|
||||
"@emnapi/core@npm:^1.1.0, @emnapi/core@npm:^1.7.0, @emnapi/core@npm:^1.7.1":
|
||||
version: 1.7.1
|
||||
resolution: "@emnapi/core@npm:1.7.1"
|
||||
dependencies:
|
||||
"@emnapi/wasi-threads": "npm:1.1.0"
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10c0/ea57802079fda31f87506bba63f1299f0fa60546c1a1a424d2d5926f98f1ffc4a94ae3c885155f4a60114c19d314addb45d94dc0e427ac1594cbfca7cd910a31
|
||||
checksum: 10c0/f3740be23440b439333e3ae3832163f60c96c4e35337f3220ceba88f36ee89a57a871d27c94eb7a9ff98a09911ed9a2089e477ab549f4d30029f8b907f84a351
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emnapi/runtime@npm:^1.1.0, @emnapi/runtime@npm:^1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "@emnapi/runtime@npm:1.7.0"
|
||||
"@emnapi/runtime@npm:^1.1.0, @emnapi/runtime@npm:^1.7.1":
|
||||
version: 1.7.1
|
||||
resolution: "@emnapi/runtime@npm:1.7.1"
|
||||
dependencies:
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10c0/b99334582effe146e9fb5cd9e7f866c6c7047a8576f642456d56984b574b40b2ba14e4aede26217fcefa1372ddd1e098a19912f17033a9ae469928b0dc65a682
|
||||
checksum: 10c0/26b851cd3e93877d8732a985a2ebf5152325bbacc6204ef5336a47359dedcc23faeb08cdfcb8bb389b5401b3e894b882bc1a1e55b4b7c1ed1e67c991a760ddd5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1366,7 +1366,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@napi-rs/cli@workspace:cli"
|
||||
dependencies:
|
||||
"@emnapi/runtime": "npm:^1.7.0"
|
||||
"@emnapi/runtime": "npm:^1.7.1"
|
||||
"@inquirer/prompts": "npm:^8.0.0"
|
||||
"@napi-rs/cross-toolchain": "npm:^1.0.3"
|
||||
"@napi-rs/wasm-tools": "npm:^1.0.1"
|
||||
@ -1380,7 +1380,7 @@ __metadata:
|
||||
ava: "npm:^6.4.1"
|
||||
clipanion: "npm:^4.0.0-rc.4"
|
||||
colorette: "npm:^2.0.20"
|
||||
emnapi: "npm:^1.7.0"
|
||||
emnapi: "npm:^1.7.1"
|
||||
empathic: "npm:^2.0.0"
|
||||
env-paths: "npm:^3.0.0"
|
||||
es-toolkit: "npm:^1.41.0"
|
||||
@ -1393,12 +1393,10 @@ __metadata:
|
||||
typanion: "npm:^3.14.0"
|
||||
typescript: "npm:^5.9.3"
|
||||
peerDependencies:
|
||||
"@emnapi/runtime": ^1.7.0
|
||||
"@emnapi/runtime": ^1.7.1
|
||||
peerDependenciesMeta:
|
||||
"@emnapi/runtime":
|
||||
optional: true
|
||||
emnapi:
|
||||
optional: true
|
||||
bin:
|
||||
napi: ./dist/cli.js
|
||||
napi-raw: ./cli.mjs
|
||||
@ -1826,8 +1824,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@napi-rs/wasm-runtime@workspace:wasm-runtime"
|
||||
dependencies:
|
||||
"@emnapi/core": "npm:^1.7.0"
|
||||
"@emnapi/runtime": "npm:^1.7.0"
|
||||
"@emnapi/core": "npm:^1.7.1"
|
||||
"@emnapi/runtime": "npm:^1.7.1"
|
||||
"@rollup/plugin-alias": "npm:^6.0.0"
|
||||
"@rollup/plugin-commonjs": "npm:^29.0.0"
|
||||
"@rollup/plugin-inject": "npm:^5.0.5"
|
||||
@ -6480,15 +6478,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"emnapi@npm:^1.7.0":
|
||||
version: 1.7.0
|
||||
resolution: "emnapi@npm:1.7.0"
|
||||
"emnapi@npm:^1.7.1":
|
||||
version: 1.7.1
|
||||
resolution: "emnapi@npm:1.7.1"
|
||||
peerDependencies:
|
||||
node-addon-api: ">= 6.1.0"
|
||||
peerDependenciesMeta:
|
||||
node-addon-api:
|
||||
optional: true
|
||||
checksum: 10c0/a09c849f46022bc42f971a7cd21f4bd9a98546d5cf655e8377ecdbfd909c9e4601e45d23e7d56174a5eb1cfc7db80e9565299d89bbe353e123b4a4e6463396af
|
||||
checksum: 10c0/e3b223cb75bed94a8d11a3fa4c1b621bf32556e3c31239c589593fc275df80630af1a113fb2598436c2b08d7d8fd0099d9d24a3fc08cabddca5b0aa044a14cf2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user