import type { InlineSpan } from '../parse/index.js'; import type { DigitSystem, DocumentMetadata } from '../types.js'; import type { VDTBlock, VDTPage } from '../vdt.js'; /** A minimal view of a page used by `computeChapterTitles` to detect * blank parity-padding pages. We accept just the flags rather than the * whole `VDTPage` so this helper stays easy to test in isolation. * * `blankForParity` pages belong to the upcoming chapter (they exist * solely to push it onto the right parity). `blankForForce` pages * belong to the *previous* chapter (they are the mandatory separator * of the `always-*` modes) — the walker stops when it hits one. */ export interface ChapterTitlePageInfo { blankForParity?: boolean; blankForForce?: boolean; /** Set on a part-divider page. */ partInfo?: unknown; } export interface PlaceholderContext { page: VDTPage; allPages: VDTPage[]; metadata: DocumentMetadata; /** Chapter title per page index (most recent H1 at or before each page). */ chapterTitleByPageIndex: string[]; /** The chapter in force at the top of each page (see * `computeChapterTitlesAtTop`, `computeChapterNumbersAtTop`). Back * `{chapterTitleAtTop}` / `{chapterNumberAtTop}`; a missing entry * resolves to `''`. */ chapterTitleAtTopByPageIndex?: string[]; chapterNumberAtTopByPageIndex?: string[]; /** Heading attributes of the current chapter's H1 per page index (see * `computeChapterAttrs`). Backs `{attr.}` in header/footer slots. A * missing entry or key resolves to `''`. */ chapterAttrsByPageIndex?: Record[]; /** Current part title / number per page index (see `computePartValues`). * Back `{partTitle}` / `{partNumber}`; a missing entry resolves to `''`. */ partTitleByPageIndex?: string[]; partNumberByPageIndex?: string[]; partPaletteByPageIndex?: Record[]; /** Current chapter number per page index (see `computeChapterNumbers`). * Backs `{chapterNumber}` in header/footer slots. */ chapterNumberByPageIndex?: string[]; /** Physical pages of the whole book (`{bookTotalPages}`); defaults to * `allPages.length`, the document being the whole book. */ bookTotalPages?: number; /** The document's digit system: `{totalPages}` and `{bookTotalPages}` * are written in it (the page labels already are). `'latn'` when * unset. */ numerals?: DigitSystem; /** The first and last marks of every page for a mark key (see * `computePageMarks`); backs `{firstMark.}` / `{lastMark.}`. * Called lazily, once per key a template names. Absent → `''`. */ marksFor?: (key: string) => PageMarks | undefined; /** On a composed page (#984): the counter of the first numbered heading * its frames hold, in the document's digits, for `{headingNumber}`; * and the same by frame name, for `{headingNumber.}`. Absent or * missing → `''`. */ headingNumber?: string; headingNumberByFrame?: Record; } export interface PlaceholderResult { text: string; unknownPlaceholders: string[]; missingMetadata: string[]; } /** Optional behaviour of the placeholder resolvers. */ export interface PlaceholderResolveOptions { /** Applied to every `{attr.}` value before it is inserted (design * text turns the `\n` escape of an attribute value into a newline). */ attrValue?: (value: string) => string; } /** Placeholder grammar: `name` or `name.key` — the dotted form is reserved * for namespaced lookups such as `{attr.author}` (heading attributes) and * `{boxText.2}` (the second item of a box's content, #1014). */ export declare const PLACEHOLDER_NAME_RE: RegExp; /** `{boxText}` and `{boxText.}` (#1014): in a box style's design, the * box's content, whole (`0`) or its `n`-th paragraph or list item (from * 1). Undefined for any other name. */ export declare function boxTextPlaceholderIndex(name: string): number | undefined; /** Namespace of the heading-attribute placeholders (`{attr.}`). */ export declare const ATTR_PLACEHOLDER_PREFIX = "attr."; /** When `name` is an `attr.` placeholder, returns ``. */ export declare function attrPlaceholderKey(name: string): string | undefined; /** When `name` is `headingNumber` (the page's first numbered heading) or * `headingNumber.` (the one the frame `` holds), a composed * page's counter of the heading a frame takes (#984): `{}` or the frame's * name. Undefined for any other name. */ export declare function headingNumberPlaceholder(name: string): { frame?: string; } | undefined; /** When `name` is a running-mark placeholder — `firstMark.` or * `lastMark.`, the first or last mark on the page — returns which one * and the key: `h1`…`h6` for a heading level, else a paragraph style id. */ export declare function markPlaceholder(name: string): { which: 'first' | 'last'; key: string; } | undefined; /** The marks of one key laid out on each page: `first[p]` is the first mark * that starts on page `p` and `last[p]` the last; a page on which none * starts takes the mark in effect (the last one before it) for both, and * pages before the first mark get `''`. */ export interface PageMarks { first: string[]; last: string[]; } /** What sets a mark: a heading of `level`, or a paragraph of a * `:::paragraphs{style=…}` container whose style is `styleId`. */ export type MarkSource = { level: number; } | { styleId: string; }; /** The source a mark key names: `h1`…`h6` a heading level, anything else a * paragraph style id. */ export declare function markSourceOf(key: string): MarkSource; /** The bold run a paragraph opens with — a dictionary headword, a glossary * term — as a running mark: the leading bold spans joined, trimmed, minus * closing punctuation (`**Aback.**` → `Aback`). `''` when the paragraph * does not open with bold text. */ export declare function leadingBoldText(spans: readonly InlineSpan[]): string; /** * Per page, the first and last mark of one source (see {@link PageMarks}), * walking the blocks in placement order. A heading's mark is its text * without the number; a paragraph's is its leading bold run (a headword), * given by `paragraphMark` from the content block — a paragraph that does * not open with bold text sets none. A block split across columns or pages * sets its mark once, where it starts. */ export declare function computePageMarks(blocks: readonly VDTBlock[], totalPages: number, source: MarkSource, paragraphMark?: (contentIndex: number) => { styleId: string; text: string; } | undefined): PageMarks; /** * Precompute chapter titles (most recent H1 text) for each page index by * walking blocks once. Returns an array where `result[pageIndex]` is the plain * text of the most recent H1 encountered at or before that page. When no H1 * has appeared yet, the entry is an empty string. * * When `pages` is supplied, blank parity-padding pages immediately * preceding a new H1 are retroactively attributed to the *upcoming* * chapter — the blank left-hand page that exists only to push the next * chapter onto a right-hand page should display the new chapter's title * in its header, not the previous chapter's. */ export declare function computeChapterTitles(blocks: VDTBlock[], totalPages: number, pages?: ChapterTitlePageInfo[]): string[]; /** * Precompute chapter numbers (most recent H1 `numberPrefix`) per page. Mirrors * `computeChapterTitles` but tracks the numeric prefix (e.g. `"1"`, `"2"`) so * `{chapterNumber}` in heading-context slots resolves to the current chapter. */ export declare function computeChapterNumbers(blocks: VDTBlock[], totalPages: number, pages?: ChapterTitlePageInfo[], ordinalOffset?: number, /** Chapters that print no number at all (a heading style whose * `numberingTemplate` is `''`): they count, but show no ordinal. */ numberless?: (block: VDTBlock) => boolean, /** The document's digit system, for the chapter ordinal. */ digits?: DigitSystem): string[]; /** * `{chapterNumber}` at each placed block: the value of the last level-1 * heading at or before it in document order ('' before the first), by the * same counter as `computeChapterNumbers`. A heading design reads its own * block's value — where two chapters meet on a page, the page value is the * later one's, which is right for the running heads but not for the first * chapter's heading, nor for a lower heading that comes before the later * chapter. The document's build measures an opener with this same value * (over the content blocks), so measure and paint agree. */ export declare function computeChapterNumbersByBlock(blocks: readonly VDTBlock[], ordinalOffset?: number, numberless?: (block: VDTBlock) => boolean, digits?: DigitSystem): Map; /** The fields of a level-1 heading `{chapterNumber}` reads. */ export interface ChapterNumberSource { /** A heading style with `numbered: false`. */ unnumbered?: boolean; /** The heading's content block index: blocks of one heading split * across columns share it and count once. */ contentIndex?: number; /** The heading's own counter value (a `startAt` attribute restarts it). */ headingNumber?: number; /** The formatted number the level's (or style's) template prints. */ numberPrefix?: string; } /** What `{chapterNumber}` prints for each level-1 heading, fed in document * order: the heading's number prefix, else — without a numbering * template — the chapter ordinal, continuing past the `ordinalOffset` * chapters laid out before this document. An unnumbered chapter advances * nothing and shows nothing; a `numberless` one counts but shows nothing. * One rule for the running heads (`computeChapterNumbers`, over the placed * blocks) and for measuring an opener design before it is painted (over * the content blocks), so both read the same value. The ordinal is * written in the document's `digits`; a prefix already is. */ export declare function chapterNumberCounter(ordinalOffset?: number, numberless?: (block: B) => boolean, digits?: DigitSystem): (block: B) => string; /** * Precompute the heading attributes (`# Title {key="value"}`) of the most * recent H1 per page. Backs `{attr.}` in header/footer slots; pages * before the first H1 get an empty record. */ export declare function computeChapterAttrs(blocks: VDTBlock[], totalPages: number, pages?: ChapterTitlePageInfo[]): Record[]; /** * `{chapterTitleAtTop}`: per page, the title of the chapter in force at the * top of the page, the chapter whose text opens it. That is the chapter a * level-1 heading opens when the heading is the first block placed on the * page, and otherwise the chapter the page runs on from, even when a new * one starts lower down the page. `computeChapterTitles` gives the later * one on such a page. A blank parity page goes with the page after it, as * there, so it names the chapter in force at that page's top; a * `blankForForce` page goes with the page before it. */ export declare function computeChapterTitlesAtTop(blocks: VDTBlock[], totalPages: number, pages?: ChapterTitlePageInfo[]): string[]; /** `{chapterNumberAtTop}`: the number of the chapter in force at the top * of each page (see {@link computeChapterTitlesAtTop}), by the counter of * `computeChapterNumbers`. */ export declare function computeChapterNumbersAtTop(blocks: VDTBlock[], totalPages: number, pages?: ChapterTitlePageInfo[], ordinalOffset?: number, numberless?: (block: VDTBlock) => boolean, digits?: DigitSystem): string[]; /** The page fields `computePartValues` reads. */ export interface PartPageInfo extends ChapterTitlePageInfo { partInfo?: { number: string; title: string; palette?: Record; }; } /** Per page, the part in effect: the most recent part page on or before it * (blank parity pages right before a part page already belong to it), or * `start` — the part the preceding chapters left open — before any. Each * part brings its own palette overrides (`{}` when the fence sets none), * which also tint every blank leaf right before its divider. */ export declare function computePartValues(pages: readonly PartPageInfo[], start?: { number: string; title: string; palette?: Record; }): { partTitleByPageIndex: string[]; partNumberByPageIndex: string[]; partPaletteByPageIndex: Record[]; }; /** The fields of a laid-out line that say how it joins the next one. */ export interface JoinedLine { hyphenated?: boolean; hardHyphen?: boolean; plainStart?: number; plainEnd?: number; /** The line opens with the hyphen repeated from the line before * (`bodyText.repeatHyphen`), which is not part of the text. */ repeatedHyphen?: boolean; } /** How a wrapped line joins the line after it when a block's lines are * read back as one text (a running head's `{chapterTitle}`, a design's * `{titleText}`). Returns how many characters to drop from the end of * the line (the hyphen a break added) and what goes between the two * lines. * * A hyphenated line continues its word: the break's own hyphen (a * dictionary syllable, an author's soft hyphen, a word cut for being * wider than the line) is dropped, and the hyphen of a line broken after * the text's own (`hardHyphen`, "well-" | "known") stays. A line that * ends where the next one starts in the block's plain text (`plainEnd` = * `plainStart`) broke inside a run without adding anything (after a hard * hyphen or a dash, or in a word cut for width, when the first-fit * breaker of a heading without formatting set it) and joins with nothing. * A hyphenated line that ends without a hyphen, where the next line * starts one character further on in the plain text, parted a group * glued by a no-break space that was wider than the line ("Cap\u00edtulo" | * "XVIII"): the break took the no-break space, which comes back as * U+00A0, so the group stays glued. Every other break took a space, * which comes back once, and so does a space the line itself ends with * (`spaceAtEnd`: the caller trimmed it from `text`); the last line is * followed by nothing. */ export declare function lineJoin(text: string, line: JoinedLine, next: JoinedLine | undefined, spaceAtEnd?: boolean): { drop: number; separator: '' | ' ' | '\u00A0'; }; /** How {@link blockLinesText} reads a block. */ export interface BlockLinesTextOptions { /** A heading's forced breaks (`\\`, `VDTBlock.titleBreaks`) as plain * text reads them (`plainTitleBreak`): nothing where a Chinese * character meets a digit or Latin text, where the lines hold the space * the page sets as the Han–Latin space. The PDF bookmarks and document * title read a heading this way (#221). */ plainTitleBreaks?: boolean; } /** A block's lines read back as the text they were broken from, the way * the paragraph read before wrapping (see {@link lineJoin}): wrapped lines * keep their trailing space token and hyphenated lines end with the break * mark. A line of Chinese broken between two characters joins the next * with nothing, and one broken at an ideographic space (U+3000, the space * of a couplet title or of `numberSeparator: ' '`) gets it back, whichever * of the two lines holds it. Whitespace inside the lines is kept as it is; * the ends are trimmed. `\u2028` is the title-break placeholder. The * running heads read a heading this way, and so do the PDF bookmarks and * document title (with `options.plainTitleBreaks`). */ export declare function blockLinesText(block: VDTBlock, options?: BlockLinesTextOptions): string; /** A title written with forced breaks (`\\`, as in a part's `title` * attribute) as plain text reads it: each break as `plainTitleBreak` reads * it, nothing where a Chinese character meets a digit or Latin text, the * ideographic space between two Chinese characters, a space between Latin * words. The PDF bookmarks of the parts read their titles this way, as * those of the headings read theirs (#221). */ export declare function plainTitleText(title: string): string; /** * Resolve placeholder templates. Grammar: * - `{name}` with name matching `[a-zA-Z][a-zA-Z0-9]*` is a placeholder; * - `{name.key}` is a namespaced placeholder — `{attr.}` reads the * current chapter's heading attributes (missing → `''`, no warning), * `{firstMark.}` / `{lastMark.}` the page's running marks; * - `{{` and `}}` are literal braces. */ export declare function resolvePlaceholders(template: string, ctx: PlaceholderContext, options?: PlaceholderResolveOptions): PlaceholderResult; /** * Scan a template for the set of placeholder names it references (unique, * including unknown ones). Useful for warnings. */ export declare function collectPlaceholderNames(template: string): string[]; /** * The literal text of a template: every placeholder (`{name}`, known or * not, `{attr.key}`, `{firstMark.key}`) removed, the `{{` / `}}` escapes * read as the braces they print, and the `\n` escape as a line break. * What a design text prints whatever the document (#849). */ export declare function stripPlaceholders(template: string): string; export declare function isKnownPlaceholder(name: string): boolean; export declare function isMetadataPlaceholder(name: string): boolean; //# sourceMappingURL=placeholders.d.ts.map