
Export.pudu
Pudu131 lines8.0 KB
1/** @Docgen.Api.Export — extracted declarations written as model, Markdown, or API page files */2module PuduLangDocgen.Api.Export34import Std.Json as Json5import PuduLangDocgen.Api.Catalog as Catalog6import PuduLangDocgen.Api.Model as Model7import PuduLangDocgen as Docgen8import PuduLangDocgen.Yaml as Yaml91011const API_PAGE: Str = "#YamlMime:ApiPage\n"121314export const FORMATS: Array[Str] = ["json", "markdown", "apiPage"]15161718export fn files(units: &Array[Model.Unit], format: Str) -> Array[(Str, Str)] {19 var result: Array[(Str, Str)] = []20 let extension = if format == "markdown" { ".md" } else if format == "apiPage" { ".yml" } else { ".json" }21 for unit in *units {22 if format == "json" { result = result.push((unit.uid + ".json", Json.encodePretty(&unitJson(&unit)))) }23 else {24 result = result.push((unit.uid + extension, if format == "markdown" { moduleMarkdown(&unit) } else { API_PAGE + Yaml.encode(&modulePage(&unit)) }))25 for member in unit.members {26 if Model.isType(member.kind) { result = result.push((member.uid + extension, if format == "markdown" { typeMarkdown(&unit, &member) } else { API_PAGE + Yaml.encode(&typePage(&unit, &member)) })) }27 }28 }29 }30 let options = Catalog.Options{..Catalog.defaults(), dest: ""}31 let toc = Catalog.toc(units, &options).map(fn(item: Docgen.TocItem) -> Docgen.Meta {32 let children = item.children.map(|child: Docgen.TocItem| Docgen.Fields([("name", Docgen.Text(child.title)), ("href", Docgen.Text(child.href.replace(".html", extension)))]))33 Docgen.Fields([("name", Docgen.Text(item.title)), ("href", Docgen.Text(item.href.replace(".html", extension))), ("items", Docgen.Items(children))])34 })35 result.push(("toc.yml", Yaml.encode(&Docgen.Items(toc))))36}373839fn unitJson(unit: &Model.Unit) -> Json.Json {40 Json.object(&[41 ("uid", Json.Text(unit.uid)), ("path", Json.Text(unit.path)), ("line", Json.Number(unit.line)), ("doc", Json.Text(unit.doc)),42 ("imports", Json.list(&unit.imports.map(fn(entry: (Str, Str)) -> Json.Json {43 let (alias, name) = entry44 Json.object(&[("alias", Json.Text(alias)), ("module", Json.Text(name))])45 }))),46 ("members", Json.list(&unit.members.map(|member: Model.Member| memberJson(&member)))),47 ("implementations", Json.list(&unit.implementations.map(|held: Model.Implementation| Json.object(&[("trait", Json.Text(held.contract)), ("target", Json.Text(held.target)), ("line", Json.Number(held.line)), ("methods", Json.list(&held.methods.map(|method: Model.Member| memberJson(&method))))]))))48 ])49}505152fn memberJson(member: &Model.Member) -> Json.Json {53 Json.object(&[54 ("uid", Json.Text(member.uid)), ("name", Json.Text(member.name)), ("kind", Json.Text(member.kind)), ("signature", Json.Text(member.signature)),55 ("doc", Json.Text(member.doc)), ("line", Json.Number(member.line)), ("exported", Json.Boolean(member.exported)),56 ("parameters", Json.list(&member.parameters.map(|parameter: Model.Parameter| Json.object(&[("name", Json.Text(parameter.name)), ("type", Json.Text(parameter.kind))])))),57 ("returns", Json.Text(member.returns)), ("members", Json.list(&member.members.map(|inner: Model.Member| memberJson(&inner))))58 ])59}606162fn moduleMarkdown(unit: &Model.Unit) -> Str {63 var lines = ["---", "uid: " + Yaml.scalar(unit.uid), "title: " + Yaml.scalar(unit.uid), "---", "", "# " + unit.uid, ""]64 if !unit.doc.isEmpty() { lines = lines.push(unit.doc).push("") }65 for member in unit.members {66 if Model.isType(member.kind) {67 let summary = Model.summary(member.doc)68 lines = lines.push("- <xref:" + member.uid + ">" + (if summary.isEmpty() { "" } else { ": " + summary }))69 }70 }71 for member in unit.members {72 if !Model.isType(member.kind) {73 lines = lines.concat(["", "## " + member.name + " \{#" + member.name + "\}", "", "```pudu", member.signature, "```", ""])74 if !member.doc.isEmpty() { lines = lines.push(member.doc) }75 }76 }77 lines.join("\n") + "\n"78}798081fn typeMarkdown(unit: &Model.Unit, member: &Model.Member) -> Str {82 var lines = ["---", "uid: " + Yaml.scalar(member.uid), "title: " + Yaml.scalar(member.name), "---", "", "# " + member.name, "", "Module <xref:" + unit.uid + ">", "", "```pudu", member.signature, "```", ""]83 if !member.doc.isEmpty() { lines = lines.push(member.doc).push("") }84 if member.kind == "trait" {85 for method in member.members { lines = lines.concat(["## " + method.name + " \{#" + method.name + "\}", "", "```pudu", method.signature, "```", "", method.doc, ""]) }86 } else if !member.members.isEmpty() {87 lines = lines.concat(["| Name | Type | Description |", "| --- | --- | --- |"])88 for inner in member.members { lines = lines.push("| `" + inner.name + "` | `" + inner.returns.replace("|", "\\|") + "` | " + Model.summary(inner.doc).replace("|", "\\|") + " |") }89 }90 lines.join("\n") + "\n"91}929394fn modulePage(unit: &Model.Unit) -> Docgen.Meta {95 var body = [Docgen.Fields([("h1", Docgen.Text(unit.uid))])]96 if !unit.doc.isEmpty() { body = body.push(Docgen.Fields([("markdown", Docgen.Text(unit.doc))])) }97 let types = unit.members.filter(|member: Model.Member| Model.isType(member.kind))98 if !types.isEmpty() {99 body = body.push(Docgen.Fields([("h2", Docgen.Text("Types"))]))100 body = body.push(Docgen.Fields([("list", Docgen.Items(types.map(|member: Model.Member| Docgen.Fields([("text", Docgen.Text(member.name)), ("url", Docgen.Text(member.uid + ".html"))]))))]))101 }102 for member in unit.members {103 if !Model.isType(member.kind) { body = body.concat(declaration(member, 3)) }104 }105 Docgen.Fields([("title", Docgen.Text(unit.uid)), ("languageId", Docgen.Text("pudu")), ("body", Docgen.Items(body))])106}107108109fn typePage(unit: &Model.Unit, member: &Model.Member) -> Docgen.Meta {110 var body = [Docgen.Fields([("h1", Docgen.Text(member.name))]), Docgen.Fields([("facts", Docgen.Items([Docgen.Fields([("name", Docgen.Text("Module")), ("value", Docgen.Fields([("text", Docgen.Text(unit.uid)), ("url", Docgen.Text(unit.uid + ".html"))]))])]))]), Docgen.Fields([("code", Docgen.Text(member.signature))])]111 if !member.doc.isEmpty() { body = body.push(Docgen.Fields([("markdown", Docgen.Text(member.doc))])) }112 if !member.members.isEmpty() {113 body = body.push(Docgen.Fields([("h2", Docgen.Text(if member.kind == "trait" { "Methods" } else if member.kind == "union" { "Variants" } else { "Fields" }))]))114 if member.kind == "trait" {115 for method in member.members { body = body.concat(declaration(method, 3)) }116 } else {117 body = body.push(Docgen.Fields([("parameters", Docgen.Items(member.members.map(|inner: Model.Member| Docgen.Fields([("name", Docgen.Text(inner.name)), ("type", Docgen.Text(inner.returns)), ("description", Docgen.Text(inner.doc))]))))]))118 }119 }120 Docgen.Fields([("title", Docgen.Text(member.name)), ("languageId", Docgen.Text("pudu")), ("body", Docgen.Items(body))])121}122123124fn declaration(member: Model.Member, level: Int) -> Array[Docgen.Meta] {125 var blocks = [Docgen.Fields([("api" + show(level), Docgen.Text(member.name)), ("id", Docgen.Text(member.name))]), Docgen.Fields([("code", Docgen.Text(member.signature))])]126 if !member.doc.isEmpty() { blocks = blocks.push(Docgen.Fields([("markdown", Docgen.Text(member.doc))])) }127 let shown = member.parameters.filter(|parameter: Model.Parameter| parameter.name != "self")128 if !shown.isEmpty() { blocks = blocks.push(Docgen.Fields([("parameters", Docgen.Items(shown.map(|parameter: Model.Parameter| Docgen.Fields([("name", Docgen.Text(parameter.name)), ("type", Docgen.Text(parameter.kind))]))))])) }129 blocks130}131