import type { Dimension } from '../types.js'; import type { ScoreFormat, ScoreSystem } from '../music/types.js'; import type { ComicPageSource } from '../comics/types.js'; import type { FigureLabelNode, SourceRange } from '../composed/types.js'; export type ContentBlockType = 'heading' | 'paragraph' | 'blockquote' | 'listItem' | 'mathDisplay' | 'resourceBlock' | 'directive' | 'containerStart' | 'containerEnd' /** A code listing (#624): a ```` ``` ```` or `~~~` fence, or indented * code under `codeStyle.indentedCode` (see {@link CodeBlockInfo}). */ | 'code' /** A music score (#1172): a ```` ```abc ```` / ```` ```musicxml ```` / * ```` ```mei ```` / ```` ```humdrum ```` fence (see {@link ScoreBlockInfo}). * The build expands it into one block per engraved system. */ | 'score'; /** Attributes parsed from a `:::name{key="v" other=bare flag}` directive. * Values are kept as strings; directive consumers validate/coerce. A bare * `flag` becomes `{ flag: '' }`. */ export type DirectiveAttrs = Record; /** A `:::verse` poem. The bayt layout (#378): one bayt per source line, * its hemistichs (the ṣadr, then the ʿajuz) split at `||` (or a spaced * `\\`, the Wikisource convention); a line without one is a single * hemistich, centred. The line layout (#620): one line of verse per * source line, a stanza per run of lines between blank lines, each stanza * a block of its own (see {@link VerseStanza}). */ export interface VerseInfo { /** The fence's attributes as written (`gap`, `width`, `align`, * `ornament`, `style`, `dir`, `layout`, `indentStep`, `turnover`, * `stanzaSpace`, `keepStanzas`, …); `pipeline/verse.ts` and * `pipeline/verseLines.ts` read them. */ attrs: DirectiveAttrs; /** Set on the blocks of a poem in the line layout (#620): which stanza * of which poem the block sets. Unset: the bayt layout, one block. */ stanza?: VerseStanza; } /** One stanza of a poem in the line layout (#620). Its block's text holds * the lines of verse, a line feed (`\n`) between two, mapped to the * source's line end; leading whitespace is not in the text but in * {@link lines}. */ export interface VerseStanza { /** The poem, numbered from 0 in the document's order: the stanzas of a * poem share it. */ poem: number; /** The stanza's index in its poem, from 0. */ index: number; /** Whether it is the poem's last stanza. */ last: boolean; /** Poem-wide index of the stanza's first line of verse, from 0. */ firstLine: number; /** The stanza's lines, in order. */ lines: VerseLineInfo[]; /** The fence named no layout and the poem has no hemistich separator: * the line layout was picked by `layout="auto"`. A configuration * stored before #620 (`bodyText.verse.layout: 'bayt'`) sets such a * stanza as single hemistichs, as postext 1.22 did. */ auto?: true; } /** A line of verse in the line layout (#620). */ export interface VerseLineInfo { /** Its indent in spaces as written: each leading space counts 1, a tab * 4, an ideographic space (U+3000) 2. Multiplied by the poem's * `indentStep`. */ indent: number; /** The line was written `+ …`: a stepped line (a line of dramatic verse * shared between speakers), set to start where the line above ended. */ stepped?: true; } /** A code listing (#624): the lines between a ```` ``` ```` or `~~~` * fence and its closing fence (or a run of indented lines), kept as * written: no inline Markdown, no directives, every space and tab. The * block's `text` joins the lines with a line feed, mapped to the source * line end, so the plain text and the source map read the listing as * written. */ /** A music score (#1172): the notation as written in its fence. */ export interface ScoreBlockInfo { format: ScoreFormat; /** The notation, the fence's indentation taken off. */ source: string; /** The fence's attributes (`{#id style=… alt="…"}`). */ attrs: DirectiveAttrs; /** Present once the build has engraved the score: the system this * block sets, out of `count`. */ system?: ScoreSystem; index?: number; count?: number; /** The engraver's message when the notation did not load. */ error?: string; /** Read from the notation, for alt text. */ title?: string; composer?: string; } export interface CodeBlockInfo { /** The first word of the info string (`js`, `python`, `console`), * lower-cased; absent when the fence names none. */ lang?: string; /** The info string as written, after the fence. */ info: string; /** The rest of the info string read in the directive attribute grammar * (`{title="backup.sh" lineNumbers start=12 highlight="3,5-7"}`). */ attrs: DirectiveAttrs; /** The title: the `title` attribute, else a bare second word of the info * string (```` ```console Terminal ````). */ title?: string; /** The listing's lines, the fence's indentation (or the four columns of * indented code) taken off, tabs kept. */ lines: string[]; /** Source offset of each line's first kept character. */ lineStarts: number[]; /** How the listing was written. */ fence: '```' | '~~~' | 'indent'; } /** Recognized directive names. Unknown names are not parsed as directives — * they fall through to the paragraph branch and surface via warnings. */ export type DirectiveName = 'pagebreak' | 'numbering' | 'columnbreak' | 'space' | 'toc' | 'index' | 'bibliography' | 'references' | 'verse' | 'page' | 'strip' | 'figure' /** Where an exercise's solutions print (#1229): `:::solutions{scope=…}`. */ | 'solutions' /** An exercise's word bank (#1225): a `::bank[sun | rain]` line inside a * `:::exercise`; its words are added to the bank as distractors. */ | 'bank'; /** Recognized fenced-container names. A container opens with a * `:::name{attrs}` line and closes with a bare `:::` line; the blocks in * between are parsed as usual and bracketed by a `containerStart` / * `containerEnd` marker pair sharing a `containerId`. */ export type ContainerName = 'callout' | 'paragraphs' | 'part' | 'columns' | 'paper' | 'frame' /** An exercise (#1225): `:::exercise{type=…}` … `:::` (see * `exercises/model.ts`), with its `:::solution` and `:::hint` inside. */ | 'exercise' | 'solution' | 'hint' /** A module of a composed page (#1062): `:::module{template="…" * name="…"}` … `:::` inside a page fence (see {@link ComposedModuleFence}). */ | 'module' /** A composed page (#854): `::::page{template=…}` … `::::`, four or * more colons (see {@link ComposedPageFence}). Not in * `KNOWN_CONTAINERS`: a three-colon `:::page` is a comic page. */ | 'composedPage' /** Only named by an `unclosedContainer` issue: a `:::figure` (#854) is * read whole into one `resourceBlock` (see {@link FigureInfo}). */ | 'figure'; /** The fence of a composed page (#854, DESIGN §3.1), on its * `containerStart` marker: `::::page{template="…" spread …}`. The page's * content is the blocks up to the matching `containerEnd`; a bare fence * of the same number of colons closes it, and a bare `:::` inside never * does. `composedPages()` (`composed/document.ts`) gathers the content by * slot. */ export interface ComposedPageFence { /** The `template` attribute as written (`''` when missing). */ template: string; /** The `spread` flag (any value but `false`). */ spread: boolean; /** Every attribute of the fence as written (`template`, `spread`, `id` * and the page's own, read by the template as `{attr.x}`). */ attrs: DirectiveAttrs; /** Absolute source range of each attribute's value. */ attrSources: Record; /** Ordinal of the fence in its text, from 0: the same in every locale * when the chapters keep their pages in order. */ fenceIndex: number; /** How many colons open (and close) the page: 4 or more. */ colons: number; /** The page's `:::module` blocks (#1062), in Markdown order, a module * inside a module left out. */ modules?: ComposedModuleFence[]; } /** A `:::module{template="…" name="…"}` block of a composed page (#1062, * DESIGN §12.7), on its `containerStart`. The slots its blocks name are * the module's: their `slot.name` is scoped by the instance name * (`.`), the source range still the value as written. */ export interface ComposedModuleFence extends SourceRange { /** The `template` attribute as written (`''` when missing). */ template: string; /** The instance name: `name` as written, else `