@@ -19,6 +19,7 @@ import {
1919import {
2020 kAbstract ,
2121 kAuthor ,
22+ kAuthors ,
2223 kDate ,
2324 kDescription ,
2425 kNumberSections ,
@@ -78,14 +79,13 @@ import {
7879} from "./book-shared.ts" ;
7980import { bookCrossrefsPostRender } from "./book-crossrefs.ts" ;
8081import { bookBibliographyPostRender } from "./book-bibliography.ts" ;
81- import {
82- partitionYamlFrontMatter ,
83- readYamlFromMarkdown ,
84- } from "../../../core/yaml.ts" ;
82+ import { partitionYamlFrontMatter } from "../../../core/yaml.ts" ;
8583import { pathWithForwardSlashes } from "../../../core/path.ts" ;
8684import { kDateFormat } from "../website/listing/website-listing-template.ts" ;
8785import { removePandocTo } from "../../../command/render/flags.ts" ;
8886import { resourcePath } from "../../../core/resources.ts" ;
87+ import { PandocAttr , PartitionedMarkdown } from "../../../core/pandoc/types.ts" ;
88+ import { stringify } from "encoding/yaml.ts" ;
8989
9090export function bookPandocRenderer (
9191 options : RenderOptions ,
@@ -347,42 +347,89 @@ async function mergeExecutedFiles(
347347 file . context . target . source === itemInputPath
348348 ) ;
349349 if ( file ) {
350- const partitioned = partitionYamlFrontMatter (
351- file . executeResult . markdown ,
352- ) ;
350+ const partitioned = partitionMarkdown ( file . executeResult . markdown ) ;
351+
352+ // Will always provide the title markdown whether the title was provided by
353+ // front matter or by the first heading. Note that this will
354+ // prefer to use the title that appears in the front matter, and if
355+ // there is no front matter title it will promote the first heading to
356+ // level 1 heading
357+ const resolveTitleMarkdown = ( partitioned : PartitionedMarkdown ) => {
358+ // Creates a markdown title, dealing with attributes, if present
359+ const createMarkdownTitle = ( text : string , attr ?: PandocAttr ) => {
360+ let attrStr = "" ;
361+ if ( attr ) {
362+ const idStr = attr . id !== "" ? `#${ attr . id } ` : "" ;
363+ const clzStr = attr . classes . map ( ( clz ) => {
364+ return `.${ clz } ` ;
365+ } ) ;
366+ const keyValueStr = attr . keyvalue . map ( ( kv ) => {
367+ const escapedValue = kv [ 1 ] . replaceAll ( / " / gm, '\\"' ) ;
368+ return `${ kv [ 0 ] } ="${ escapedValue } " ` ;
369+ } ) ;
370+ const attrContents = `${ idStr } ${ clzStr } ${ keyValueStr } ` . trim ( ) ;
371+ attrStr = `{${ attrContents } }` ;
372+ }
353373
354- const titleMdFromFrontMatter = ( frontMatter ?: string ) => {
355- const yaml = frontMatter
356- ? readYamlFromMarkdown ( frontMatter )
357- : undefined ;
374+ return `# ${ text } ${ attrStr } \n\n` ;
375+ } ;
358376
359- if ( yaml ) {
360- const frontTitle = frontMatterTitle ( yaml ) ;
377+ let titleText ;
378+ let titleAttr ;
379+ if ( partitioned . yaml ) {
380+ const frontTitle = frontMatterTitle ( partitioned . yaml ) ;
361381 if ( frontTitle ) {
362- const titleMarkdown = frontTitle ? `# ${ frontTitle } \n\n` : "" ;
382+ titleText = frontTitle ;
383+ } else {
384+ titleText = partitioned . headingText ;
385+ titleAttr = partitioned . headingAttr ;
386+ }
387+ } else {
388+ titleText = partitioned . headingText ;
389+ titleAttr = partitioned . headingAttr ;
390+ }
363391
364- const titleBlockPath = resourcePath (
365- "projects/book/pandoc/title-block.md" ,
366- ) ;
367- const titleAttr = `template='${ titleBlockPath } '` ;
392+ if ( titleText === undefined ) {
393+ titleText = "" ;
394+ }
395+ return createMarkdownTitle ( titleText , titleAttr ) ;
396+ } ;
368397
369- const titleBlockMd = "```````{.quarto-title-block " +
370- titleAttr + "}\n" +
371- partitioned ?. yaml +
372- "\n```````" ;
398+ // If there is front matter for this chapter, this will generate a code
399+ // cell that will be rendered a LUA filter (the code cell will provide the
400+ // path to the template that should be used as well as the front matter
401+ // to use when rendering)
402+ const resolveTitleBlockMarkdown = ( yaml ?: Metadata ) => {
403+ if ( yaml ) {
404+ const titleBlockPath = resourcePath (
405+ "projects/book/pandoc/title-block.md" ,
406+ ) ;
373407
374- return titleMarkdown + titleBlockMd ;
375- } else {
376- return "" ;
377- }
408+ const titleAttr = `template='${ titleBlockPath } '` ;
409+ const frontMatter = `---\n${
410+ stringify ( yaml , { indent : 2 } )
411+ } \n---\n`;
412+
413+ const titleBlockMd = "```````{.quarto-title-block " +
414+ titleAttr + "}\n" +
415+ frontMatter +
416+ "\n```````\n\n" ;
417+
418+ return titleBlockMd ;
378419 } else {
379420 return "" ;
380421 }
381422 } ;
382423
424+ // Compose the markdown for this chapter
425+ const titleMarkdown = resolveTitleMarkdown ( partitioned ) ;
426+ const titleBlockMarkdown = resolveTitleBlockMarkdown (
427+ partitioned . yaml ,
428+ ) ;
383429 itemMarkdown = bookItemMetadata ( project , item , file ) +
384- titleMdFromFrontMatter ( partitioned ?. yaml ) +
385- ( partitioned ?. markdown || file . executeResult . markdown ) ;
430+ titleMarkdown +
431+ titleBlockMarkdown +
432+ partitioned . markdown ;
386433 } else {
387434 throw new Error (
388435 "Executed file not found for book item: " + item . file ,
0 commit comments