feat(napi): output Rust doc comments in definitions as jsdoc comments

This commit is contained in:
Tim Fish 2021-11-29 04:54:45 +00:00 committed by GitHub
parent a25f0b990c
commit 18d2743862
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 251 additions and 73 deletions

View file

@ -329,6 +329,7 @@ interface TypeDef {
name: string name: string
def: string def: string
js_mod?: string js_mod?: string
js_doc: string
} }
async function processIntermediateTypeFile( async function processIntermediateTypeFile(
@ -358,49 +359,65 @@ export class ExternalObject<T> {
const allDefs = lines.map((line) => JSON.parse(line) as TypeDef) const allDefs = lines.map((line) => JSON.parse(line) as TypeDef)
function convertDefs(defs: TypeDef[], nested = false): string { function convertDefs(defs: TypeDef[], nested = false): string {
const classes = new Map<string, string>() const classes = new Map<string, { def: string; js_doc: string }>()
const impls = new Map<string, string>() const impls = new Map<string, string>()
let dts = '' let dts = ''
const lineStart = nested ? ' ' : '' const nest = nested ? 2 : 0
defs.forEach((def) => { defs.forEach((def) => {
switch (def.kind) { switch (def.kind) {
case 'struct': case 'struct':
if (!nested) { if (!nested) {
idents.push(def.name) idents.push(def.name)
} }
classes.set(def.name, def.def) classes.set(def.name, { def: def.def, js_doc: def.js_doc })
break break
case 'impl': case 'impl':
impls.set(def.name, def.def) impls.set(def.name, `${def.js_doc}${def.def}`)
break break
case 'interface': case 'interface':
dts += `${lineStart}interface ${def.name} {\n${indentLines( dts +=
def.def, indentLines(`${def.js_doc}export interface ${def.name} {`, nest) +
nested ? 4 : 2, '\n'
)}\n}\n` dts += indentLines(def.def, nest + 2) + '\n'
dts += indentLines(`}`, nest) + '\n'
break
case 'enum':
dts +=
indentLines(`${def.js_doc}export enum ${def.name} {`, nest) + '\n'
dts += indentLines(def.def, nest + 2) + '\n'
dts += indentLines(`}`, nest) + '\n'
break break
default: default:
if (!nested) { if (!nested) {
idents.push(def.name) idents.push(def.name)
} }
dts += lineStart + def.def + '\n' dts += indentLines(`${def.js_doc}${def.def}`, nest) + '\n'
} }
}) })
for (const [name, classDef] of classes.entries()) { for (const [name, { js_doc, def }] of classes.entries()) {
const implDef = impls.get(name) const implDef = impls.get(name)
dts += `${lineStart}export class ${name} {\n${indentLines( dts += indentLines(`${js_doc}export class ${name} {`, nest)
classDef,
nested ? 4 : 2, if (def) {
)}` dts += '\n' + indentLines(def, nest + 2)
}
if (implDef) { if (implDef) {
dts += `\n${indentLines(implDef, nested ? 4 : 2)}` dts += '\n' + indentLines(implDef, nest + 2)
} }
dts += `\n${lineStart}}\n` if (def || implDef) {
dts += '\n'
} else {
dts += ` `
} }
dts += indentLines(`}`, nest) + '\n'
}
return dts return dts
} }
@ -413,12 +430,7 @@ export class ExternalObject<T> {
), ),
).reduce((acc, [mod, defs]) => { ).reduce((acc, [mod, defs]) => {
idents.push(mod) idents.push(mod)
return ( return acc + `export namespace ${mod} {\n${convertDefs(defs, true)}}\n`
acc +
`export namespace ${mod} {
${convertDefs(defs, true)}
}\n`
)
}, '') }, '')
await unlinkAsync(source) await unlinkAsync(source)
@ -429,7 +441,11 @@ ${convertDefs(defs, true)}
function indentLines(input: string, spaces: number) { function indentLines(input: string, spaces: number) {
return input return input
.split('\n') .split('\n')
.map((line) => ''.padEnd(spaces, ' ') + line.trim()) .map(
(line) =>
''.padEnd(spaces, ' ') +
(line.startsWith(' *') ? line.trimEnd() : line.trim()),
)
.join('\n') .join('\n')
} }
@ -442,9 +458,10 @@ async function writeJsBinding(
if (distFileName) { if (distFileName) {
const template = createJsBinding(localName, packageName) const template = createJsBinding(localName, packageName)
const declareCodes = `const { ${idents.join(', ')} } = nativeBinding\n` const declareCodes = `const { ${idents.join(', ')} } = nativeBinding\n`
const exportsCode = idents.reduce((acc, cur) => { const exportsCode = idents.reduce(
return `${acc}\nmodule.exports.${cur} = ${cur}` (acc, cur) => `${acc}\nmodule.exports.${cur} = ${cur}`,
}, '') '',
)
await writeFileAsync( await writeFileAsync(
distFileName, distFileName,
template + declareCodes + exportsCode + '\n', template + declareCodes + exportsCode + '\n',

View file

@ -18,6 +18,7 @@ pub struct NapiFn {
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub ts_args_type: Option<String>, pub ts_args_type: Option<String>,
pub ts_return_type: Option<String>, pub ts_return_type: Option<String>,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -58,6 +59,7 @@ pub struct NapiStruct {
pub is_tuple: bool, pub is_tuple: bool,
pub kind: NapiStructKind, pub kind: NapiStructKind,
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -74,6 +76,7 @@ pub struct NapiStructField {
pub ty: syn::Type, pub ty: syn::Type,
pub getter: bool, pub getter: bool,
pub setter: bool, pub setter: bool,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -83,6 +86,7 @@ pub struct NapiImpl {
pub items: Vec<NapiFn>, pub items: Vec<NapiFn>,
pub task_output_type: Option<Type>, pub task_output_type: Option<Type>,
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -91,6 +95,7 @@ pub struct NapiEnum {
pub js_name: String, pub js_name: String,
pub variants: Vec<NapiEnumVariant>, pub variants: Vec<NapiEnumVariant>,
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -107,6 +112,7 @@ pub struct NapiConst {
pub type_name: Type, pub type_name: Type,
pub value: Expr, pub value: Expr,
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub comments: Vec<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -18,7 +18,6 @@ pub use typegen::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Napi { pub struct Napi {
pub comments: Vec<String>,
pub item: NapiItem, pub item: NapiItem,
} }

View file

@ -15,6 +15,51 @@ pub struct TypeDef {
pub name: String, pub name: String,
pub def: String, pub def: String,
pub js_mod: Option<String>, pub js_mod: Option<String>,
pub js_doc: String,
}
pub fn js_doc_from_comments(comments: &[String]) -> String {
if comments.is_empty() {
return "".to_owned();
}
if comments.len() == 1 {
return format!("/**{} */\n", comments[0]);
}
format!(
"/**\n{} */\n",
comments
.iter()
.map(|c| format!(" *{}\n", c))
.collect::<Vec<String>>()
.join("")
)
}
fn escape_json(src: &str) -> String {
use std::fmt::Write;
let mut escaped = String::with_capacity(src.len());
let mut utf16_buf = [0u16; 2];
for c in src.chars() {
match c {
'\x08' => escaped += "\\b",
'\x0c' => escaped += "\\f",
'\n' => escaped += "\\n",
'\r' => escaped += "\\r",
'\t' => escaped += "\\t",
'"' => escaped += "\\\"",
'\\' => escaped += "\\",
c if c.is_ascii_graphic() => escaped.push(c),
c => {
let encoded = c.encode_utf16(&mut utf16_buf);
for utf16 in encoded {
write!(&mut escaped, "\\u{:04X}", utf16).unwrap();
}
}
}
}
escaped
} }
impl ToString for TypeDef { impl ToString for TypeDef {
@ -25,8 +70,12 @@ impl ToString for TypeDef {
"".to_owned() "".to_owned()
}; };
format!( format!(
r#"{{"kind": "{}", "name": "{}", "def": "{}"{}}}"#, r#"{{"kind": "{}", "name": "{}", "js_doc": "{}", "def": "{}"{}}}"#,
self.kind, self.name, self.def, js_mod, self.kind,
self.name,
escape_json(&self.js_doc),
escape_json(&self.def),
js_mod,
) )
} }
} }

View file

@ -1,6 +1,6 @@
use super::{ToTypeDef, TypeDef}; use super::{ToTypeDef, TypeDef};
use crate::{ty_to_ts_type, NapiConst}; use crate::{js_doc_from_comments, ty_to_ts_type, NapiConst};
impl ToTypeDef for NapiConst { impl ToTypeDef for NapiConst {
fn to_type_def(&self) -> TypeDef { fn to_type_def(&self) -> TypeDef {
@ -13,6 +13,7 @@ impl ToTypeDef for NapiConst {
ty_to_ts_type(&self.type_name, false).0 ty_to_ts_type(&self.type_name, false).0
), ),
js_mod: self.js_mod.to_owned(), js_mod: self.js_mod.to_owned(),
js_doc: js_doc_from_comments(&self.comments),
} }
} }
} }

View file

@ -1,16 +1,13 @@
use super::{ToTypeDef, TypeDef}; use super::{ToTypeDef, TypeDef};
use crate::NapiEnum; use crate::{js_doc_from_comments, NapiEnum};
impl ToTypeDef for NapiEnum { impl ToTypeDef for NapiEnum {
fn to_type_def(&self) -> TypeDef { fn to_type_def(&self) -> TypeDef {
TypeDef { TypeDef {
kind: "enum".to_owned(), kind: "enum".to_owned(),
name: self.js_name.to_owned(), name: self.js_name.to_owned(),
def: format!( def: self.gen_ts_variants(),
r"export enum {js_name} {{ {variants} }}", js_doc: js_doc_from_comments(&self.comments),
js_name = &self.js_name,
variants = self.gen_ts_variants()
),
js_mod: self.js_mod.to_owned(), js_mod: self.js_mod.to_owned(),
} }
} }
@ -21,8 +18,15 @@ impl NapiEnum {
self self
.variants .variants
.iter() .iter()
.map(|v| format!("{} = {}", v.name, v.val)) .map(|v| {
format!(
"{}{} = {}",
js_doc_from_comments(&v.comments),
v.name,
v.val,
)
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(",\n ")
} }
} }

View file

@ -3,7 +3,7 @@ use quote::ToTokens;
use syn::Pat; use syn::Pat;
use super::{ty_to_ts_type, ToTypeDef, TypeDef}; use super::{ty_to_ts_type, ToTypeDef, TypeDef};
use crate::{CallbackArg, FnKind, NapiFn}; use crate::{js_doc_from_comments, CallbackArg, FnKind, NapiFn};
impl ToTypeDef for NapiFn { impl ToTypeDef for NapiFn {
fn to_type_def(&self) -> TypeDef { fn to_type_def(&self) -> TypeDef {
@ -27,6 +27,7 @@ impl ToTypeDef for NapiFn {
name: self.js_name.clone(), name: self.js_name.clone(),
def, def,
js_mod: self.js_mod.to_owned(), js_mod: self.js_mod.to_owned(),
js_doc: js_doc_from_comments(&self.comments),
} }
} }
} }

View file

@ -7,6 +7,7 @@ impl ToTypeDef for NapiMod {
name: self.js_name.clone(), name: self.js_name.clone(),
def: "".to_owned(), def: "".to_owned(),
js_mod: None, js_mod: None,
js_doc: "".to_owned(),
} }
} }
} }

View file

@ -2,7 +2,7 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use super::{ToTypeDef, TypeDef}; use super::{ToTypeDef, TypeDef};
use crate::{ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind}; use crate::{js_doc_from_comments, ty_to_ts_type, NapiImpl, NapiStruct, NapiStructKind};
thread_local! { thread_local! {
pub(crate) static TASK_STRUCTS: RefCell<HashMap<String, String>> = Default::default(); pub(crate) static TASK_STRUCTS: RefCell<HashMap<String, String>> = Default::default();
@ -24,6 +24,7 @@ impl ToTypeDef for NapiStruct {
name: self.js_name.to_owned(), name: self.js_name.to_owned(),
def: self.gen_ts_class(), def: self.gen_ts_class(),
js_mod: self.js_mod.to_owned(), js_mod: self.js_mod.to_owned(),
js_doc: js_doc_from_comments(&self.comments),
} }
} }
} }
@ -42,10 +43,17 @@ impl ToTypeDef for NapiImpl {
def: self def: self
.items .items
.iter() .iter()
.map(|f| f.to_type_def().def) .map(|f| {
format!(
"{}{}",
js_doc_from_comments(&f.comments),
f.to_type_def().def
)
})
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\\n"), .join("\\n"),
js_mod: self.js_mod.to_owned(), js_mod: self.js_mod.to_owned(),
js_doc: "".to_string(),
} }
} }
} }
@ -60,6 +68,10 @@ impl NapiStruct {
.map(|f| { .map(|f| {
let mut field_str = String::from(""); let mut field_str = String::from("");
if !f.comments.is_empty() {
field_str.push_str(&js_doc_from_comments(&f.comments))
}
if !f.setter { if !f.setter {
field_str.push_str("readonly ") field_str.push_str("readonly ")
} }

View file

@ -572,6 +572,7 @@ fn napi_fn_from_decl(
kind: fn_kind(opts), kind: fn_kind(opts),
fn_self, fn_self,
parent: parent.cloned(), parent: parent.cloned(),
comments: extract_doc_comments(&attrs),
attrs, attrs,
strict: opts.strict().is_some(), strict: opts.strict().is_some(),
js_mod: opts.namespace().map(|(m, _)| m.to_owned()), js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
@ -693,7 +694,6 @@ impl ConvertToAST for syn::ItemFn {
)?; )?;
Ok(Napi { Ok(Napi {
comments: vec![],
item: NapiItem::Fn(func), item: NapiItem::Fn(func),
}) })
} }
@ -758,12 +758,13 @@ impl ConvertToAST for syn::ItemStruct {
ty: field.ty.clone(), ty: field.ty.clone(),
getter: !ignored, getter: !ignored,
setter: !(ignored || readonly), setter: !(ignored || readonly),
comments: extract_doc_comments(&field.attrs),
}) })
} }
record_struct(&struct_name, js_name.clone(), &opts); record_struct(&struct_name, js_name.clone(), &opts);
Diagnostic::from_vec(errors).map(|()| Napi { Diagnostic::from_vec(errors).map(|()| Napi {
comments: vec![],
item: NapiItem::Struct(NapiStruct { item: NapiItem::Struct(NapiStruct {
js_name, js_name,
name: struct_name, name: struct_name,
@ -772,6 +773,7 @@ impl ConvertToAST for syn::ItemStruct {
is_tuple, is_tuple,
kind: struct_kind, kind: struct_kind,
js_mod: opts.namespace().map(|(m, _)| m.to_owned()), js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
comments: extract_doc_comments(&self.attrs),
}), }),
}) })
} }
@ -842,13 +844,13 @@ impl ConvertToAST for syn::ItemImpl {
} }
Ok(Napi { Ok(Napi {
comments: vec![],
item: NapiItem::Impl(NapiImpl { item: NapiItem::Impl(NapiImpl {
name: struct_name, name: struct_name,
js_name: struct_js_name, js_name: struct_js_name,
items, items,
task_output_type, task_output_type,
js_mod: impl_opts.namespace().map(|(m, _)| m.to_owned()), js_mod: impl_opts.namespace().map(|(m, _)| m.to_owned()),
comments: extract_doc_comments(&self.attrs),
}), }),
}) })
} }
@ -925,24 +927,22 @@ impl ConvertToAST for syn::ItemEnum {
}; };
last_variant_val = val; last_variant_val = val;
let comments = extract_doc_comments(&v.attrs);
Ok(NapiEnumVariant { Ok(NapiEnumVariant {
name: v.ident.clone(), name: v.ident.clone(),
val, val,
comments, comments: extract_doc_comments(&v.attrs),
}) })
}) })
.collect::<BindgenResult<Vec<NapiEnumVariant>>>()?; .collect::<BindgenResult<Vec<NapiEnumVariant>>>()?;
let comments = extract_doc_comments(&self.attrs);
Ok(Napi { Ok(Napi {
comments,
item: NapiItem::Enum(NapiEnum { item: NapiItem::Enum(NapiEnum {
name: self.ident.clone(), name: self.ident.clone(),
js_name, js_name,
variants, variants,
js_mod: opts.namespace().map(|(m, _)| m.to_owned()), js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
comments: extract_doc_comments(&self.attrs),
}), }),
}) })
} }
@ -952,7 +952,6 @@ impl ConvertToAST for syn::ItemConst {
fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> { fn convert_to_ast(&mut self, opts: BindgenAttrs) -> BindgenResult<Napi> {
match self.vis { match self.vis {
Visibility::Public(_) => Ok(Napi { Visibility::Public(_) => Ok(Napi {
comments: vec![],
item: NapiItem::Const(NapiConst { item: NapiItem::Const(NapiConst {
name: self.ident.clone(), name: self.ident.clone(),
js_name: opts js_name: opts
@ -961,6 +960,7 @@ impl ConvertToAST for syn::ItemConst {
type_name: *self.ty.clone(), type_name: *self.ty.clone(),
value: *self.expr.clone(), value: *self.expr.clone(),
js_mod: opts.namespace().map(|(m, _)| m.to_owned()), js_mod: opts.namespace().map(|(m, _)| m.to_owned()),
comments: extract_doc_comments(&self.attrs),
}), }),
}), }),
_ => bail_span!(self, "only public const allowed"), _ => bail_span!(self, "only public const allowed"),

View file

@ -16,8 +16,10 @@ Generated by [AVA](https://avajs.dev).
[K: symbol]: T␊ [K: symbol]: T␊
}␊ }␊
}␊ }␊
/** This is a const */␊
export const DEFAULT_COST: number␊ export const DEFAULT_COST: number␊
export function getWords(): Array<string> export function getWords(): Array<string>
/** Gets some numbers */␊
export function getNums(): Array<number> export function getNums(): Array<number>
export function sumNums(nums: Array<number>): number␊ export function sumNums(nums: Array<number>): number␊
export function readFileAsync(path: string): Promise<Buffer> export function readFileAsync(path: string): Promise<Buffer>
@ -26,16 +28,35 @@ Generated by [AVA](https://avajs.dev).
export function createBigInt(): BigInt␊ export function createBigInt(): BigInt␊
export function createBigIntI64(): BigInt␊ export function createBigIntI64(): BigInt␊
export function getCwd(callback: (arg0: string) => void): void␊ export function getCwd(callback: (arg0: string) => void): void␊
/** napi = { version = 2, features = ["serde-json"] } */␊
export function readFile(callback: (arg0: Error | undefined, arg1?: string | undefined | null) => void): void␊ export function readFile(callback: (arg0: Error | undefined, arg1?: string | undefined | null) => void): void␊
export function eitherStringOrNumber(input: string | number): number␊ export function eitherStringOrNumber(input: string | number): number␊
export function returnEither(input: number): string | number␊ export function returnEither(input: number): string | number␊
export function either3(input: string | number | boolean): number␊ export function either3(input: string | number | boolean): number␊
interface Obj {␊ export interface Obj {␊
v: string | number␊ v: string | number␊
}␊ }␊
export function either4(input: string | number | boolean | Obj): number␊ export function either4(input: string | number | boolean | Obj): number␊
export enum Kind { Dog = 0, Cat = 1, Duck = 2 }␊ /** default enum values are continuos i32s start from 0 */␊
export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 }␊ export enum Kind {␊
/** Barks */␊
Dog = 0,␊
/** Kills birds */␊
Cat = 1,␊
/** Tasty */␊
Duck = 2␊
}␊
/** You could break the step and for an new continuous value. */␊
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 enumToI32(e: CustomNumEnum): number␊
export function throwError(): void␊ export function throwError(): void␊
export function createExternal(size: number): ExternalObject<number> export function createExternal(size: number): ExternalObject<number>
@ -53,8 +74,10 @@ Generated by [AVA](https://avajs.dev).
export function getUndefined(): void␊ export function getUndefined(): void␊
export function getNull(): JsNull␊ export function getNull(): JsNull␊
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
interface PackageJson {␊ /** This is an interface for package.json */␊
export interface PackageJson {␊
name: string␊ name: string␊
/** The version of the package */␊
version: string␊ version: string␊
dependencies?: Record<string, any> | undefined | null␊ dependencies?: Record<string, any> | undefined | null␊
devDependencies?: Record<string, any> | undefined | null␊ devDependencies?: Record<string, any> | undefined | null␊
@ -73,22 +96,34 @@ Generated by [AVA](https://avajs.dev).
export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void␊ export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void␊
export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void␊ export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void␊
export function getBuffer(): Buffer␊ export function getBuffer(): Buffer␊
/**␊
* \`constructor\` option for \`struct\` requires all fields to be public,␊
* otherwise tag impl fn as constructor␊
* #[napi(constructor)]␊
*/␊
export class Animal {␊ export class Animal {␊
/** Kind of animal */␊
readonly kind: Kind␊ readonly kind: Kind␊
/** This is the constructor */␊
constructor(kind: Kind, name: string)␊ constructor(kind: Kind, name: string)␊
/** This is a factory method */␊
static withKind(kind: Kind): Animal␊ static withKind(kind: Kind): Animal␊
get name(): string␊ get name(): string␊
set name(name: string)␊ set name(name: string)␊
/**␊
* This is a␊
* multi-line comment␊
* with an emoji 🚀␊
*/␊
whoami(): string␊ whoami(): string␊
/** This is static... */␊
static getDogKind(): Kind␊ static getDogKind(): Kind␊
}␊ }␊
/** Smoking test for type generation */␊
export class Blake2BHasher {␊ export class Blake2BHasher {␊
static withKey(key: Blake2bKey): Blake2BHasher␊ static withKey(key: Blake2bKey): Blake2BHasher␊
}␊ }␊
export class Blake2BKey {␊ export class Blake2BKey { }␊
}␊
export class Context {␊ export class Context {␊
maybeNeed?: boolean | undefined | null␊ maybeNeed?: boolean | undefined | null␊
constructor()␊ constructor()␊
@ -103,18 +138,18 @@ Generated by [AVA](https://avajs.dev).
export namespace xxh3 {␊ export namespace xxh3 {␊
export const ALIGNMENT: number␊ export const ALIGNMENT: number␊
export function xxh3_64(input: Buffer): BigInt␊ export function xxh3_64(input: Buffer): BigInt␊
/** xxh128 function */␊
export function xxh128(input: Buffer): BigInt␊ export function xxh128(input: Buffer): BigInt␊
/** Xxh3 class */␊
export class Xxh3 {␊ export class Xxh3 {␊
constructor()␊ constructor()␊
/** update */␊
update(input: Buffer): void␊ update(input: Buffer): void␊
digest(): BigInt␊ digest(): BigInt␊
}␊ }␊
}␊ }␊
export namespace xxh2 {␊ export namespace xxh2 {␊
export function xxh2Plus(a: number, b: number): number␊ export function xxh2Plus(a: number, b: number): number␊
export function xxh3Xxh64Alias(input: Buffer): BigInt␊ export function xxh3Xxh64Alias(input: Buffer): BigInt␊
}␊ }␊
` `

View file

@ -6,8 +6,10 @@ export class ExternalObject<T> {
[K: symbol]: T [K: symbol]: T
} }
} }
/** This is a const */
export const DEFAULT_COST: number export const DEFAULT_COST: number
export function getWords(): Array<string> export function getWords(): Array<string>
/** Gets some numbers */
export function getNums(): Array<number> export function getNums(): Array<number>
export function sumNums(nums: Array<number>): number export function sumNums(nums: Array<number>): number
export function readFileAsync(path: string): Promise<Buffer> export function readFileAsync(path: string): Promise<Buffer>
@ -16,16 +18,35 @@ export function bigintAdd(a: BigInt, b: BigInt): BigInt
export function createBigInt(): BigInt export function createBigInt(): BigInt
export function createBigIntI64(): BigInt export function createBigIntI64(): BigInt
export function getCwd(callback: (arg0: string) => void): void export function getCwd(callback: (arg0: string) => void): void
/** napi = { version = 2, features = ["serde-json"] } */
export function readFile(callback: (arg0: Error | undefined, arg1?: string | undefined | null) => void): void export function readFile(callback: (arg0: Error | undefined, arg1?: string | undefined | null) => void): void
export function eitherStringOrNumber(input: string | number): number export function eitherStringOrNumber(input: string | number): number
export function returnEither(input: number): string | number export function returnEither(input: number): string | number
export function either3(input: string | number | boolean): number export function either3(input: string | number | boolean): number
interface Obj { export interface Obj {
v: string | number v: string | number
} }
export function either4(input: string | number | boolean | Obj): number export function either4(input: string | number | boolean | Obj): number
export enum Kind { Dog = 0, Cat = 1, Duck = 2 } /** default enum values are continuos i32s start from 0 */
export enum CustomNumEnum { One = 1, Two = 2, Three = 3, Four = 4, Six = 6, Eight = 8, Nine = 9, Ten = 10 } export enum Kind {
/** Barks */
Dog = 0,
/** Kills birds */
Cat = 1,
/** Tasty */
Duck = 2
}
/** You could break the step and for an new continuous value. */
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 enumToI32(e: CustomNumEnum): number
export function throwError(): void export function throwError(): void
export function createExternal(size: number): ExternalObject<number> export function createExternal(size: number): ExternalObject<number>
@ -43,8 +64,10 @@ export function getGlobal(): typeof global
export function getUndefined(): void export function getUndefined(): void
export function getNull(): JsNull export function getNull(): JsNull
export function asyncPlus100(p: Promise<number>): Promise<number> export function asyncPlus100(p: Promise<number>): Promise<number>
interface PackageJson { /** This is an interface for package.json */
export interface PackageJson {
name: string name: string
/** The version of the package */
version: string version: string
dependencies?: Record<string, any> | undefined | null dependencies?: Record<string, any> | undefined | null
devDependencies?: Record<string, any> | undefined | null devDependencies?: Record<string, any> | undefined | null
@ -63,22 +86,34 @@ export function callThreadsafeFunction(callback: (...args: any[]) => any): void
export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void export function threadsafeFunctionThrowError(cb: (...args: any[]) => any): void
export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void export function threadsafeFunctionFatalMode(cb: (...args: any[]) => any): void
export function getBuffer(): Buffer export function getBuffer(): Buffer
/**
* `constructor` option for `struct` requires all fields to be public,
* otherwise tag impl fn as constructor
* #[napi(constructor)]
*/
export class Animal { export class Animal {
/** Kind of animal */
readonly kind: Kind readonly kind: Kind
/** This is the constructor */
constructor(kind: Kind, name: string) constructor(kind: Kind, name: string)
/** This is a factory method */
static withKind(kind: Kind): Animal static withKind(kind: Kind): Animal
get name(): string get name(): string
set name(name: string) set name(name: string)
/**
* This is a
* multi-line comment
* with an emoji 🚀
*/
whoami(): string whoami(): string
/** This is static... */
static getDogKind(): Kind static getDogKind(): Kind
} }
/** Smoking test for type generation */
export class Blake2BHasher { export class Blake2BHasher {
static withKey(key: Blake2bKey): Blake2BHasher static withKey(key: Blake2bKey): Blake2BHasher
} }
export class Blake2BKey { export class Blake2BKey { }
}
export class Context { export class Context {
maybeNeed?: boolean | undefined | null maybeNeed?: boolean | undefined | null
constructor() constructor()
@ -93,17 +128,17 @@ export class ClassWithFactory {
export namespace xxh3 { export namespace xxh3 {
export const ALIGNMENT: number export const ALIGNMENT: number
export function xxh3_64(input: Buffer): BigInt export function xxh3_64(input: Buffer): BigInt
/** xxh128 function */
export function xxh128(input: Buffer): BigInt export function xxh128(input: Buffer): BigInt
/** Xxh3 class */
export class Xxh3 { export class Xxh3 {
constructor() constructor()
/** update */
update(input: Buffer): void update(input: Buffer): void
digest(): BigInt digest(): BigInt
} }
} }
export namespace xxh2 { export namespace xxh2 {
export function xxh2Plus(a: number, b: number): number export function xxh2Plus(a: number, b: number): number
export function xxh3Xxh64Alias(input: Buffer): BigInt export function xxh3Xxh64Alias(input: Buffer): BigInt
} }

View file

@ -4,6 +4,7 @@ fn get_words() -> Vec<&'static str> {
} }
#[napi] #[napi]
/// Gets some numbers
fn get_nums() -> Vec<u32> { fn get_nums() -> Vec<u32> {
vec![1, 1, 2, 3, 5, 8] vec![1, 1, 2, 3, 5, 8]
} }

View file

@ -8,17 +8,21 @@ use crate::r#enum::Kind;
#[napi] #[napi]
pub struct Animal { pub struct Animal {
#[napi(readonly)] #[napi(readonly)]
/// Kind of animal
pub kind: Kind, pub kind: Kind,
name: String, name: String,
} }
#[napi] #[napi]
impl Animal { impl Animal {
/// This is the constructor
#[napi(constructor)] #[napi(constructor)]
pub fn new(kind: Kind, name: String) -> Self { pub fn new(kind: Kind, name: String) -> Self {
Animal { kind, name } Animal { kind, name }
} }
/// This is a factory method
#[napi(factory)] #[napi(factory)]
pub fn with_kind(kind: Kind) -> Self { pub fn with_kind(kind: Kind) -> Self {
Animal { Animal {
@ -37,6 +41,9 @@ impl Animal {
self.name = name; self.name = name;
} }
/// This is a
/// multi-line comment
/// with an emoji 🚀
#[napi] #[napi]
pub fn whoami(&self) -> String { pub fn whoami(&self) -> String {
match self.kind { match self.kind {
@ -49,6 +56,7 @@ impl Animal {
} }
#[napi] #[napi]
/// This is static...
pub fn get_dog_kind() -> Kind { pub fn get_dog_kind() -> Kind {
Kind::Dog Kind::Dog
} }

View file

@ -3,8 +3,11 @@ use napi::bindgen_prelude::*;
/// default enum values are continuos i32s start from 0 /// default enum values are continuos i32s start from 0
#[napi] #[napi]
pub enum Kind { pub enum Kind {
/// Barks
Dog, Dog,
/// Kills birds
Cat, Cat,
/// Tasty
Duck, Duck,
} }

View file

@ -15,6 +15,7 @@ mod xxh3 {
} }
#[napi] #[napi]
/// xxh128 function
pub fn xxh128(input: Buffer) -> u128 { pub fn xxh128(input: Buffer) -> u128 {
let mut h: u128 = 0; let mut h: u128 = 0;
for i in input.as_ref() { for i in input.as_ref() {
@ -24,6 +25,7 @@ mod xxh3 {
} }
#[napi] #[napi]
/// Xxh3 class
pub struct Xxh3 { pub struct Xxh3 {
inner: BigInt, inner: BigInt,
} }
@ -41,6 +43,7 @@ mod xxh3 {
} }
#[napi] #[napi]
/// update
pub fn update(&mut self, input: Buffer) { pub fn update(&mut self, input: Buffer) {
for i in input.as_ref() { for i in input.as_ref() {
self.inner = BigInt { self.inner = BigInt {

View file

@ -4,6 +4,7 @@ extern crate napi_derive;
extern crate serde_derive; extern crate serde_derive;
#[napi] #[napi]
/// This is a const
pub const DEFAULT_COST: u32 = 12; pub const DEFAULT_COST: u32 = 12;
mod array; mod array;

View file

@ -4,8 +4,10 @@ use std::fs;
#[napi(object)] #[napi(object)]
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
/// This is an interface for package.json
struct PackageJson { struct PackageJson {
pub name: String, pub name: String,
/// The version of the package
pub version: String, pub version: String,
pub dependencies: Option<Map<String, Value>>, pub dependencies: Option<Map<String, Value>>,
#[serde(rename = "devDependencies")] #[serde(rename = "devDependencies")]