Skip to content

Commit

Permalink
feat: support expando properties (#575)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored May 13, 2024
1 parent 3fbaf0f commit cddfff0
Show file tree
Hide file tree
Showing 10 changed files with 440 additions and 140 deletions.
13 changes: 7 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repository = "https://github.com/denoland/deno_doc"
members = ["lib"]

[workspace.dependencies]
deno_graph = { version = "0.74.0", default-features = false, features = ["symbols"] }
deno_graph = { version = "0.75.1", default-features = false, features = ["symbols"] }
import_map = "0.19.0"
serde = { version = "1.0.140", features = ["derive"] }

Expand Down Expand Up @@ -67,7 +67,7 @@ anyhow = { version = "1.0.58" }
clap = "2.33.3"
console_static_text = "0.8.2"
criterion = { version = "0.4.0", features = ["async_futures", "html_reports"] }
file_test_runner = "0.2.0"
file_test_runner = "0.7.0"
tokio = { version = "1.25.0", features = ["full"] }
pretty_assertions = "1.0.0"
insta = "1.38.0"
Expand Down
123 changes: 110 additions & 13 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::node::DeclarationKind;
use crate::node::DocNode;
use crate::node::ModuleDoc;
use crate::node::NamespaceDef;
use crate::ts_type::infer_simple_ts_type_from_init;
use crate::ts_type::PropertyDef;
use crate::ts_type::TsTypeDef;
use crate::ts_type::TsTypeDefKind;
Expand Down Expand Up @@ -48,8 +49,10 @@ use deno_ast::swc::ast::VarDeclKind;
use deno_ast::swc::ast::VarDeclarator;
use deno_ast::ParsedSource;
use deno_ast::SourceRange;
use deno_ast::SourceRanged;
use deno_ast::SourceRangedForSpanned;
use deno_graph::symbols::EsModuleInfo;
use deno_graph::symbols::ExpandoPropertyRef;
use deno_graph::symbols::ExportDeclRef;
use deno_graph::symbols::ModuleInfoRef;
use deno_graph::symbols::Symbol;
Expand Down Expand Up @@ -281,12 +284,12 @@ impl<'a> DocParser<'a> {
if first_def.module.specifier() != module_info.specifier() {
for definition in definitions {
let decl = definition.symbol_decl;
let maybe_doc = self.doc_for_maybe_node(
let maybe_docs = self.docs_for_maybe_node(
definition.module,
definition.symbol,
decl.maybe_node(),
);
if let Some(mut doc_node) = maybe_doc {
for mut doc_node in maybe_docs {
doc_node.name = export_name.clone();
doc_node.declaration_kind = DeclarationKind::Export;

Expand Down Expand Up @@ -370,6 +373,32 @@ impl<'a> DocParser<'a> {
Ok(imports)
}

fn get_doc_for_expando_property(
&self,
source: &ParsedSource,
expando_property: ExpandoPropertyRef,
) -> Option<DocNode> {
let location =
get_location(source, expando_property.prop_name_range().start());
let ts_type = infer_simple_ts_type_from_init(
source,
Some(expando_property.assignment()),
/* is const */ true,
);
let js_doc = js_doc_for_range(source, &expando_property.inner().range())?;

Some(DocNode::variable(
expando_property.prop_name().to_string(),
location,
DeclarationKind::Declare,
js_doc,
VariableDef {
ts_type,
kind: VarDeclKind::Const,
},
))
}

fn get_doc_for_var_declarator_ident(
&self,
module_info: &EsModuleInfo,
Expand Down Expand Up @@ -565,12 +594,12 @@ impl<'a> DocParser<'a> {
continue;
}

let maybe_doc = self.doc_for_maybe_node(
let maybe_docs = self.docs_for_maybe_node(
definition.module,
definition.symbol,
definition.symbol_decl.maybe_node(),
);
if let Some(mut doc_node) = maybe_doc {
for mut doc_node in maybe_docs {
doc_node.name = export_name.to_string();
doc_node.declaration_kind = DeclarationKind::Export;

Expand Down Expand Up @@ -624,9 +653,9 @@ impl<'a> DocParser<'a> {
.is_none());
let mut doc_nodes = Vec::with_capacity(child_symbol.decls().len());
for decl in child_symbol.decls() {
if let Some(mut doc_node) =
self.doc_for_maybe_node(module_info, child_symbol, decl.maybe_node())
{
let maybe_docs =
self.docs_for_maybe_node(module_info, child_symbol, decl.maybe_node());
for mut doc_node in maybe_docs {
let is_declared = decl
.maybe_node()
.map(|node| self.get_declare_for_symbol_node(node))
Expand Down Expand Up @@ -966,12 +995,12 @@ impl<'a> DocParser<'a> {
continue;
}
handled_symbols.insert(definition.symbol.unique_id());
let maybe_doc = self.doc_for_maybe_node(
let maybe_docs = self.docs_for_maybe_node(
definition.module,
definition.symbol,
definition.symbol_decl.maybe_node(),
);
if let Some(mut doc_node) = maybe_doc {
for mut doc_node in maybe_docs {
doc_node.name = export_name.clone();
doc_node.declaration_kind = DeclarationKind::Export;

Expand Down Expand Up @@ -1002,12 +1031,13 @@ impl<'a> DocParser<'a> {
doc_nodes
}

fn doc_for_maybe_node(
fn docs_for_maybe_node(
&self,
module_info: ModuleInfoRef,
symbol: &Symbol,
maybe_node: Option<SymbolNodeRef<'_>>,
) -> Option<DocNode> {
) -> Vec<DocNode> {
let mut docs = Vec::with_capacity(2);
let maybe_doc = match module_info {
ModuleInfoRef::Json(module_info) => parse_json_module_doc_node(
module_info.specifier(),
Expand All @@ -1022,11 +1052,74 @@ impl<'a> DocParser<'a> {
}
};

if maybe_doc.is_some() {
if let Some(doc) = maybe_doc {
docs.push(doc);

self.check_private_type_in_public_diagnostic(module_info, symbol);

if let Some(node) = maybe_node {
if node.is_function() {
// find any expando properties for this function symbol
if let Some(expando_namespace) = self
.maybe_expando_property_namespace_doc(&docs[0], module_info, symbol)
{
docs.push(expando_namespace);
}
}
}
}

maybe_doc
docs
}

fn maybe_expando_property_namespace_doc(
&self,
func_doc: &DocNode,
module_info: ModuleInfoRef,
symbol: &Symbol,
) -> Option<DocNode> {
let expando_properties = symbol.exports().iter().flat_map(|(name, id)| {
let symbol = module_info.symbol(*id).unwrap();
symbol
.decls()
.iter()
.filter_map(move |n| match n.maybe_node() {
Some(SymbolNodeRef::ExpandoProperty(n)) => Some((name, n)),
_ => None,
})
});
let elements = expando_properties
.flat_map(|(name, n)| {
let mut docs = self.docs_for_maybe_node(
module_info,
symbol,
Some(SymbolNodeRef::ExpandoProperty(n)),
);
for doc in &mut docs {
doc.name = name.clone();
doc.declaration_kind = DeclarationKind::Declare;
}
docs
})
.map(Arc::new)
.collect::<Vec<_>>();
if elements.is_empty() {
return None;
}
Some(DocNode::namespace(
func_doc.name.clone(),
elements[0].location.clone(),
DeclarationKind::Declare,
// give this a JS doc to prevent a missing JS doc diagnostic
JsDoc {
doc: Some(format!(
"Additional properties on the `{}` function.",
func_doc.name
)),
tags: vec![],
},
NamespaceDef { elements },
))
}

fn check_private_type_in_public_diagnostic(
Expand Down Expand Up @@ -1092,6 +1185,9 @@ impl<'a> DocParser<'a> {
SymbolNodeRef::ClassDecl(n) => {
self.get_doc_for_class_decl(parsed_source, n, &n.class.range())
}
SymbolNodeRef::ExpandoProperty(n) => {
self.get_doc_for_expando_property(parsed_source, n)
}
SymbolNodeRef::ExportDefaultDecl(n) => {
self.get_doc_for_export_default_decl(parsed_source, n)
}
Expand Down Expand Up @@ -1195,6 +1291,7 @@ impl<'a> DocParser<'a> {
| SymbolNodeRef::ClassMethod(_)
| SymbolNodeRef::ClassProp(_)
| SymbolNodeRef::ClassParamProp(_)
| SymbolNodeRef::ExpandoProperty(_)
| SymbolNodeRef::Constructor(_)
| SymbolNodeRef::TsIndexSignature(_)
| SymbolNodeRef::TsCallSignatureDecl(_)
Expand Down
8 changes: 4 additions & 4 deletions src/ts_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1597,13 +1597,13 @@ pub fn infer_ts_type_from_expr(
}
}

pub fn infer_simple_ts_type_from_var_decl(
pub fn infer_simple_ts_type_from_init(
parsed_source: &ParsedSource,
decl: &VarDeclarator,
init: Option<&Expr>,
is_const: bool,
) -> Option<TsTypeDef> {
if let Some(init_expr) = &decl.init {
infer_ts_type_from_expr(parsed_source, init_expr.as_ref(), is_const)
if let Some(init_expr) = init {
infer_ts_type_from_expr(parsed_source, init_expr, is_const)
} else {
None
}
Expand Down
1 change: 1 addition & 0 deletions src/ts_type_param.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use crate::ts_type::TsTypeDef;
use deno_ast::swc::ast::TsTypeParam;
use deno_ast::swc::ast::TsTypeParamDecl;
Expand Down
10 changes: 5 additions & 5 deletions src/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use deno_graph::symbols::SymbolNodeRef;
use serde::Deserialize;
use serde::Serialize;

use crate::ts_type::infer_simple_ts_type_from_var_decl;
use crate::ts_type::infer_simple_ts_type_from_init;
use crate::ts_type::TsTypeDef;
use crate::ts_type::TsTypeDefKind;

Expand Down Expand Up @@ -60,9 +60,9 @@ pub fn get_docs_for_var_declarator(
}
}
}
let maybe_type_ann = infer_simple_ts_type_from_var_decl(
let maybe_type_ann = infer_simple_ts_type_from_init(
module_info.source(),
var_declarator,
var_declarator.init.as_deref(),
var_decl.kind == VarDeclKind::Const,
);
if let Some(type_ann) = maybe_type_ann {
Expand All @@ -76,9 +76,9 @@ pub fn get_docs_for_var_declarator(
}
})
.or_else(|| {
infer_simple_ts_type_from_var_decl(
infer_simple_ts_type_from_init(
module_info.source(),
var_declarator,
var_declarator.init.as_deref(),
var_decl.kind == VarDeclKind::Const,
)
});
Expand Down
2 changes: 2 additions & 0 deletions tests/html_test.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

use deno_ast::ModuleSpecifier;
use deno_doc::html::pages::SymbolPage;
use deno_doc::html::*;
Expand Down
Loading

0 comments on commit cddfff0

Please sign in to comment.