Skip to content

Commit 03b83ff

Browse files
GearsDatapackslpil
authored andcommitted
Test search data generation
1 parent a2b22c1 commit 03b83ff

6 files changed

+432
-81
lines changed

compiler-core/src/docs.rs

Lines changed: 87 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,7 @@ pub fn generate_html<IO: FileSystemReader>(
184184
content: Content::Text(temp.render().expect("Page template rendering")),
185185
});
186186

187-
search_items.push(SearchItem {
188-
type_: SearchItemType::Page,
189-
parent_title: config.name.to_string(),
190-
title: config.name.to_string(),
191-
content: escape_html_content(content),
192-
reference: page.path.to_string(),
193-
})
187+
search_items.push(search_item_for_page(&config.name, &page.path, content))
194188
}
195189

196190
// Generate module documentation pages
@@ -203,7 +197,7 @@ pub fn generate_html<IO: FileSystemReader>(
203197

204198
let documentation_content = module.ast.documentation.iter().join("\n");
205199
let rendered_documentation =
206-
render_markdown(&documentation_content.clone(), MarkdownSource::Comment);
200+
render_markdown(&documentation_content, MarkdownSource::Comment);
207201

208202
let mut printer = Printer::new(
209203
module.ast.type_info.package.clone(),
@@ -215,62 +209,14 @@ pub fn generate_html<IO: FileSystemReader>(
215209
let types = printer.type_definitions(&source_links, &module.ast.definitions);
216210
let values = printer.value_definitions(&source_links, &module.ast.definitions);
217211

218-
types.iter().for_each(|type_| {
219-
let constructors = type_
220-
.constructors
221-
.iter()
222-
.map(|constructor| {
223-
let arguments = constructor
224-
.arguments
225-
.iter()
226-
.map(|argument| {
227-
format!("{}\n{}", argument.name, argument.text_documentation)
228-
})
229-
.join("\n");
230-
231-
format!(
232-
"{}\n{}\n{}",
233-
constructor.raw_definition, constructor.text_documentation, arguments
234-
)
235-
})
236-
.join("\n");
237-
238-
search_items.push(SearchItem {
239-
type_: SearchItemType::Type,
240-
parent_title: module.name.to_string(),
241-
title: type_.name.to_string(),
242-
content: format!(
243-
"{}\n{}\n{}\n{}",
244-
type_.raw_definition,
245-
type_.text_documentation,
246-
constructors,
247-
import_synonyms(&module.name, type_.name)
248-
),
249-
reference: format!("{}.html#{}", module.name, type_.name),
250-
})
251-
});
252-
values.iter().for_each(|value| {
253-
search_items.push(SearchItem {
254-
type_: SearchItemType::Value,
255-
parent_title: module.name.to_string(),
256-
title: value.name.to_string(),
257-
content: format!(
258-
"{}\n{}\n{}",
259-
value.raw_definition,
260-
value.text_documentation,
261-
import_synonyms(&module.name, value.name)
262-
),
263-
reference: format!("{}.html#{}", module.name, value.name),
264-
})
265-
});
212+
types
213+
.iter()
214+
.for_each(|type_| search_items.push(search_item_for_type(&module.name, type_)));
215+
values
216+
.iter()
217+
.for_each(|value| search_items.push(search_item_for_value(&module.name, value)));
266218

267-
search_items.push(SearchItem {
268-
type_: SearchItemType::Module,
269-
parent_title: module.name.to_string(),
270-
title: module.name.to_string(),
271-
content: documentation_content,
272-
reference: format!("{}.html", module.name),
273-
});
219+
search_items.push(search_item_for_module(module));
274220

275221
let page_title = format!("{} · {} · v{}", name, config.name, config.version);
276222
let page_meta_description = "";
@@ -472,6 +418,74 @@ pub fn generate_html<IO: FileSystemReader>(
472418
files
473419
}
474420

421+
fn search_item_for_page(package: &str, path: &str, content: String) -> SearchItem {
422+
SearchItem {
423+
type_: SearchItemType::Page,
424+
parent_title: package.to_string(),
425+
title: package.to_string(),
426+
content,
427+
reference: path.to_string(),
428+
}
429+
}
430+
431+
fn search_item_for_type(module: &str, type_: &TypeDefinition<'_>) -> SearchItem {
432+
let constructors = type_
433+
.constructors
434+
.iter()
435+
.map(|constructor| {
436+
let arguments = constructor
437+
.arguments
438+
.iter()
439+
.map(|argument| format!("{}\n{}", argument.name, argument.text_documentation))
440+
.join("\n");
441+
442+
format!(
443+
"{}\n{}\n{}",
444+
constructor.raw_definition, constructor.text_documentation, arguments
445+
)
446+
})
447+
.join("\n");
448+
449+
SearchItem {
450+
type_: SearchItemType::Type,
451+
parent_title: module.to_string(),
452+
title: type_.name.to_string(),
453+
content: format!(
454+
"{}\n{}\n{}\n{}",
455+
type_.raw_definition,
456+
type_.text_documentation,
457+
constructors,
458+
import_synonyms(module, type_.name)
459+
),
460+
reference: format!("{}.html#{}", module, type_.name),
461+
}
462+
}
463+
464+
fn search_item_for_value(module: &str, value: &DocsValues<'_>) -> SearchItem {
465+
SearchItem {
466+
type_: SearchItemType::Value,
467+
parent_title: module.to_string(),
468+
title: value.name.to_string(),
469+
content: format!(
470+
"{}\n{}\n{}",
471+
value.raw_definition,
472+
value.text_documentation,
473+
import_synonyms(module, value.name)
474+
),
475+
reference: format!("{}.html#{}", module, value.name),
476+
}
477+
}
478+
479+
fn search_item_for_module(module: &Module) -> SearchItem {
480+
SearchItem {
481+
type_: SearchItemType::Module,
482+
parent_title: module.name.to_string(),
483+
title: module.name.to_string(),
484+
content: module.ast.documentation.iter().join("\n"),
485+
reference: format!("{}.html", module.name),
486+
}
487+
}
488+
475489
pub fn generate_json_package_interface(
476490
path: Utf8PathBuf,
477491
package: &Package,
@@ -529,22 +543,6 @@ fn page_unnest_test() {
529543
assert_eq!(page_unnest("gleam/string/inspect"), "../..");
530544
}
531545

532-
fn escape_html_content(it: String) -> String {
533-
it.replace('&', "&amp;")
534-
.replace('<', "&lt;")
535-
.replace('>', "&gt;")
536-
.replace('\"', "&quot;")
537-
.replace('\'', "&#39;")
538-
}
539-
540-
#[test]
541-
fn escape_html_content_test() {
542-
assert_eq!(
543-
escape_html_content("&<>\"'".to_string()),
544-
"&amp;&lt;&gt;&quot;&#39;"
545-
);
546-
}
547-
548546
fn import_synonyms(parent: &str, child: &str) -> String {
549547
format!("Synonyms:\n{parent}.{child}\n{parent} {child}")
550548
}
@@ -677,22 +675,32 @@ struct ModuleTemplate<'a> {
677675
rendering_timestamp: &'a str,
678676
}
679677

678+
/// Search data for use by Hexdocs search, as well as the search built-in to
679+
/// generated documentation
680680
#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]
681681
struct SearchData {
682682
items: Vec<SearchItem>,
683683
#[serde(rename = "proglang")]
684684
programming_language: SearchProgrammingLanguage,
685685
}
686686

687+
/// A single item that can appear as a search result
687688
#[derive(Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]
688689
struct SearchItem {
690+
/// The type of item this is: Value, Type, Module, or other Page
689691
#[serde(rename = "type")]
690692
type_: SearchItemType,
693+
/// The title of the module or package containing this search item
691694
#[serde(rename = "parentTitle")]
692695
parent_title: String,
696+
/// The title of this item
693697
title: String,
698+
/// Markdown text which describes this item, containing documentation from
699+
/// doc comments, as well as rendered definitions of types and values.
694700
#[serde(rename = "doc")]
695701
content: String,
702+
/// The relative URL to the documentation for this search item, for example
703+
/// `gleam/option.html#Option`
696704
#[serde(rename = "ref")]
697705
reference: String,
698706
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
source: compiler-core/src/docs/tests.rs
3+
expression: output
4+
---
5+
------ SOURCE CODE
6+
7+
/// Reverses a `List`, and returns the list in reverse.
8+
/// ```
9+
/// reverse([1, 2, 3])
10+
/// // [3, 2, 1]
11+
/// ```
12+
pub fn reverse(list: List(a), out: List(a)) -> List(a) {
13+
case list {
14+
[] -> out
15+
[first, ..rest] -> reverse(rest, [first, ..out])
16+
}
17+
}
18+
19+
------------------------------------
20+
21+
TITLE: main
22+
PARENT TITLE: main
23+
TYPE: Module
24+
REFERENCE: main.html
25+
CONTENT:
26+
27+
------------------------------------
28+
TITLE: reverse
29+
PARENT TITLE: module
30+
TYPE: Value
31+
REFERENCE: module.html#reverse
32+
CONTENT:
33+
```
34+
pub fn reverse(list: List(a), out: List(a)) -> List(a)
35+
```
36+
Reverses a `List`, and returns the list in reverse.
37+
38+
reverse([1, 2, 3])
39+
// [3, 2, 1]
40+
41+
42+
Synonyms:
43+
module.reverse
44+
module reverse
45+
------------------------------------
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
source: compiler-core/src/docs/tests.rs
3+
expression: output
4+
---
5+
------ SOURCE CODE
6+
7+
/// # The `Option` type
8+
/// Represents an optional value, either `Some` or `None`.
9+
/// If it is None, the value is absent
10+
/// [Read more](https://example.com)
11+
pub type Option(inner) {
12+
/// Here is some
13+
/// documentation for the `Some` constructor
14+
Some(
15+
/// And even documentation on a **field**!
16+
value: inner
17+
)
18+
None
19+
}
20+
21+
------------------------------------
22+
23+
TITLE: main
24+
PARENT TITLE: main
25+
TYPE: Module
26+
REFERENCE: main.html
27+
CONTENT:
28+
29+
------------------------------------
30+
TITLE: Option
31+
PARENT TITLE: module
32+
TYPE: Type
33+
REFERENCE: module.html#Option
34+
CONTENT:
35+
```
36+
pub type Option(inner) {
37+
Some(value: inner)
38+
None
39+
}
40+
```
41+
# The `Option` type
42+
Represents an optional value, either `Some` or `None`.
43+
If it is None, the value is absent
44+
[Read more](https://example.com)
45+
46+
```
47+
Some(value: inner)
48+
```
49+
Here is some
50+
documentation for the `Some` constructor
51+
52+
value
53+
And even documentation on a **field**!
54+
55+
```
56+
None
57+
```
58+
59+
60+
Synonyms:
61+
module.Option
62+
module Option
63+
------------------------------------
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
source: compiler-core/src/docs/tests.rs
3+
expression: output
4+
---
5+
------ SOURCE CODE
6+
7+
/// Pi is the ration between a circle's **radius** and its
8+
/// *circumference*. Pretty cool!
9+
pub const pi = 3.14
10+
11+
------------------------------------
12+
13+
TITLE: main
14+
PARENT TITLE: main
15+
TYPE: Module
16+
REFERENCE: main.html
17+
CONTENT:
18+
19+
------------------------------------
20+
TITLE: pi
21+
PARENT TITLE: module
22+
TYPE: Value
23+
REFERENCE: module.html#pi
24+
CONTENT:
25+
```
26+
pub const pi: Float
27+
```
28+
Pi is the ration between a circle's **radius** and its
29+
*circumference*. Pretty cool!
30+
31+
Synonyms:
32+
module.pi
33+
module pi
34+
------------------------------------

0 commit comments

Comments
 (0)