|
8 | 8 | import { Format } from "../../config/types.ts"; |
9 | 9 |
|
10 | 10 | import { mergeConfigs } from "../../core/config.ts"; |
| 11 | +import { resolveInputTarget } from "../../project/project-index.ts"; |
| 12 | +import { projectFormatOutputDir } from "../../project/project-shared.ts"; |
| 13 | +import { kProjectType, ProjectContext } from "../../project/types.ts"; |
| 14 | +import { |
| 15 | + kBookAppendix, |
| 16 | + kBookChapters, |
| 17 | +} from "../../project/types/book/book-config.ts"; |
| 18 | +import { |
| 19 | + bookConfig, |
| 20 | + isBookIndexPage, |
| 21 | +} from "../../project/types/book/book-shared.ts"; |
| 22 | +import { projectType } from "../../project/types/project-types.ts"; |
| 23 | +import { join } from "path/mod.ts"; |
11 | 24 |
|
12 | 25 | import { plaintextFormat } from "../formats-shared.ts"; |
| 26 | +import { dirAndStem } from "../../core/path.ts"; |
| 27 | +import { formatResourcePath } from "../../core/resources.ts"; |
13 | 28 |
|
| 29 | +// Provide the basic asciidoc format |
14 | 30 | export function asciidocFormat(): Format { |
15 | 31 | return mergeConfigs( |
16 | 32 | plaintextFormat("Asciidoc", "adoc"), |
17 | 33 | { |
18 | 34 | extensions: { |
19 | | - book: { |
20 | | - multiFile: true, |
21 | | - formatOutputDirectory(_format: Format) { |
22 | | - return "asciidoc"; |
23 | | - }, |
24 | | - }, |
| 35 | + book: asciidocBookExtension, |
25 | 36 | }, |
26 | 37 | }, |
27 | 38 | ); |
28 | 39 | } |
| 40 | + |
| 41 | +// This provide book specific behavior for producing asciidoc books |
| 42 | +const asciidocBookExtension = { |
| 43 | + multiFile: true, |
| 44 | + formatOutputDirectory(_format: Format) { |
| 45 | + return "asciidoc"; |
| 46 | + }, |
| 47 | + async onMultiFilePrePrender( |
| 48 | + isIndex: boolean, |
| 49 | + format: Format, |
| 50 | + markdown: string, |
| 51 | + project: ProjectContext, |
| 52 | + ) { |
| 53 | + if (isIndex) { |
| 54 | + // Generate additional markdown to include in the |
| 55 | + // index page |
| 56 | + const rootPageMd = await bookRootPageMarkdown(project); |
| 57 | + const completeMd = markdown + "\n" + rootPageMd; |
| 58 | + |
| 59 | + // Use a book specific template for the book |
| 60 | + format.pandoc.template = formatResourcePath( |
| 61 | + "asciidoc", |
| 62 | + join( |
| 63 | + "templates", |
| 64 | + "book", |
| 65 | + "template.asciidoc", |
| 66 | + ), |
| 67 | + ); |
| 68 | + |
| 69 | + return { markdown: completeMd, format }; |
| 70 | + } else { |
| 71 | + // Turn off the TOC on child pages |
| 72 | + format.pandoc.toc = false; |
| 73 | + } |
| 74 | + return { format }; |
| 75 | + }, |
| 76 | + async bookPostProcess(_format: Format, _project: ProjectContext) { |
| 77 | + }, |
| 78 | +}; |
| 79 | + |
| 80 | +async function bookRootPageMarkdown(project: ProjectContext) { |
| 81 | + // Find chapter and appendices |
| 82 | + const chapters = await resolveBookInputs( |
| 83 | + bookConfig( |
| 84 | + kBookChapters, |
| 85 | + project.config, |
| 86 | + ) as string[], |
| 87 | + project, |
| 88 | + (input: string) => { |
| 89 | + // Exclude the index page from the chapter list (since we'll append |
| 90 | + // this to the index page contents) |
| 91 | + return !isBookIndexPage(input); |
| 92 | + }, |
| 93 | + ); |
| 94 | + |
| 95 | + const bookApps = bookConfig( |
| 96 | + kBookAppendix, |
| 97 | + project.config, |
| 98 | + ) as string[]; |
| 99 | + const appendices = bookApps |
| 100 | + ? await resolveBookInputs( |
| 101 | + bookApps, |
| 102 | + project, |
| 103 | + ) |
| 104 | + : []; |
| 105 | + |
| 106 | + // Write a book asciidoc file |
| 107 | + const fileContents = [ |
| 108 | + "\n```{=asciidoc}\n\n", |
| 109 | + levelOffset("+1"), |
| 110 | + include(chapters), |
| 111 | + appendix(appendices), |
| 112 | + levelOffset("-1"), |
| 113 | + "```\n", |
| 114 | + ]; |
| 115 | + |
| 116 | + return fileContents.join("\n"); |
| 117 | +} |
| 118 | + |
| 119 | +function levelOffset(offset: string) { |
| 120 | + return `:leveloffset: ${offset}\n`; |
| 121 | +} |
| 122 | + |
| 123 | +function include(chapters: string[]) { |
| 124 | + return chapters.map((chap) => { |
| 125 | + return `include::${chap}[]\n`; |
| 126 | + }).join("\n"); |
| 127 | +} |
| 128 | + |
| 129 | +function appendix(apps: string[]) { |
| 130 | + if (apps.length > 0) { |
| 131 | + return apps.map((app) => { |
| 132 | + return `[appendix]\ninclude::${app}[]\n`; |
| 133 | + }).join("\n"); |
| 134 | + } else { |
| 135 | + return ""; |
| 136 | + } |
| 137 | +} |
| 138 | + |
| 139 | +async function resolveBookInputs( |
| 140 | + inputs: string[], |
| 141 | + project: ProjectContext, |
| 142 | + filter?: (input: string) => boolean, |
| 143 | +) { |
| 144 | + const outputs: string[] = []; |
| 145 | + for (const input of inputs) { |
| 146 | + if (filter && !filter(input)) { |
| 147 | + continue; |
| 148 | + } |
| 149 | + const target = await resolveInputTarget( |
| 150 | + project, |
| 151 | + input, |
| 152 | + false, |
| 153 | + ); |
| 154 | + if (target) { |
| 155 | + const [dir, stem] = dirAndStem(target?.outputHref); |
| 156 | + const outputFile = join( |
| 157 | + dir, |
| 158 | + `${stem}.adoc`, |
| 159 | + ); |
| 160 | + |
| 161 | + outputs.push(outputFile); |
| 162 | + } |
| 163 | + } |
| 164 | + return outputs; |
| 165 | +} |
0 commit comments