Skip to content

Commit

Permalink
Add skip_typescript attribute to prevent .d.ts emit (#2016)
Browse files Browse the repository at this point in the history
* Add skip_typescript attribute to prevent .d.ts emit

* Add guide page for typescript attribute
  • Loading branch information
joeywatts committed Mar 3, 2020
1 parent 3f4acc4 commit 7ffb5ed
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 56 deletions.
4 changes: 4 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ pub struct Function {
pub rust_attrs: Vec<syn::Attribute>,
pub rust_vis: syn::Visibility,
pub r#async: bool,
pub generate_typescript: bool,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
Expand All @@ -231,6 +232,7 @@ pub struct Struct {
pub fields: Vec<StructField>,
pub comments: Vec<String>,
pub is_inspectable: bool,
pub generate_typescript: bool,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
Expand All @@ -243,6 +245,7 @@ pub struct StructField {
pub getter: Ident,
pub setter: Ident,
pub comments: Vec<String>,
pub generate_typescript: bool,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
Expand All @@ -252,6 +255,7 @@ pub struct Enum {
pub variants: Vec<Variant>,
pub comments: Vec<String>,
pub hole: u32,
pub generate_typescript: bool,
}

#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
Expand Down
4 changes: 4 additions & 0 deletions crates/backend/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ fn shared_function<'a>(func: &'a ast::Function, _intern: &'a Interner) -> Functi
Function {
arg_names,
name: &func.name,
generate_typescript: func.generate_typescript,
}
}

Expand All @@ -218,6 +219,7 @@ fn shared_enum<'a>(e: &'a ast::Enum, intern: &'a Interner) -> Enum<'a> {
.map(|v| shared_variant(v, intern))
.collect(),
comments: e.comments.iter().map(|s| &**s).collect(),
generate_typescript: e.generate_typescript,
}
}

Expand Down Expand Up @@ -307,6 +309,7 @@ fn shared_struct<'a>(s: &'a ast::Struct, intern: &'a Interner) -> Struct<'a> {
.collect(),
comments: s.comments.iter().map(|s| &**s).collect(),
is_inspectable: s.is_inspectable,
generate_typescript: s.generate_typescript,
}
}

Expand All @@ -318,6 +321,7 @@ fn shared_struct_field<'a>(s: &'a ast::StructField, intern: &'a Interner) -> Str
},
readonly: s.readonly,
comments: s.comments.iter().map(|s| &**s).collect(),
generate_typescript: s.generate_typescript,
}
}

Expand Down
130 changes: 82 additions & 48 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,16 @@ impl<'a> Context<'a> {
&mut self,
export_name: &str,
contents: &str,
comments: Option<String>,
comments: Option<&str>,
) -> Result<(), Error> {
let definition_name = generate_identifier(export_name, &mut self.defined_identifiers);
if contents.starts_with("class") && definition_name != export_name {
bail!("cannot shadow already defined class `{}`", export_name);
}

let contents = contents.trim();
if let Some(ref c) = comments {
if let Some(c) = comments {
self.globals.push_str(c);
self.typescript.push_str(c);
}
let global = match self.config.mode {
OutputMode::Node {
Expand Down Expand Up @@ -804,7 +803,7 @@ impl<'a> Context<'a> {
dst.push_str("}\n");
ts_dst.push_str("}\n");

self.export(&name, &dst, Some(class.comments.clone()))?;
self.export(&name, &dst, Some(&class.comments))?;
self.typescript.push_str(&ts_dst);

Ok(())
Expand Down Expand Up @@ -2153,41 +2152,58 @@ impl<'a> Context<'a> {
// on what's being exported.
match kind {
Kind::Export(export) => {
let ts_sig = match export.generate_typescript {
true => Some(ts_sig.as_str()),
false => None,
};

let docs = format_doc_comments(&export.comments, Some(js_doc));
match &export.kind {
AuxExportKind::Function(name) => {
self.export(&name, &format!("function{}", code), Some(docs))?;
if let Some(ts_sig) = ts_sig {
self.typescript.push_str(&docs);
self.typescript.push_str("export function ");
self.typescript.push_str(&name);
self.typescript.push_str(ts_sig);
self.typescript.push_str(";\n");
}
self.export(&name, &format!("function{}", code), Some(&docs))?;
self.globals.push_str("\n");
self.typescript.push_str("export function ");
self.typescript.push_str(&name);
self.typescript.push_str(&ts_sig);
self.typescript.push_str(";\n");
}
AuxExportKind::Constructor(class) => {
let exported = require_class(&mut self.exported_classes, class);
if exported.has_constructor {
bail!("found duplicate constructor for class `{}`", class);
}
exported.has_constructor = true;
exported.push(&docs, "constructor", "", &code, &ts_sig);
exported.push(&docs, "constructor", "", &code, ts_sig);
}
AuxExportKind::Getter { class, field } => {
let ret_ty = ts_ret_ty.unwrap();
let ret_ty = match export.generate_typescript {
true => match &ts_ret_ty {
Some(s) => Some(s.as_str()),
_ => None,
},
false => None,
};
let exported = require_class(&mut self.exported_classes, class);
exported.push_getter(&docs, field, &code, &ret_ty);
exported.push_getter(&docs, field, &code, ret_ty);
}
AuxExportKind::Setter { class, field } => {
let arg_ty = ts_arg_tys[0].clone();
let arg_ty = match export.generate_typescript {
true => Some(ts_arg_tys[0].as_str()),
false => None,
};
let exported = require_class(&mut self.exported_classes, class);
exported.push_setter(&docs, field, &code, &arg_ty, might_be_optional_field);
exported.push_setter(&docs, field, &code, arg_ty, might_be_optional_field);
}
AuxExportKind::StaticFunction { class, name } => {
let exported = require_class(&mut self.exported_classes, class);
exported.push(&docs, name, "static ", &code, &ts_sig);
exported.push(&docs, name, "static ", &code, ts_sig);
}
AuxExportKind::Method { class, name, .. } => {
let exported = require_class(&mut self.exported_classes, class);
exported.push(&docs, name, "", &code, &ts_sig);
exported.push(&docs, name, "", &code, ts_sig);
}
}
}
Expand Down Expand Up @@ -2865,19 +2881,27 @@ impl<'a> Context<'a> {
}

fn generate_enum(&mut self, enum_: &AuxEnum) -> Result<(), Error> {
let docs = format_doc_comments(&enum_.comments, None);
let mut variants = String::new();

self.typescript
.push_str(&format!("export enum {} {{", enum_.name));
if enum_.generate_typescript {
self.typescript.push_str(&docs);
self.typescript
.push_str(&format!("export enum {} {{", enum_.name));
}
for (name, value) in enum_.variants.iter() {
variants.push_str(&format!("{}:{},", name, value));
self.typescript.push_str(&format!("\n {},", name));
if enum_.generate_typescript {
self.typescript.push_str(&format!("\n {},", name));
}
}
if enum_.generate_typescript {
self.typescript.push_str("\n}\n");
}
self.typescript.push_str("\n}\n");
self.export(
&enum_.name,
&format!("Object.freeze({{ {} }})", variants),
Some(format_doc_comments(&enum_.comments, None)),
Some(&docs),
)?;

Ok(())
Expand Down Expand Up @@ -3163,24 +3187,36 @@ fn require_class<'a>(
}

impl ExportedClass {
fn push(&mut self, docs: &str, function_name: &str, function_prefix: &str, js: &str, ts: &str) {
fn push(
&mut self,
docs: &str,
function_name: &str,
function_prefix: &str,
js: &str,
ts: Option<&str>,
) {
self.contents.push_str(docs);
self.contents.push_str(function_prefix);
self.contents.push_str(function_name);
self.contents.push_str(js);
self.contents.push_str("\n");
self.typescript.push_str(docs);
self.typescript.push_str(" ");
self.typescript.push_str(function_prefix);
self.typescript.push_str(function_name);
self.typescript.push_str(ts);
self.typescript.push_str(";\n");
if let Some(ts) = ts {
self.typescript.push_str(docs);
self.typescript.push_str(" ");
self.typescript.push_str(function_prefix);
self.typescript.push_str(function_name);
self.typescript.push_str(ts);
self.typescript.push_str(";\n");
}
}

/// Used for adding a getter to a class, mainly to ensure that TypeScript
/// generation is handled specially.
fn push_getter(&mut self, docs: &str, field: &str, js: &str, ret_ty: &str) {
self.push_accessor(docs, field, js, "get ", ret_ty);
fn push_getter(&mut self, docs: &str, field: &str, js: &str, ret_ty: Option<&str>) {
self.push_accessor(docs, field, js, "get ");
if let Some(ret_ty) = ret_ty {
self.push_accessor_ts(field, ret_ty);
}
self.readable_properties.push(field.to_string());
}

Expand All @@ -3191,28 +3227,18 @@ impl ExportedClass {
docs: &str,
field: &str,
js: &str,
ret_ty: &str,
ret_ty: Option<&str>,
might_be_optional_field: bool,
) {
let (has_setter, is_optional) = self.push_accessor(docs, field, js, "set ", ret_ty);
*has_setter = true;
*is_optional = might_be_optional_field;
self.push_accessor(docs, field, js, "set ");
if let Some(ret_ty) = ret_ty {
let (has_setter, is_optional) = self.push_accessor_ts(field, ret_ty);
*has_setter = true;
*is_optional = might_be_optional_field;
}
}

fn push_accessor(
&mut self,
docs: &str,
field: &str,
js: &str,
prefix: &str,
ret_ty: &str,
) -> (&mut bool, &mut bool) {
self.contents.push_str(docs);
self.contents.push_str(prefix);
self.contents.push_str(field);
self.contents.push_str(js);
self.contents.push_str("\n");

fn push_accessor_ts(&mut self, field: &str, ret_ty: &str) -> (&mut bool, &mut bool) {
let (ty, has_setter, is_optional) = self
.typescript_fields
.entry(field.to_string())
Expand All @@ -3221,6 +3247,14 @@ impl ExportedClass {
*ty = ret_ty.to_string();
(has_setter, is_optional)
}

fn push_accessor(&mut self, docs: &str, field: &str, js: &str, prefix: &str) {
self.contents.push_str(docs);
self.contents.push_str(prefix);
self.contents.push_str(field);
self.contents.push_str(js);
self.contents.push_str("\n");
}
}

#[test]
Expand Down
6 changes: 6 additions & 0 deletions crates/cli-support/src/wit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ impl<'a> Context<'a> {
comments: concatenate_comments(&export.comments),
arg_names: Some(export.function.arg_names),
kind,
generate_typescript: export.function.generate_typescript,
},
);
Ok(())
Expand Down Expand Up @@ -767,6 +768,7 @@ impl<'a> Context<'a> {
.iter()
.map(|v| (v.name.to_string(), v.value))
.collect(),
generate_typescript: enum_.generate_typescript,
};
self.aux.enums.push(aux);
Ok(())
Expand Down Expand Up @@ -799,6 +801,7 @@ impl<'a> Context<'a> {
class: struct_.name.to_string(),
field: field.name.to_string(),
},
generate_typescript: field.generate_typescript,
},
);

Expand All @@ -824,13 +827,15 @@ impl<'a> Context<'a> {
class: struct_.name.to_string(),
field: field.name.to_string(),
},
generate_typescript: field.generate_typescript,
},
);
}
let aux = AuxStruct {
name: struct_.name.to_string(),
comments: concatenate_comments(&struct_.comments),
is_inspectable: struct_.is_inspectable,
generate_typescript: struct_.generate_typescript,
};
self.aux.structs.push(aux);

Expand Down Expand Up @@ -1048,6 +1053,7 @@ impl<'a> Context<'a> {
comments: String::new(),
arg_names: None,
kind,
generate_typescript: true,
};
assert!(self.aux.export_map.insert(id, export).is_none());
}
Expand Down
7 changes: 7 additions & 0 deletions crates/cli-support/src/wit/nonstandard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub struct AuxExport {
pub arg_names: Option<Vec<String>>,
/// What kind of function this is and where it shows up
pub kind: AuxExportKind,
/// Whether typescript bindings should be generated for this export.
pub generate_typescript: bool,
}

/// All possible kinds of exports from a wasm module.
Expand Down Expand Up @@ -131,7 +133,10 @@ pub struct AuxEnum {
/// The copied Rust comments to forward to JS
pub comments: String,
/// A list of variants with their name and value
/// and whether typescript bindings should be generated for each variant
pub variants: Vec<(String, u32)>,
/// Whether typescript bindings should be generated for this enum.
pub generate_typescript: bool,
}

#[derive(Debug)]
Expand All @@ -142,6 +147,8 @@ pub struct AuxStruct {
pub comments: String,
/// Whether to generate helper methods for inspecting the class
pub is_inspectable: bool,
/// Whether typescript bindings should be generated for this struct.
pub generate_typescript: bool,
}

/// All possible types of imports that can be imported by a wasm module.
Expand Down
Loading

0 comments on commit 7ffb5ed

Please sign in to comment.