diff --git a/src/html/symbols/function.rs b/src/html/symbols/function.rs
index 00c00e9c8..eda9ca8e8 100644
--- a/src/html/symbols/function.rs
+++ b/src/html/symbols/function.rs
@@ -297,13 +297,17 @@ fn render_single_function(
.enumerate()
.map(|(i, param)| {
let (name, str_name) = crate::html::parameters::param_name(param, i);
+ // `@param` tag names are bare identifiers, but the rendered name of a
+ // rest parameter carries a `...` prefix (e.g. `...rest`). Strip it so the
+ // doc lookup matches the tag (see issue #574).
+ let lookup_name = str_name.trim_start_matches('.');
let id = IdBuilder::new_with_parent(ctx, &overload_id)
.kind(IdKind::Parameter)
.name(&str_name)
.build();
let (mut default, optional) = if let Some((_doc, optional, default)) =
- param_docs.get(name.as_str())
+ param_docs.get(lookup_name)
{
((**default).to_owned(), *optional)
} else {
@@ -342,7 +346,7 @@ fn render_single_function(
};
let param_doc = param_docs
- .get(name.as_str())
+ .get(lookup_name)
.and_then(|(doc, _, _)| doc.as_deref());
let (diff_status, old_content) =
diff --git a/tests/html_test.rs b/tests/html_test.rs
index 0b90708bf..893a36394 100644
--- a/tests/html_test.rs
+++ b/tests/html_test.rs
@@ -761,6 +761,64 @@ export class Foo {
);
}
+// Regression test for https://github.com/denoland/deno_doc/issues/574:
+// `@param` documentation must render for rest/spread parameters. The rendered
+// parameter name carries a `...` prefix, but the JSDoc `@param` tag name does
+// not, so the doc lookup has to match on the bare identifier.
+#[tokio::test]
+async fn html_rest_param_jsdoc() {
+ let source = r#"
+/**
+ * Sums numbers.
+ *
+ * @param first the leading number
+ * @param rest the trailing numbers
+ */
+export function sum(first: number, ...rest: number[]): number {
+ return first + rest.reduce((a, b) => a + b, 0);
+}
+"#;
+
+ let ctx = GenerateCtx::create_basic(
+ GenerateOptions {
+ package_name: None,
+ main_entrypoint: None,
+ href_resolver: Arc::new(EmptyResolver),
+ usage_composer: Some(Arc::new(EmptyResolver)),
+ rewrite_map: None,
+ category_docs: None,
+ disable_search: false,
+ symbol_redirect_map: None,
+ default_symbol_map: None,
+ markdown_renderer: comrak::create_renderer(None, None, None),
+ markdown_stripper: Arc::new(comrak::strip),
+ head_inject: None,
+ id_prefix: None,
+ diff_only: false,
+ },
+ parse_source(source).await,
+ None,
+ )
+ .unwrap();
+
+ let files = generate(ctx).unwrap();
+
+ let sum_page = files
+ .get("./~/sum.html")
+ .expect("function symbol page should be generated");
+
+ // The non-rest parameter has always rendered its doc.
+ assert!(
+ sum_page.contains("the leading number"),
+ "expected the first parameter's @param doc to render"
+ );
+ // The rest parameter's @param doc must render too (the bug in #574).
+ assert!(
+ sum_page.contains("the trailing numbers"),
+ "expected the rest parameter's @param doc to render"
+ );
+}
+
#[tokio::test]
async fn diff_kind_change() {
let test_dir = std::env::current_dir()
diff --git a/tests/snapshots/html_test__diff_comprehensive_diff_only.snap b/tests/snapshots/html_test__diff_comprehensive_diff_only.snap
index 1c9788f43..c2c6c3a95 100644
--- a/tests/snapshots/html_test__diff_comprehensive_diff_only.snap
+++ b/tests/snapshots/html_test__diff_comprehensive_diff_only.snap
@@ -249,7 +249,7 @@ expression: pages
],
[
"./~/createPipeline.json",
- "{\"kind\":\"SymbolPageCtx\",\"html_head_ctx\":{\"title\":\"createPipeline - default - documentation\",\"current_file\":\".\",\"stylesheet_url\":\"../styles.css\",\"page_stylesheet_url\":\"../page.css\",\"reset_stylesheet_url\":\"../reset.css\",\"url_search_index\":\"../search_index.js\",\"script_js\":\"../script.js\",\"fuse_js\":\"../fuse.js\",\"search_js\":\"../search.js\",\"darkmode_toggle_js\":\"../darkmode_toggle.js\",\"head_inject\":null,\"disable_search\":false},\"symbol_group_ctx\":{\"name\":\"createPipeline\",\"symbols\":[{\"kind\":{\"kind\":\"Function\",\"char\":\"f\",\"title\":\"Function\",\"title_lowercase\":\"function\",\"title_plural\":\"Functions\"},\"usage\":null,\"tags\":[],\"subtitle\":null,\"content\":[{\"kind\":\"function\",\"value\":{\"functions\":[{\"anchor\":{\"id\":\"function_createpipeline_0\"},\"name\":\"createPipeline\",\"summary\":\"(...middlewares: Middleware[]): Middleware\",\"deprecated\":null,\"content\":{\"id\":\"\",\"docs\":\"
Create middleware pipeline.
\\n
\",\"sections\":[{\"header\":{\"title\":\"Parameters\",\"anchor\":{\"id\":\"parameters\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":\"...middlewares\",\"name_href\":null,\"content\":\": Middleware[]\",\"anchor\":{\"id\":\"function_createpipeline_0_parameter____middlewares\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}},{\"header\":{\"title\":\"Return Type\",\"anchor\":{\"id\":\"return-type\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":null,\"name_href\":null,\"content\":\"Middleware\",\"anchor\":{\"id\":\"function_createpipeline_0_return\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}}]}}]}}],\"deprecated\":null,\"source_href\":null}],\"diff_status\":{\"kind\":\"added\"}},\"breadcrumbs_ctx\":{\"root\":{\"name\":\"index\",\"href\":\"../\"},\"current_entrypoint\":{\"name\":\"default\",\"href\":\"../\"},\"entrypoints\":[{\"name\":\"all symbols\",\"href\":\".././all_symbols.html\"},{\"name\":\"default\",\"href\":\"../\"}],\"symbol\":[{\"name\":\"createPipeline\",\"href\":\"../././~/createPipeline.html\"}]},\"toc_ctx\":{\"usages\":{\"usages\":[{\"name\":\"\",\"content\":\"import { createPipeline } from ".";\\n
\\n
\",\"icon\":null,\"additional_css\":\"\"}],\"composed\":false},\"top_symbols\":null,\"document_navigation_str\":\"\",\"document_navigation\":[{\"level\":1,\"content\":\"Parameters\",\"anchor\":\"parameters\"},{\"level\":2,\"content\":\"...middlewares\",\"anchor\":\"function_createpipeline_0_parameter____middlewares\"},{\"level\":1,\"content\":\"Return Type\",\"anchor\":\"return-type\"}]},\"disable_search\":false,\"categories_panel\":null}"
+ "{\"kind\":\"SymbolPageCtx\",\"html_head_ctx\":{\"title\":\"createPipeline - default - documentation\",\"current_file\":\".\",\"stylesheet_url\":\"../styles.css\",\"page_stylesheet_url\":\"../page.css\",\"reset_stylesheet_url\":\"../reset.css\",\"url_search_index\":\"../search_index.js\",\"script_js\":\"../script.js\",\"fuse_js\":\"../fuse.js\",\"search_js\":\"../search.js\",\"darkmode_toggle_js\":\"../darkmode_toggle.js\",\"head_inject\":null,\"disable_search\":false},\"symbol_group_ctx\":{\"name\":\"createPipeline\",\"symbols\":[{\"kind\":{\"kind\":\"Function\",\"char\":\"f\",\"title\":\"Function\",\"title_lowercase\":\"function\",\"title_plural\":\"Functions\"},\"usage\":null,\"tags\":[],\"subtitle\":null,\"content\":[{\"kind\":\"function\",\"value\":{\"functions\":[{\"anchor\":{\"id\":\"function_createpipeline_0\"},\"name\":\"createPipeline\",\"summary\":\"(...middlewares: Middleware[]): Middleware\",\"deprecated\":null,\"content\":{\"id\":\"\",\"docs\":\"Create middleware pipeline.
\\n
\",\"sections\":[{\"header\":{\"title\":\"Parameters\",\"anchor\":{\"id\":\"parameters\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":\"...middlewares\",\"name_href\":null,\"content\":\": Middleware[]\",\"anchor\":{\"id\":\"function_createpipeline_0_parameter____middlewares\"},\"tags\":[],\"js_doc\":\"\",\"source_href\":null}]}},{\"header\":{\"title\":\"Return Type\",\"anchor\":{\"id\":\"return-type\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":null,\"name_href\":null,\"content\":\"Middleware\",\"anchor\":{\"id\":\"function_createpipeline_0_return\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}}]}}]}}],\"deprecated\":null,\"source_href\":null}],\"diff_status\":{\"kind\":\"added\"}},\"breadcrumbs_ctx\":{\"root\":{\"name\":\"index\",\"href\":\"../\"},\"current_entrypoint\":{\"name\":\"default\",\"href\":\"../\"},\"entrypoints\":[{\"name\":\"all symbols\",\"href\":\".././all_symbols.html\"},{\"name\":\"default\",\"href\":\"../\"}],\"symbol\":[{\"name\":\"createPipeline\",\"href\":\"../././~/createPipeline.html\"}]},\"toc_ctx\":{\"usages\":{\"usages\":[{\"name\":\"\",\"content\":\"import { createPipeline } from ".";\\n
\\n
\",\"icon\":null,\"additional_css\":\"\"}],\"composed\":false},\"top_symbols\":null,\"document_navigation_str\":\"\",\"document_navigation\":[{\"level\":1,\"content\":\"Parameters\",\"anchor\":\"parameters\"},{\"level\":2,\"content\":\"...middlewares\",\"anchor\":\"function_createpipeline_0_parameter____middlewares\"},{\"level\":1,\"content\":\"Return Type\",\"anchor\":\"return-type\"}]},\"disable_search\":false,\"categories_panel\":null}"
],
[
"./~/debugLog.json",
diff --git a/tests/snapshots/html_test__diff_comprehensive_full.snap b/tests/snapshots/html_test__diff_comprehensive_full.snap
index 6e761e3e2..d59c24154 100644
--- a/tests/snapshots/html_test__diff_comprehensive_full.snap
+++ b/tests/snapshots/html_test__diff_comprehensive_full.snap
@@ -273,7 +273,7 @@ expression: pages
],
[
"./~/createPipeline.json",
- "{\"kind\":\"SymbolPageCtx\",\"html_head_ctx\":{\"title\":\"createPipeline - default - documentation\",\"current_file\":\".\",\"stylesheet_url\":\"../styles.css\",\"page_stylesheet_url\":\"../page.css\",\"reset_stylesheet_url\":\"../reset.css\",\"url_search_index\":\"../search_index.js\",\"script_js\":\"../script.js\",\"fuse_js\":\"../fuse.js\",\"search_js\":\"../search.js\",\"darkmode_toggle_js\":\"../darkmode_toggle.js\",\"head_inject\":null,\"disable_search\":false},\"symbol_group_ctx\":{\"name\":\"createPipeline\",\"symbols\":[{\"kind\":{\"kind\":\"Function\",\"char\":\"f\",\"title\":\"Function\",\"title_lowercase\":\"function\",\"title_plural\":\"Functions\"},\"usage\":null,\"tags\":[],\"subtitle\":null,\"content\":[{\"kind\":\"function\",\"value\":{\"functions\":[{\"anchor\":{\"id\":\"function_createpipeline_0\"},\"name\":\"createPipeline\",\"summary\":\"(...middlewares: Middleware[]): Middleware\",\"deprecated\":null,\"content\":{\"id\":\"\",\"docs\":\"Create middleware pipeline.
\\n
\",\"sections\":[{\"header\":{\"title\":\"Parameters\",\"anchor\":{\"id\":\"parameters\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":\"...middlewares\",\"name_href\":null,\"content\":\": Middleware[]\",\"anchor\":{\"id\":\"function_createpipeline_0_parameter____middlewares\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}},{\"header\":{\"title\":\"Return Type\",\"anchor\":{\"id\":\"return-type\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":null,\"name_href\":null,\"content\":\"Middleware\",\"anchor\":{\"id\":\"function_createpipeline_0_return\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}}]}}]}}],\"deprecated\":null,\"source_href\":null}],\"diff_status\":{\"kind\":\"added\"}},\"breadcrumbs_ctx\":{\"root\":{\"name\":\"index\",\"href\":\"../\"},\"current_entrypoint\":{\"name\":\"default\",\"href\":\"../\"},\"entrypoints\":[{\"name\":\"all symbols\",\"href\":\".././all_symbols.html\"},{\"name\":\"default\",\"href\":\"../\"}],\"symbol\":[{\"name\":\"createPipeline\",\"href\":\"../././~/createPipeline.html\"}]},\"toc_ctx\":{\"usages\":{\"usages\":[{\"name\":\"\",\"content\":\"import { createPipeline } from ".";\\n
\\n
\",\"icon\":null,\"additional_css\":\"\"}],\"composed\":false},\"top_symbols\":null,\"document_navigation_str\":\"\",\"document_navigation\":[{\"level\":1,\"content\":\"Parameters\",\"anchor\":\"parameters\"},{\"level\":2,\"content\":\"...middlewares\",\"anchor\":\"function_createpipeline_0_parameter____middlewares\"},{\"level\":1,\"content\":\"Return Type\",\"anchor\":\"return-type\"}]},\"disable_search\":false,\"categories_panel\":null}"
+ "{\"kind\":\"SymbolPageCtx\",\"html_head_ctx\":{\"title\":\"createPipeline - default - documentation\",\"current_file\":\".\",\"stylesheet_url\":\"../styles.css\",\"page_stylesheet_url\":\"../page.css\",\"reset_stylesheet_url\":\"../reset.css\",\"url_search_index\":\"../search_index.js\",\"script_js\":\"../script.js\",\"fuse_js\":\"../fuse.js\",\"search_js\":\"../search.js\",\"darkmode_toggle_js\":\"../darkmode_toggle.js\",\"head_inject\":null,\"disable_search\":false},\"symbol_group_ctx\":{\"name\":\"createPipeline\",\"symbols\":[{\"kind\":{\"kind\":\"Function\",\"char\":\"f\",\"title\":\"Function\",\"title_lowercase\":\"function\",\"title_plural\":\"Functions\"},\"usage\":null,\"tags\":[],\"subtitle\":null,\"content\":[{\"kind\":\"function\",\"value\":{\"functions\":[{\"anchor\":{\"id\":\"function_createpipeline_0\"},\"name\":\"createPipeline\",\"summary\":\"(...middlewares: Middleware[]): Middleware\",\"deprecated\":null,\"content\":{\"id\":\"\",\"docs\":\"Create middleware pipeline.
\\n
\",\"sections\":[{\"header\":{\"title\":\"Parameters\",\"anchor\":{\"id\":\"parameters\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":\"...middlewares\",\"name_href\":null,\"content\":\": Middleware[]\",\"anchor\":{\"id\":\"function_createpipeline_0_parameter____middlewares\"},\"tags\":[],\"js_doc\":\"\",\"source_href\":null}]}},{\"header\":{\"title\":\"Return Type\",\"anchor\":{\"id\":\"return-type\"},\"href\":null,\"doc\":null},\"content\":{\"kind\":\"doc_entry\",\"content\":[{\"name_prefix\":null,\"name\":null,\"name_href\":null,\"content\":\"Middleware\",\"anchor\":{\"id\":\"function_createpipeline_0_return\"},\"tags\":[],\"js_doc\":null,\"source_href\":null}]}}]}}]}}],\"deprecated\":null,\"source_href\":null}],\"diff_status\":{\"kind\":\"added\"}},\"breadcrumbs_ctx\":{\"root\":{\"name\":\"index\",\"href\":\"../\"},\"current_entrypoint\":{\"name\":\"default\",\"href\":\"../\"},\"entrypoints\":[{\"name\":\"all symbols\",\"href\":\".././all_symbols.html\"},{\"name\":\"default\",\"href\":\"../\"}],\"symbol\":[{\"name\":\"createPipeline\",\"href\":\"../././~/createPipeline.html\"}]},\"toc_ctx\":{\"usages\":{\"usages\":[{\"name\":\"\",\"content\":\"import { createPipeline } from ".";\\n
\\n
\",\"icon\":null,\"additional_css\":\"\"}],\"composed\":false},\"top_symbols\":null,\"document_navigation_str\":\"\",\"document_navigation\":[{\"level\":1,\"content\":\"Parameters\",\"anchor\":\"parameters\"},{\"level\":2,\"content\":\"...middlewares\",\"anchor\":\"function_createpipeline_0_parameter____middlewares\"},{\"level\":1,\"content\":\"Return Type\",\"anchor\":\"return-type\"}]},\"disable_search\":false,\"categories_panel\":null}"
],
[
"./~/debugLog.json",