Skip to content

Commit b9ad1de

Browse files
committed
feat(apiref): heavy lifting
1 parent 0273bce commit b9ad1de

File tree

14 files changed

+299
-48
lines changed

14 files changed

+299
-48
lines changed

Diff for: crates/rari-doc/src/cached_readers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::docs::curriculum::{CurriculumIndexEntry, CurriculumPage};
1414
use crate::docs::page::{Page, PageLike};
1515
use crate::error::DocError;
1616
use crate::html::sidebar::{MetaSidebar, Sidebar};
17-
use crate::sidebars::jsref;
17+
use crate::sidebars::{apiref, jsref};
1818
use crate::utils::{root_for_locale, split_fm};
1919
use crate::walker::{read_docs_parallel, walk_builder};
2020

Diff for: crates/rari-doc/src/docs/build.rs

+34-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::borrow::Cow;
22

3+
use itertools::Itertools;
34
use rari_types::fm_types::PageType;
45
use rari_types::globals::{base_url, content_branch, git_history, popularities};
56
use rari_types::locale::Locale;
@@ -16,7 +17,7 @@ use super::json::{
1617
BuiltDocy, Compat, JsonBlogPost, JsonBlogPostDoc, JsonCurriculum, JsonDoADoc, JsonDoc, Prose,
1718
Section, Source, SpecificationSection, TocEntry,
1819
};
19-
use super::page::PageLike;
20+
use super::page::{Page, PageLike};
2021
use super::parents::parents;
2122
use super::title::{page_title, transform_title};
2223
use crate::baseline::get_baseline;
@@ -25,9 +26,12 @@ use crate::html::bubble_up::bubble_up_curriculum_page;
2526
use crate::html::modifier::add_missing_ids;
2627
use crate::html::rewriter::{post_process_html, post_process_inline_sidebar};
2728
use crate::html::sections::{split_sections, BuildSection, BuildSectionType, Splitted};
28-
use crate::html::sidebar::{build_sidebars, expand_details_and_mark_current_for_inline_sidebar};
29+
use crate::html::sidebar::{
30+
self, build_sidebars, expand_details_and_mark_current_for_inline_sidebar, postprocess_sidebar,
31+
};
32+
use crate::sidebars;
2933
use crate::specs::extract_specifications;
30-
use crate::templ::render::{decode_ref, render};
34+
use crate::templ::render::{decode_ref, render, Rendered};
3135

3236
impl<'a> From<BuildSection<'a>> for Section {
3337
fn from(value: BuildSection) -> Self {
@@ -133,33 +137,47 @@ pub fn make_toc(sections: &[BuildSection], with_h3: bool) -> Vec<TocEntry> {
133137
.collect()
134138
}
135139

136-
pub fn build_content<T: PageLike>(doc: &T) -> Result<PageContent, DocError> {
137-
let (ks_rendered_doc, templs) = if let Some(rari_env) = &doc.rari_env() {
138-
let (out, templs) = render(rari_env, doc.content())?;
139-
(Cow::Owned(out), templs)
140+
pub fn build_content<T: PageLike>(page: &T) -> Result<PageContent, DocError> {
141+
let (ks_rendered_doc, templs, sidebars) = if let Some(rari_env) = &page.rari_env() {
142+
let Rendered {
143+
content,
144+
templs,
145+
sidebars,
146+
} = render(rari_env, page.content())?;
147+
(Cow::Owned(content), templs, sidebars)
140148
} else {
141-
(Cow::Borrowed(doc.content()), vec![])
149+
(Cow::Borrowed(page.content()), vec![], vec![])
142150
};
143-
let encoded_html = render_md_to_html(&ks_rendered_doc, doc.locale())?;
151+
let encoded_html = render_md_to_html(&ks_rendered_doc, page.locale())?;
144152
let html = decode_ref(&encoded_html, &templs)?;
145-
let post_processed_html = post_process_html(&html, doc, false)?;
153+
let post_processed_html = post_process_html(&html, page, false)?;
146154
let mut fragment = Html::parse_fragment(&post_processed_html);
147-
if doc.page_type() == PageType::Curriculum {
155+
if page.page_type() == PageType::Curriculum {
148156
bubble_up_curriculum_page(&mut fragment)?;
149157
}
150158
add_missing_ids(&mut fragment)?;
151-
expand_details_and_mark_current_for_inline_sidebar(&mut fragment, doc.url())?;
159+
expand_details_and_mark_current_for_inline_sidebar(&mut fragment, page.url())?;
152160
let Splitted {
153161
sections,
154162
summary,
155163
sidebar,
156164
} = split_sections(&fragment).expect("DOOM");
157-
let sidebar = if let Some(sidebar) = sidebar {
158-
Some(post_process_inline_sidebar(&sidebar)?)
159-
} else {
165+
166+
// TODO cleanup
167+
let mut sidebars = sidebars
168+
.iter()
169+
.map(|s| postprocess_sidebar(s, page))
170+
.collect::<Vec<_>>();
171+
if let Some(sidebar) = &sidebar {
172+
sidebars.push(post_process_inline_sidebar(sidebar));
173+
}
174+
175+
let sidebar = if sidebars.is_empty() {
160176
None
177+
} else {
178+
Some(sidebars.into_iter().collect::<Result<String, _>>()?)
161179
};
162-
let toc = make_toc(&sections, matches!(doc.page_type(), PageType::Curriculum));
180+
let toc = make_toc(&sections, matches!(page.page_type(), PageType::Curriculum));
163181
let body = sections.into_iter().map(Into::into).collect();
164182
Ok(PageContent {
165183
body,

Diff for: crates/rari-doc/src/error.rs

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ pub enum DocError {
9191
MissingCSSL10n,
9292
#[error("At rule was empty")]
9393
MustHaveAtRule,
94+
#[error("Invalid slug for templ/sidebar: {0}")]
95+
InvalidSlugForX(String),
9496
}
9597

9698
impl<T> From<PoisonError<T>> for DocError {

Diff for: crates/rari-doc/src/helpers/json_data.rs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use std::collections::HashMap;
2+
use std::fs;
3+
4+
use once_cell::sync::OnceCell;
5+
use rari_types::globals::content_root;
6+
use serde::Deserialize;
7+
8+
#[derive(Debug, Default, Clone, Deserialize)]
9+
pub struct InterfaceData {
10+
pub inh: String,
11+
}
12+
13+
pub static JSON_DATA_INTERFACE: OnceCell<HashMap<String, InterfaceData>> = OnceCell::new();
14+
15+
pub fn json_data_interface() -> &'static HashMap<String, InterfaceData> {
16+
JSON_DATA_INTERFACE.get_or_init(|| {
17+
let f = content_root().join("jsondata/InterfaceData.json");
18+
let json_str = fs::read_to_string(f).expect("unable to read interface data json");
19+
let mut interface_data: Vec<HashMap<String, InterfaceData>> =
20+
serde_json::from_str(&json_str).expect("unable to parse interface data json");
21+
interface_data.pop().unwrap_or_default()
22+
})
23+
}
24+
25+
#[derive(Debug, Default, Clone, Deserialize)]
26+
pub struct GroupData {
27+
#[serde(default)]
28+
pub overview: Vec<String>,
29+
#[serde(default)]
30+
pub guides: Vec<String>,
31+
#[serde(default)]
32+
pub interfaces: Vec<String>,
33+
#[serde(default)]
34+
pub methods: Vec<String>,
35+
#[serde(default)]
36+
pub properties: Vec<String>,
37+
#[serde(default)]
38+
pub events: Vec<String>,
39+
}
40+
41+
pub static JSON_DATA_GROUP: OnceCell<HashMap<String, GroupData>> = OnceCell::new();
42+
43+
pub fn json_data_group() -> &'static HashMap<String, GroupData> {
44+
JSON_DATA_GROUP.get_or_init(|| {
45+
let f = content_root().join("jsondata/GroupData.json");
46+
let json_str = fs::read_to_string(f).expect("unable to read interface data json");
47+
let mut interface_data: Vec<HashMap<String, GroupData>> =
48+
serde_json::from_str(&json_str).expect("unable to parse group data json");
49+
interface_data.pop().unwrap_or_default()
50+
})
51+
}

Diff for: crates/rari-doc/src/helpers/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub mod css_info;
2+
pub mod json_data;
23
pub mod subpages;

Diff for: crates/rari-doc/src/html/sidebar.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,14 @@ fn expand_details_and_mark_current(html: &mut Html, a_selector: Selector) -> Res
7272
Ok(())
7373
}
7474

75-
fn postprocess_sidebar(ks_rendered_sidebar: &str, doc: &Doc) -> Result<String, DocError> {
75+
pub fn postprocess_sidebar<T: PageLike>(
76+
ks_rendered_sidebar: &str,
77+
page: &T,
78+
) -> Result<String, DocError> {
7679
let mut fragment = Html::parse_fragment(ks_rendered_sidebar);
7780

78-
expand_details_and_mark_current_for_sidebar(&mut fragment, &doc.meta.url)?;
79-
let post_processed_html = post_process_html(&fragment.html(), doc, true)?;
81+
expand_details_and_mark_current_for_sidebar(&mut fragment, page.url())?;
82+
let post_processed_html = post_process_html(&fragment.html(), page, true)?;
8083
Ok::<_, DocError>(post_processed_html)
8184
}
8285

Diff for: crates/rari-doc/src/sidebars/apiref.rs

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
use rari_l10n::l10n_json_data;
2+
use rari_types::fm_types::PageType;
3+
use rari_types::locale::Locale;
4+
use tracing::error;
5+
6+
use crate::docs::doc::Doc;
7+
use crate::docs::page::{Page, PageLike};
8+
use crate::error::DocError;
9+
use crate::helpers::json_data::{json_data_group, json_data_interface};
10+
use crate::helpers::subpages::get_sub_pages;
11+
use crate::html::sidebar::{MetaSidebar, SidebarEntry, SidebarMetaEntry, SidebarMetaEntryContent};
12+
13+
pub fn sidebar(slug: &str, group: Option<&str>, locale: Locale) -> Result<MetaSidebar, DocError> {
14+
let static_properties_label = l10n_json_data("Common", "Static_properties", locale)?;
15+
let instance_properties_label = l10n_json_data("Common", "Instance_properties", locale)?;
16+
let static_methods_label = l10n_json_data("Common", "Static_methods", locale)?;
17+
let instance_methods_label = l10n_json_data("Common", "Instance_methods", locale)?;
18+
let constructor_label = l10n_json_data("Common", "Constructor", locale)?;
19+
let inheritance_label = l10n_json_data("Common", "Inheritance", locale)?;
20+
let implemented_by_label = l10n_json_data("Common", "Implemented_by", locale)?;
21+
let related_labl = l10n_json_data("Common", "Related_pages_wo_group", locale)?;
22+
let translate_label = l10n_json_data("Common", "[Translate]", locale)?;
23+
let title_label = l10n_json_data("Common", "TranslationCTA", locale)?;
24+
let events_label = l10n_json_data("Common", "Events", locale)?;
25+
26+
let main_if = slug
27+
.strip_prefix("Web/API/")
28+
.map(|s| &s[..s.find('/').unwrap_or(s.len())])
29+
.ok_or_else(|| DocError::InvalidSlugForX(slug.to_string()))?;
30+
if !main_if
31+
.chars()
32+
.next()
33+
.map(|c| c.is_uppercase())
34+
.unwrap_or_default()
35+
{
36+
error!("Slugs for Web/API/* must start with uppercase letter got {slug}");
37+
return Err(DocError::InvalidSlugForX(slug.to_string()));
38+
}
39+
40+
let web_api_data = json_data_interface();
41+
let web_api_groups = group.and_then(|group| json_data_group().get(group));
42+
43+
// TODO: custom sorting?
44+
let main_if_pages = get_sub_pages(
45+
&format!("/en-US/docs/Web/API/{}", main_if),
46+
Some(1),
47+
Default::default(),
48+
)?;
49+
50+
let related = if let Some(iter) = web_api_groups.map(|groups| {
51+
groups
52+
.interfaces
53+
.iter()
54+
.chain(groups.methods.iter())
55+
.chain(groups.properties.iter())
56+
.filter(|s| s.as_str() != main_if)
57+
}) {
58+
let mut related = iter.collect::<Vec<_>>();
59+
related.sort();
60+
related
61+
} else {
62+
Default::default()
63+
};
64+
65+
let mut static_properties = vec![];
66+
let mut instance_properties = vec![];
67+
let mut static_methods = vec![];
68+
let mut instance_methods = vec![];
69+
let mut constructors = vec![];
70+
let mut events = vec![];
71+
72+
for page in main_if_pages {
73+
let v = match page.page_type() {
74+
PageType::WebApiStaticProperty => &mut static_properties,
75+
PageType::WebApiInstanceProperty => &mut instance_properties,
76+
PageType::WebApiStaticMethod => &mut static_methods,
77+
PageType::WebApiInstanceMethod => &mut instance_methods,
78+
PageType::WebApiConstructor => &mut constructors,
79+
PageType::WebApiEvent => &mut events,
80+
_ => continue,
81+
};
82+
v.push(page);
83+
}
84+
85+
let mut inherited = vec![];
86+
87+
let mut interface = main_if;
88+
while let Some(inherited_data) = web_api_data.get(interface).map(|data| data.inh.as_str()) {
89+
inherited.push(inherited_data);
90+
interface = inherited_data;
91+
}
92+
93+
let mut entries = vec![];
94+
95+
if let Some([ref overview]) = web_api_groups.map(|group| group.overview.as_slice()) {
96+
entries.push(SidebarMetaEntry {
97+
section: true,
98+
content: SidebarMetaEntryContent::Page(Doc::page_from_slug(
99+
&format!("Web/API/{}", overview.replace(' ', "_")),
100+
locale,
101+
)?),
102+
..Default::default()
103+
});
104+
}
105+
entries.push(SidebarMetaEntry {
106+
section: true,
107+
content: SidebarMetaEntryContent::Page(Doc::page_from_slug(
108+
&format!("Web/API/{main_if}"),
109+
locale,
110+
)?),
111+
..Default::default()
112+
});
113+
114+
Ok(MetaSidebar { entries })
115+
}
116+
117+
fn api_page_title(page: &Page) -> &str {
118+
if let Some(short_title) = page.short_title() {
119+
return short_title;
120+
}
121+
let title = page.title();
122+
let title = &title[title.rfind('.').unwrap_or(0)..];
123+
if matches!(page.page_type(), PageType::WebApiEvent) {
124+
let title = page.slug();
125+
let title = &title[title.rfind('/').unwrap_or(0)..];
126+
if let Some(title) = title.strip_suffix("_event") {
127+
title
128+
} else {
129+
title
130+
}
131+
} else {
132+
title
133+
}
134+
}

Diff for: crates/rari-doc/src/sidebars/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
pub mod apiref;
12
pub mod jsref;

Diff for: crates/rari-doc/src/templ/macros/apiref.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use rari_templ_func::rari_f;
2+
3+
use crate::error::DocError;
4+
use crate::sidebars::apiref;
5+
6+
#[rari_f]
7+
pub fn apiref(group: Option<String>) -> Result<String, DocError> {
8+
apiref::sidebar(env.slug, group.as_deref(), env.locale)?.render(env.locale)
9+
}

Diff for: crates/rari-doc/src/templ/macros/compat.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@ mod test {
1616
use rari_types::RariEnv;
1717

1818
use crate::error::DocError;
19-
use crate::templ::render::{decode_ref, render};
19+
use crate::templ::render::{decode_ref, render, Rendered};
2020

2121
#[test]
2222
fn test_compat_none() -> Result<(), DocError> {
2323
let env = RariEnv {
2424
..Default::default()
2525
};
26-
let (out, templs) = render(&env, r#"{{ compat }}"#)?;
27-
let out = decode_ref(&out, &templs)?;
26+
let Rendered {
27+
content, templs, ..
28+
} = render(&env, r#"{{ compat }}"#)?;
29+
let out = decode_ref(&content, &templs)?;
2830
assert_eq!(out, r#""#);
2931
Ok(())
3032
}
@@ -38,8 +40,10 @@ mod test {
3840
let exp = r#"<div class="bc-data" data-query="javascript.builtins.Array.concat" data-depth="1" data-multiple="false">
3941
If you're able to see this, something went wrong on this page.
4042
</div>"#;
41-
let (out, templs) = render(&env, r#"{{ compat }}"#)?;
42-
let out = decode_ref(&out, &templs)?;
43+
let Rendered {
44+
content, templs, ..
45+
} = render(&env, r#"{{ compat }}"#)?;
46+
let out = decode_ref(&content, &templs)?;
4347
assert_eq!(out, exp);
4448
Ok(())
4549
}
@@ -59,8 +63,10 @@ If you're able to see this, something went wrong on this page.
5963
<div class="bc-data" data-query="javascript.builtins.Array.filter" data-depth="1" data-multiple="true">
6064
If you're able to see this, something went wrong on this page.
6165
</div>"#;
62-
let (out, templs) = render(&env, r#"{{ compat }}"#)?;
63-
let out = decode_ref(&out, &templs)?;
66+
let Rendered {
67+
content, templs, ..
68+
} = render(&env, r#"{{ compat }}"#)?;
69+
let out = decode_ref(&content, &templs)?;
6470
assert_eq!(out, exp);
6571
Ok(())
6672
}

Diff for: crates/rari-doc/src/templ/macros/links.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,17 @@ pub fn link_internal(
114114
mod test {
115115

116116
use crate::error::DocError;
117-
use crate::templ::render::{decode_ref, render};
117+
use crate::templ::render::{decode_ref, render, Rendered};
118118

119119
#[test]
120120
fn test_link() -> Result<(), DocError> {
121121
let env = rari_types::RariEnv {
122122
..Default::default()
123123
};
124-
let (out, templs) = render(&env, r#"{{ link("/en-US/docs/basic") }}"#)?;
125-
let out = decode_ref(&out, &templs)?;
124+
let Rendered {
125+
content, templs, ..
126+
} = render(&env, r#"{{ link("/en-US/docs/basic") }}"#)?;
127+
let out = decode_ref(&content, &templs)?;
126128
assert_eq!(out, r#"<a href="/en-US/docs/Basic">The Basic Page</a>"#);
127129
Ok(())
128130
}

0 commit comments

Comments
 (0)