diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 814cfcd8..43d395c3 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -30,7 +30,9 @@ pub trait ToTypeDef { static KNOWN_TYPES: Lazy> = Lazy::new(|| { let mut map = HashMap::default(); map.extend([ + ("JsUndefined", "undefined"), ("()", "undefined"), + ("JsNumber", "number"), ("i8", "number"), ("i16", "number"), ("i32", "number"), @@ -47,12 +49,15 @@ static KNOWN_TYPES: Lazy> = Lazy::new(|| { ("isize", "BigInt"), ("JsBigInt", "BigInt"), ("BigInt", "BigInt"), + ("JsBoolean", "boolean"), ("bool", "boolean"), + ("JsString", "string"), ("String", "string"), ("str", "string"), ("Latin1String", "string"), ("Utf16String", "string"), ("char", "string"), + ("JsObject", "object"), ("Object", "object"), ("Value", "any"), ("Map", "Record"), @@ -71,7 +76,8 @@ static KNOWN_TYPES: Lazy> = Lazy::new(|| { ("Either5", "{} | {} | {} | {} | {}"), ("unknown", "unknown"), ("null", "null"), - ("symbol", "symbol"), + ("Symbol", "symbol"), + ("JsSymbol", "symbol"), ("external", "object"), ("AbortSignal", "AbortSignal"), ("JsFunction", "(...args: any[]) => any"), diff --git a/crates/napi/src/bindgen_runtime/js_values.rs b/crates/napi/src/bindgen_runtime/js_values.rs index ec880d07..65cd6ebc 100644 --- a/crates/napi/src/bindgen_runtime/js_values.rs +++ b/crates/napi/src/bindgen_runtime/js_values.rs @@ -17,6 +17,7 @@ mod promise; #[cfg(feature = "serde-json")] mod serde; mod string; +mod symbol; mod task; pub use array::*; @@ -30,6 +31,7 @@ pub use nil::*; pub use object::*; pub use promise::*; pub use string::*; +pub use symbol::*; pub use task::*; #[cfg(feature = "latin1")] diff --git a/crates/napi/src/bindgen_runtime/js_values/symbol.rs b/crates/napi/src/bindgen_runtime/js_values/symbol.rs new file mode 100644 index 00000000..51a7ff40 --- /dev/null +++ b/crates/napi/src/bindgen_runtime/js_values/symbol.rs @@ -0,0 +1,48 @@ +use std::{ffi::CString, ptr}; + +use crate::check_status; + +use super::ToNapiValue; + +pub struct Symbol { + desc: Option, +} + +impl Symbol { + pub fn new(desc: String) -> Self { + Self { desc: Some(desc) } + } + + pub fn identity() -> Self { + Self { desc: None } + } +} + +impl ToNapiValue for Symbol { + unsafe fn to_napi_value( + env: napi_sys::napi_env, + val: Self, + ) -> crate::Result { + let mut symbol_value = ptr::null_mut(); + check_status!(napi_sys::napi_create_symbol( + env, + match val.desc { + Some(desc) => { + let mut desc_string = ptr::null_mut(); + let desc_len = desc.len(); + let desc_c_string = CString::new(desc)?; + check_status!(napi_sys::napi_create_string_utf8( + env, + desc_c_string.as_ptr(), + desc_len, + &mut desc_string + ))?; + desc_string + } + None => ptr::null_mut(), + }, + &mut symbol_value + ))?; + Ok(symbol_value) + } +} diff --git a/crates/napi/src/js_values/mod.rs b/crates/napi/src/js_values/mod.rs index 87892a1a..1fd72bc2 100644 --- a/crates/napi/src/js_values/mod.rs +++ b/crates/napi/src/js_values/mod.rs @@ -260,12 +260,13 @@ macro_rules! impl_js_value_methods { macro_rules! impl_object_methods { ($js_value:ident) => { impl $js_value { - pub fn set_property(&mut self, key: JsString, value: V) -> Result<()> + pub fn set_property(&mut self, key: K, value: V) -> Result<()> where + K: NapiRaw, V: NapiRaw, { check_status!(unsafe { - sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw()) + sys::napi_set_property(self.0.env, self.0.value, key.raw(), value.raw()) }) } diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index df52895a..0f6c3615 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -35,7 +35,7 @@ Generated by [AVA](https://avajs.dev). export function listObjKeys(obj: object): Array␊ export function createObj(): object␊ export function getGlobal(): typeof global␊ - export function getUndefined(): JsUndefined␊ + export function getUndefined(): void␊ export function getNull(): JsNull␊ export function asyncPlus100(p: Promise): Promise␊ interface PackageJson {␊ @@ -50,6 +50,8 @@ Generated by [AVA](https://avajs.dev). export function concatStr(s: string): string␊ export function concatUtf16(s: string): string␊ export function concatLatin1(s: string): string␊ + export function setSymbolInObj(symbol: symbol): object␊ + export function createSymbol(): symbol␊ export function withoutAbortController(a: number, b: number): Promise␊ export function withAbortController(a: number, b: number, signal: AbortSignal): Promise␊ export function callThreadsafeFunction(callback: (...args: any[]) => any): void␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index a8561624..cc8aa757 100644 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index fd818df4..f5cb81fc 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -44,6 +44,8 @@ import { getGlobal, getUndefined, getNull, + setSymbolInObj, + createSymbol, } from '../' test('number', (t) => { @@ -156,6 +158,16 @@ test('get null', (t) => { } }) +test('pass symbol in', (t) => { + const sym = Symbol('test') + const obj = setSymbolInObj(sym) + t.is(obj[sym], 'a symbol') +}) + +test('create symbol', (t) => { + t.is(createSymbol().toString(), 'Symbol(a symbol)') +}) + test('Option', (t) => { t.is(mapOption(null), null) t.is(mapOption(3), 4) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index d850dddf..229af9ce 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -7,9 +7,7 @@ export function bigintAdd(a: BigInt, b: BigInt): BigInt export function createBigInt(): BigInt export function createBigIntI64(): BigInt export function getCwd(callback: (arg0: string) => void): void -export function readFile( - callback: (arg0: Error | undefined, arg1: string | null) => void, -): void +export function readFile(callback: (arg0: Error | undefined, arg1: string | null) => void): void export function eitherStringOrNumber(input: string | number): number export function returnEither(input: number): string | number export function either3(input: string | number | boolean): number @@ -17,21 +15,8 @@ interface Obj { v: string | number } export function either4(input: string | number | boolean | Obj): number -export enum Kind { - Dog = 0, - Cat = 1, - Duck = 2, -} -export enum CustomNumEnum { - One = 1, - Two = 2, - Three = 3, - Four = 4, - Six = 6, - Eight = 8, - Nine = 9, - Ten = 10, -} +export enum Kind { Dog = 0, Cat = 1, Duck = 2 } +export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 } export function enumToI32(e: CustomNumEnum): number export function throwError(): void export function mapOption(val: number | null): number | null @@ -40,7 +25,7 @@ export function fibonacci(n: number): number export function listObjKeys(obj: object): Array export function createObj(): object export function getGlobal(): typeof global -export function getUndefined(): JsUndefined +export function getUndefined(): void export function getNull(): JsNull export function asyncPlus100(p: Promise): Promise interface PackageJson { @@ -55,12 +40,10 @@ export function contains(source: string, target: string): boolean export function concatStr(s: string): string export function concatUtf16(s: string): string export function concatLatin1(s: string): string +export function setSymbolInObj(symbol: symbol): object +export function createSymbol(): symbol export function withoutAbortController(a: number, b: number): Promise -export function withAbortController( - a: number, - b: number, - signal: AbortSignal, -): Promise +export function withAbortController(a: number, b: number, signal: AbortSignal): Promise export function callThreadsafeFunction(callback: (...args: any[]) => any): void export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void export function getBuffer(): Buffer @@ -74,10 +57,14 @@ export class Animal { static getDogKind(): Kind } export class Blake2BHasher { + static withKey(key: Blake2bKey): Blake2BHasher } -export class Blake2BKey {} +export class Blake2BKey { + +} export class Context { + constructor() static withData(data: string): Context method(): string diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index 8c75aa37..bbd3e620 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -18,6 +18,7 @@ mod object; mod promise; mod serde; mod string; +mod symbol; mod task; mod threadsafe_function; mod typed_array; diff --git a/examples/napi/src/symbol.rs b/examples/napi/src/symbol.rs new file mode 100644 index 00000000..cc52be68 --- /dev/null +++ b/examples/napi/src/symbol.rs @@ -0,0 +1,13 @@ +use napi::{bindgen_prelude::*, Env, JsObject, JsSymbol}; + +#[napi] +pub fn set_symbol_in_obj(env: Env, symbol: JsSymbol) -> Result { + let mut obj = env.create_object()?; + obj.set_property(symbol, env.create_string("a symbol")?)?; + Ok(obj) +} + +#[napi] +pub fn create_symbol() -> Symbol { + Symbol::new("a symbol".to_owned()) +}