///|
/// Browser bridge for the MoonDocKit playground.
///
/// The playground compiles this package to JavaScript and calls it from the
/// page, so reviewers can run the real MoonBit renderer without installing the
/// toolchain. Only plain strings cross the boundary: no JSON encoding, no
/// escaping rules that could silently disagree between MoonBit and JavaScript.
///|
/// Publish a three-argument render entry point on the host global object.
extern "js" fn host_expose_render(
name : String,
f : (String, String, String) -> String,
) -> Unit =
#| function(name, f) {
#| globalThis[name] = function(markdown, title, themeName) {
#| return f(markdown, title, themeName);
#| };
#| }
///|
/// Publish a two-argument statistics entry point on the host global object.
extern "js" fn host_expose_stats(
name : String,
f : (String, String) -> String,
) -> Unit =
#| function(name, f) {
#| globalThis[name] = function(markdown, title) {
#| return f(markdown, title);
#| };
#| }
///|
fn playground_site(title : String, markdown : String) -> @lib.DocSite {
let pages : Array[@lib.DocPage] = [
{ title, slug: "playground", source: markdown, },
]
{ title, pages, }
}
///|
fn select_theme(theme_name : String) -> @lib.SiteTheme {
if theme_name == "package" {
@lib.package_theme()
} else {
@lib.default_theme()
}
}
///|
/// Render one Markdown document into a complete HTML document.
fn render_impl(
markdown : String,
title : String,
theme_name : String,
) -> String {
let site = playground_site(title, markdown)
let page : @lib.DocPage = { title, slug: "playground", source: markdown, }
let rendered = @lib.render_page_with_options(
site,
page,
select_theme(theme_name),
@lib.default_site_options(),
)
rendered.html
}
///|
/// Return newline-separated `key=value` metrics for one Markdown document.
fn stats_impl(markdown : String, title : String) -> String {
let site = playground_site(title, markdown)
let metrics = @lib.measure_site(site)
let gate = @lib.evaluate_quality(site)
let passed = if gate.passed { "1" } else { "0" }
let out = StringBuilder(size_hint=256)
out.write_string("score=\{gate.score}\n")
out.write_string("passed=\{passed}\n")
out.write_string("words=\{metrics.word_count}\n")
out.write_string("headings=\{metrics.heading_count}\n")
out.write_string("code_blocks=\{metrics.code_block_count}\n")
out.write_string("reading_minutes=\{metrics.reading_minutes}\n")
for check in gate.checks {
let ok = if check.passed { "1" } else { "0" }
out.write_string("check_\{check.name}=\{ok}\n")
}
out.to_string()
}
///|
fn main {
host_expose_render("moonDocKitRenderPage", render_impl)
host_expose_stats("moonDocKitPageStats", stats_impl)
}