fix(napi-derive): fix union type generation for ts function notation (#1439)

* fix(backend): fix union type generation for ts function notation

* chore: update snapshot

* fix: naming
This commit is contained in:
Hana 2023-01-14 18:27:46 +08:00 committed by GitHub
parent c61b20234e
commit 78b6e1574a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 139 additions and 103 deletions

View file

@ -56,40 +56,40 @@ napi_ast_impl! {
(Const, NapiConst), (Const, NapiConst),
} }
pub(crate) static PRIMITIVE_TYPES: &[(&str, &str)] = &[ pub(crate) static PRIMITIVE_TYPES: &[(&str, (&str, bool, bool))] = &[
("JsUndefined", "undefined"), ("JsUndefined", ("undefined", false, false)),
("()", "undefined"), ("()", ("undefined", false, false)),
("Undefined", "undefined"), ("Undefined", ("undefined", false, false)),
("JsNumber", "number"), ("JsNumber", ("number", false, false)),
("i8", "number"), ("i8", ("number", false, false)),
("i16", "number"), ("i16", ("number", false, false)),
("i32", "number"), ("i32", ("number", false, false)),
("i64", "number"), ("i64", ("number", false, false)),
("f32", "number"), ("f32", ("number", false, false)),
("f64", "number"), ("f64", ("number", false, false)),
("u8", "number"), ("u8", ("number", false, false)),
("u16", "number"), ("u16", ("number", false, false)),
("u32", "number"), ("u32", ("number", false, false)),
("u64", "bigint"), ("u64", ("bigint", false, false)),
("i64n", "bigint"), ("i64n", ("bigint", false, false)),
("u128", "bigint"), ("u128", ("bigint", false, false)),
("i128", "bigint"), ("i128", ("bigint", false, false)),
("usize", "bigint"), ("usize", ("bigint", false, false)),
("isize", "bigint"), ("isize", ("bigint", false, false)),
("JsBigInt", "bigint"), ("JsBigInt", ("bigint", false, false)),
("BigInt", "bigint"), ("BigInt", ("bigint", false, false)),
("JsBoolean", "boolean"), ("JsBoolean", ("boolean", false, false)),
("bool", "boolean"), ("bool", ("boolean", false, false)),
("JsString", "string"), ("JsString", ("string", false, false)),
("String", "string"), ("String", ("string", false, false)),
("str", "string"), ("str", ("string", false, false)),
("Latin1String", "string"), ("Latin1String", ("string", false, false)),
("Utf16String", "string"), ("Utf16String", ("string", false, false)),
("char", "string"), ("char", ("string", false, false)),
("Null", "null"), ("Null", ("null", false, false)),
("JsNull", "null"), ("JsNull", ("null", false, false)),
("null", "null"), ("null", ("null", false, false)),
("Symbol", "symbol"), ("Symbol", ("symbol", false, false)),
("JsSymbol", "symbol"), ("JsSymbol", ("symbol", false, false)),
("JsFunction", "(...args: any[]) => any"), ("JsFunction", ("(...args: any[]) => any", true, false)),
]; ];

View file

@ -118,74 +118,75 @@ pub trait ToTypeDef {
fn to_type_def(&self) -> Option<TypeDef>; fn to_type_def(&self) -> Option<TypeDef>;
} }
static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| { /// Mapping from `rust_type` to (`ts_type`, `is_ts_function_type_notation`, `is_ts_union_type`)
static KNOWN_TYPES: Lazy<HashMap<&'static str, (&'static str, bool, bool)>> = Lazy::new(|| {
let mut map = HashMap::default(); let mut map = HashMap::default();
map.extend(crate::PRIMITIVE_TYPES.iter().cloned()); map.extend(crate::PRIMITIVE_TYPES.iter().cloned());
map.extend([ map.extend([
("JsObject", "object"), ("JsObject", ("object", false, false)),
("Object", "object"), ("Object", ("object", false, false)),
("Array", "unknown[]"), ("Array", ("unknown[]", false, false)),
("Value", "any"), ("Value", ("any", false, false)),
("Map", "Record<string, any>"), ("Map", ("Record<string, any>", false, false)),
("HashMap", "Record<{}, {}>"), ("HashMap", ("Record<{}, {}>", false, false)),
("ArrayBuffer", "ArrayBuffer"), ("ArrayBuffer", ("ArrayBuffer", false, false)),
("Int8Array", "Int8Array"), ("Int8Array", ("Int8Array", false, false)),
("Uint8Array", "Uint8Array"), ("Uint8Array", ("Uint8Array", false, false)),
("Uint8ClampedArray", "Uint8ClampedArray"), ("Uint8ClampedArray", ("Uint8ClampedArray", false, false)),
("Int16Array", "Int16Array"), ("Int16Array", ("Int16Array", false, false)),
("Uint16Array", "Uint16Array"), ("Uint16Array", ("Uint16Array", false, false)),
("Int32Array", "Int32Array"), ("Int32Array", ("Int32Array", false, false)),
("Uint32Array", "Uint32Array"), ("Uint32Array", ("Uint32Array", false, false)),
("Float32Array", "Float32Array"), ("Float32Array", ("Float32Array", false, false)),
("Float64Array", "Float64Array"), ("Float64Array", ("Float64Array", false, false)),
("BigInt64Array", "BigInt64Array"), ("BigInt64Array", ("BigInt64Array", false, false)),
("BigUint64Array", "BigUint64Array"), ("BigUint64Array", ("BigUint64Array", false, false)),
("DataView", "DataView"), ("DataView", ("DataView", false, false)),
("DateTime", "Date"), ("DateTime", ("Date", false, false)),
("Date", "Date"), ("Date", ("Date", false, false)),
("JsDate", "Date"), ("JsDate", ("Date", false, false)),
("JsBuffer", "Buffer"), ("JsBuffer", ("Buffer", false, false)),
("Buffer", "Buffer"), ("Buffer", ("Buffer", false, false)),
("Vec", "Array<{}>"), ("Vec", ("Array<{}>", false, false)),
("Result", "Error | {}"), ("Result", ("Error | {}", false, true)),
("Error", "Error"), ("Error", ("Error", false, false)),
("JsError", "Error"), ("JsError", ("Error", false, false)),
("JsTypeError", "TypeError"), ("JsTypeError", ("TypeError", false, false)),
("JsRangeError", "RangeError"), ("JsRangeError", ("RangeError", false, false)),
("ClassInstance", "{}"), ("ClassInstance", ("{}", false, false)),
("Either", "{} | {}"), ("Either", ("{} | {}", false, true)),
("Either3", "{} | {} | {}"), ("Either3", ("{} | {} | {}", false, true)),
("Either4", "{} | {} | {} | {}"), ("Either4", ("{} | {} | {} | {}", false, true)),
("Either5", "{} | {} | {} | {} | {}"), ("Either5", ("{} | {} | {} | {} | {}", false, true)),
("Either6", "{} | {} | {} | {} | {} | {}"), ("Either6", ("{} | {} | {} | {} | {} | {}", false, true)),
("Either7", "{} | {} | {} | {} | {} | {} | {}"), ("Either7", ("{} | {} | {} | {} | {} | {} | {}", false, true)),
("Either8", "{} | {} | {} | {} | {} | {} | {} | {}"), ("Either8", ("{} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either9", "{} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either9", ("{} | {} | {} | {} | {} | {} | {} | {} | {}",false, true)),
("Either10", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either10", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either11", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either11", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either12", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either12", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either13", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either13", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either14", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either14", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either15", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either15", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either16", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either16", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either17", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either17", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either18", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either18", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either19", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either19", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either20", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either20", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either21", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either21", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either22", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either22", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either23", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either23", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either24", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either24", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either25", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either25", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("Either26", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Either26", ("{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}", false, true)),
("external", "object"), ("external", ("object", false, false)),
("AbortSignal", "AbortSignal"), ("AbortSignal", ("AbortSignal", false, false)),
("JsGlobal", "typeof global"), ("JsGlobal", ("typeof global", false, false)),
("External", "ExternalObject<{}>"), ("External", ("ExternalObject<{}>", false, false)),
("unknown", "unknown"), ("unknown", ("unknown", false, false)),
("Unknown", "unknown"), ("Unknown", ("unknown", false, false)),
("JsUnknown", "unknown"), ("JsUnknown", ("unknown", false, false)),
("This", "this") ("This", ("this", false, false))
]); ]);
map map
@ -209,6 +210,30 @@ fn fill_ty(template: &str, args: Vec<String>) -> String {
ret ret
} }
fn is_ts_union_type(rust_ty: &str) -> bool {
KNOWN_TYPES
.get(rust_ty)
.map(|&(_, _, is_union_type)| is_union_type)
.unwrap_or(false)
}
fn is_ts_function_type_notation(ty: &Type) -> bool {
match ty {
Type::Path(syn::TypePath { qself: None, path }) => {
if let Some(syn::PathSegment { ident, .. }) = path.segments.last() {
let rust_ty = ident.to_string();
return KNOWN_TYPES
.get(&*rust_ty)
.map(|&(_, is_ts_fn, _)| is_ts_fn)
.unwrap_or(false);
}
false
}
_ => false,
}
}
pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (String, bool) { pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (String, bool) {
match ty { match ty {
Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty, is_struct_field), Type::Reference(r) => ty_to_ts_type(&r.elem, is_return_ty, is_struct_field),
@ -235,13 +260,19 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
if let Some(syn::PathSegment { ident, arguments }) = path.segments.last() { if let Some(syn::PathSegment { ident, arguments }) = path.segments.last() {
let rust_ty = ident.to_string(); let rust_ty = ident.to_string();
let is_ts_union_type = is_ts_union_type(&rust_ty);
let args = if let syn::PathArguments::AngleBracketed(arguments) = arguments { let args = if let syn::PathArguments::AngleBracketed(arguments) = arguments {
arguments arguments
.args .args
.iter() .iter()
.filter_map(|arg| match arg { .filter_map(|arg| match arg {
syn::GenericArgument::Type(generic_ty) => { syn::GenericArgument::Type(generic_ty) => {
Some(ty_to_ts_type(generic_ty, false, false)) Some(ty_to_ts_type(generic_ty, false, false)).map(|(mut ty, is_struct_field)| {
if is_ts_union_type && is_ts_function_type_notation(generic_ty) {
ty = format!("({})", ty);
}
(ty, is_struct_field)
})
} }
_ => None, _ => None,
}) })
@ -289,7 +320,7 @@ pub fn ty_to_ts_type(ty: &Type, is_return_ty: bool, is_struct_field: bool) -> (S
Some((rust_ty, false)) Some((rust_ty, false))
} }
}); });
} else if let Some(&known_ty) = KNOWN_TYPES.get(rust_ty.as_str()) { } else if let Some(&(known_ty, _, _)) = KNOWN_TYPES.get(rust_ty.as_str()) {
if known_ty.contains("{}") { if known_ty.contains("{}") {
ts_ty = Some(( ts_ty = Some((
fill_ty(known_ty, args.into_iter().map(|(arg, _)| arg).collect()), fill_ty(known_ty, args.into_iter().map(|(arg, _)| arg).collect()),

View file

@ -79,6 +79,7 @@ Generated by [AVA](https://avajs.dev).
baz: number␊ baz: number␊
}␊ }␊
export function eitherFromObjects(input: A | B | C): string␊ export function eitherFromObjects(input: A | B | C): string␊
export function eitherBoolOrFunction(input: boolean | ((...args: any[]) => any)): void␊
/** default enum values are continuos i32s start from 0 */␊ /** default enum values are continuos i32s start from 0 */␊
export const enum Kind {␊ export const enum Kind {␊
/** Barks */␊ /** Barks */␊

View file

@ -69,6 +69,7 @@ export interface C {
baz: number baz: number
} }
export function eitherFromObjects(input: A | B | C): string export function eitherFromObjects(input: A | B | C): string
export function eitherBoolOrFunction(input: boolean | ((...args: any[]) => any)): void
/** default enum values are continuos i32s start from 0 */ /** default enum values are continuos i32s start from 0 */
export const enum Kind { export const enum Kind {
/** Barks */ /** Barks */

View file

@ -127,3 +127,6 @@ pub fn either_from_objects(input: Either3<A, B, C>) -> String {
Either3::C(_) => "C".to_owned(), Either3::C(_) => "C".to_owned(),
} }
} }
#[napi]
pub fn either_bool_or_function(_input: Either<bool, JsFunction>) {}