@pretextbook/pretext-html 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +77 -3
  2. package/assets/preview-html.xsl +56 -0
  3. package/assets/upstream.json +2 -2
  4. package/assets/xsl/entities.ent +14 -1
  5. package/assets/xsl/latex/pretext-latex-texstyle.xsl +5 -2
  6. package/assets/xsl/localizations/README.md +1 -1
  7. package/assets/xsl/localizations/af-ZA.xml +5 -6
  8. package/assets/xsl/localizations/bg-BG.xml +5 -6
  9. package/assets/xsl/localizations/ca-ES.xml +5 -6
  10. package/assets/xsl/localizations/cs-CZ.xml +5 -6
  11. package/assets/xsl/localizations/de-DE.xml +108 -108
  12. package/assets/xsl/localizations/en-US.xml +18 -17
  13. package/assets/xsl/localizations/es-ES.xml +5 -6
  14. package/assets/xsl/localizations/fi-FI.xml +5 -6
  15. package/assets/xsl/localizations/fr-CA.xml +5 -6
  16. package/assets/xsl/localizations/fr-FR.xml +5 -6
  17. package/assets/xsl/localizations/hu-HU.xml +5 -6
  18. package/assets/xsl/localizations/it-IT.xml +7 -7
  19. package/assets/xsl/localizations/ku-CKB.xml +5 -6
  20. package/assets/xsl/localizations/nl-NL.xml +5 -6
  21. package/assets/xsl/localizations/pt-BR.xml +4 -5
  22. package/assets/xsl/localizations/pt-PT.xml +4 -5
  23. package/assets/xsl/localizations/zh-HANS.xml +5 -6
  24. package/assets/xsl/pretext-assembly.xsl +154 -29
  25. package/assets/xsl/pretext-beamer.xsl +112 -10
  26. package/assets/xsl/pretext-braille-preprint.xsl +22 -3
  27. package/assets/xsl/pretext-common.xsl +117 -42
  28. package/assets/xsl/pretext-epub.xsl +74 -87
  29. package/assets/xsl/pretext-fo.xsl +115 -41
  30. package/assets/xsl/pretext-html.xsl +333 -102
  31. package/assets/xsl/pretext-latex-classic.xsl +48 -35
  32. package/assets/xsl/pretext-latex-common.xsl +160 -98
  33. package/assets/xsl/pretext-latex.xsl +12 -10
  34. package/assets/xsl/pretext-markdown.xsl +5 -3
  35. package/assets/xsl/pretext-numbers.xsl +28 -2
  36. package/assets/xsl/pretext-revealjs.xsl +44 -2
  37. package/assets/xsl/pretext-runestone-static.xsl +27 -4
  38. package/assets/xsl/pretext-runestone.xsl +112 -0
  39. package/assets/xsl/pretext-text.xsl +21 -14
  40. package/assets/xsl/publisher-variables.xsl +187 -47
  41. package/assets/xsl/support/extract-math.xsl +22 -2
  42. package/assets/xsl/support/package-math.xsl +9 -8
  43. package/assets/xsl/utilities/report-publisher-variables.xsl +4 -0
  44. package/assets/xsl-bundle.json +1 -1
  45. package/dist/cli-C0JwLhuv.js +1456 -0
  46. package/dist/cli.js +3 -3
  47. package/dist/html-static.d.ts +2 -2
  48. package/dist/index.browser.d.ts +9 -4
  49. package/dist/index.browser.js +1151 -841
  50. package/dist/index.d.ts +9 -3
  51. package/dist/index.js +50 -46
  52. package/dist/publication.d.ts +21 -0
  53. package/dist/renderer.d.ts +134 -13
  54. package/dist/skeleton.d.ts +68 -7
  55. package/dist/source-cache.d.ts +36 -0
  56. package/dist/sourcemap.d.ts +11 -1
  57. package/dist/subtree.d.ts +79 -0
  58. package/dist/xinclude.d.ts +40 -3
  59. package/package.json +1 -1
  60. package/dist/cli-ox-z2TCZ.js +0 -1145
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
- export { renderHtml, defaultXslDir, isJspiAvailable, xpathStringLiteral, } from './renderer.js';
2
- export type { RenderOptions, RenderResult } from './renderer.js';
1
+ export { renderHtml, measureDocument, defaultSourceCache, defaultXslDir, isJspiAvailable, xpathStringLiteral, } from './renderer.js';
2
+ export type { DocumentSize, RenderOptions, RenderResult, SourceOptions, } from './renderer.js';
3
+ export type { SubtreeOptions } from './subtree.js';
4
+ export { SourceCache } from './source-cache.js';
5
+ export type { SourceCacheOptions } from './source-cache.js';
6
+ export type { SourceReader } from './xinclude.js';
3
7
  export { findSourceMapEntry } from './sourcemap.js';
4
8
  export type { PtxSourceMap, SourceMapEntry } from './sourcemap.js';
5
9
  export { forcePortablePublication } from './publication.js';
@@ -10,7 +14,9 @@ export { injectRevealBridge, isRevealView, revealBridgeScript, } from './reveal.
10
14
  export type { RevealView, RevealViewOptions } from './reveal.js';
11
15
  export { openBornHiddenKnowls } from './knowls.js';
12
16
  export { buildSkeleton, divisionLevel, replaceDivision } from './skeleton.js';
13
- export type { Skeleton } from './skeleton.js';
17
+ export type { Skeleton, SkeletonOptions } from './skeleton.js';
18
+ export { readPublicationLevels } from './publication.js';
19
+ export type { PublicationLevels } from './publication.js';
14
20
  export { OFF_PAGE_MESSAGE, rewriteXrefLinks } from './xrefs.js';
15
21
  export type { RewriteXrefLinkOptions } from './xrefs.js';
16
22
  export { rewriteAssetUrls } from './assets.js';
package/dist/index.js CHANGED
@@ -1,48 +1,52 @@
1
- import { O as i, P as s, b as t, d as a, a as n, c as o, f as l, e as p, i as c, g as d, o as P, p as E, r as m, h as v, j as A, m as S, s as g, k as B, x as f } from "./cli-ox-z2TCZ.js";
2
- import { injectRevealBridge as h, isRevealView as w, revealBridgeScript as R } from "./reveal.js";
3
- import { describeAsset as x, missingAssetPlaceholder as L, missingAssetSvg as T, rewriteAssetUrls as b } from "./assets.js";
4
- import { PREVIEW_THEME_MESSAGE as I, injectThemeBridge as M, isPreviewTheme as j, previewThemeMessage as O, themeBridgeScript as V } from "./theme.js";
5
- import { PRINT_PREVIEW_GLOBAL as k, injectPrintPreview as D, listPrintouts as N, printPreviewBridgeScript as W, rootPrintoutId as y } from "./printout.js";
6
- import { LIVE_PATCH_GLOBAL as F, livePatchScript as K, patchDocument as X, typesetPatch as J } from "./live-patch.js";
1
+ import { O as s, P as i, S as t, b as a, d as n, a as o, c, e as l, f as p, g as d, i as P, h as E, m, o as S, p as v, r as u, j as A, k as f, l as g, n as h, s as B, q as _, x as w } from "./cli-C0JwLhuv.js";
2
+ import { injectRevealBridge as L, isRevealView as x, revealBridgeScript as T } from "./reveal.js";
3
+ import { describeAsset as G, missingAssetPlaceholder as I, missingAssetSvg as M, rewriteAssetUrls as j } from "./assets.js";
4
+ import { PREVIEW_THEME_MESSAGE as V, injectThemeBridge as C, isPreviewTheme as D, previewThemeMessage as H, themeBridgeScript as k } from "./theme.js";
5
+ import { PRINT_PREVIEW_GLOBAL as W, injectPrintPreview as y, listPrintouts as F, printPreviewBridgeScript as K, rootPrintoutId as X } from "./printout.js";
6
+ import { LIVE_PATCH_GLOBAL as J, livePatchScript as U, patchDocument as Y, typesetPatch as z } from "./live-patch.js";
7
7
  export {
8
- F as LIVE_PATCH_GLOBAL,
9
- i as OFF_PAGE_MESSAGE,
10
- s as PREVIEW_BANNER_STORAGE_KEY,
11
- I as PREVIEW_THEME_MESSAGE,
12
- k as PRINT_PREVIEW_GLOBAL,
13
- t as buildSkeleton,
14
- a as defaultXslDir,
15
- x as describeAsset,
16
- n as detectRenderTarget,
17
- o as divisionLevel,
18
- l as findSourceMapEntry,
19
- p as forcePortablePublication,
20
- c as injectPreviewBanner,
21
- D as injectPrintPreview,
22
- h as injectRevealBridge,
23
- M as injectThemeBridge,
24
- d as isJspiAvailable,
25
- j as isPreviewTheme,
26
- w as isRevealView,
27
- N as listPrintouts,
28
- K as livePatchScript,
29
- L as missingAssetPlaceholder,
30
- T as missingAssetSvg,
31
- P as openBornHiddenKnowls,
32
- X as patchDocument,
33
- E as previewBannerScript,
34
- O as previewThemeMessage,
35
- W as printPreviewBridgeScript,
36
- m as renderHtml,
37
- v as replaceDivision,
38
- R as revealBridgeScript,
39
- b as rewriteAssetUrls,
40
- A as rewriteXrefLinks,
41
- y as rootPrintoutId,
42
- S as runCli,
43
- g as setAssetsBase,
44
- B as setMountReader,
45
- V as themeBridgeScript,
46
- J as typesetPatch,
47
- f as xpathStringLiteral
8
+ J as LIVE_PATCH_GLOBAL,
9
+ s as OFF_PAGE_MESSAGE,
10
+ i as PREVIEW_BANNER_STORAGE_KEY,
11
+ V as PREVIEW_THEME_MESSAGE,
12
+ W as PRINT_PREVIEW_GLOBAL,
13
+ t as SourceCache,
14
+ a as buildSkeleton,
15
+ n as defaultSourceCache,
16
+ o as defaultXslDir,
17
+ G as describeAsset,
18
+ c as detectRenderTarget,
19
+ l as divisionLevel,
20
+ p as findSourceMapEntry,
21
+ d as forcePortablePublication,
22
+ P as injectPreviewBanner,
23
+ y as injectPrintPreview,
24
+ L as injectRevealBridge,
25
+ C as injectThemeBridge,
26
+ E as isJspiAvailable,
27
+ D as isPreviewTheme,
28
+ x as isRevealView,
29
+ F as listPrintouts,
30
+ U as livePatchScript,
31
+ m as measureDocument,
32
+ I as missingAssetPlaceholder,
33
+ M as missingAssetSvg,
34
+ S as openBornHiddenKnowls,
35
+ Y as patchDocument,
36
+ v as previewBannerScript,
37
+ H as previewThemeMessage,
38
+ K as printPreviewBridgeScript,
39
+ u as readPublicationLevels,
40
+ A as renderHtml,
41
+ f as replaceDivision,
42
+ T as revealBridgeScript,
43
+ j as rewriteAssetUrls,
44
+ g as rewriteXrefLinks,
45
+ X as rootPrintoutId,
46
+ h as runCli,
47
+ B as setAssetsBase,
48
+ _ as setMountReader,
49
+ k as themeBridgeScript,
50
+ z as typesetPatch,
51
+ w as xpathStringLiteral
48
52
  };
@@ -50,6 +50,27 @@ export interface AssetDirectories {
50
50
  */
51
51
  managed: boolean;
52
52
  }
53
+ /** The depths a publication file sets numbering and the contents list to. */
54
+ export interface PublicationLevels {
55
+ /** `common/tableofcontents/@level`. */
56
+ tocLevel?: number;
57
+ /**
58
+ * The deepest of `numbering/{blocks,projects,equations,footnotes,figures,
59
+ * ...}/@level` — the families share one default, but a publisher may set
60
+ * them apart, and a preview must keep what the deepest of them counts.
61
+ */
62
+ numberingLevel?: number;
63
+ /** `numbering/divisions/@level`, which caps every other numbering level. */
64
+ maxNumberingLevel?: number;
65
+ }
66
+ /**
67
+ * Read the numbering and table-of-contents depths from a publication file —
68
+ * the ones that decide how much of a document a division preview has to keep
69
+ * (see skeleton.ts). Absent entries are left undefined for the skeleton to
70
+ * default by the document's structure, exactly as publisher-variables.xsl
71
+ * does. Falls back to MINIMAL_PUBLICATION when none is supplied.
72
+ */
73
+ export declare function readPublicationLevels(publicationXml?: string): PublicationLevels;
53
74
  /**
54
75
  * Read the asset directories from a publication file, falling back to the
55
76
  * defaults baked into MINIMAL_PUBLICATION when none is supplied.
@@ -4,9 +4,64 @@ import { RevealView } from './reveal.js';
4
4
  import { PtxSourceMap } from './sourcemap.js';
5
5
  import { RenderTarget } from './target.js';
6
6
  import { PreviewTheme } from './theme.js';
7
- export interface RenderOptions {
7
+ import { SourceReader } from './xinclude.js';
8
+ import { SourceCache } from './source-cache.js';
9
+ import { SubtreeOptions } from './subtree.js';
10
+ /**
11
+ * How a document is read: the options every entry point that reads source
12
+ * shares — {@link renderHtml} and {@link measureDocument}.
13
+ */
14
+ export interface SourceOptions {
8
15
  /** Path to the root PreTeXt source file (typically source/main.ptx). */
9
16
  sourcePath: string;
17
+ /**
18
+ * Source text to transform instead of reading `sourcePath` from disk.
19
+ * `sourcePath` is still used to resolve relative xi:includes. Lets callers
20
+ * render unsaved editor content.
21
+ */
22
+ sourceContent?: string;
23
+ /**
24
+ * Directory served to the transform for xi:includes and relative
25
+ * references. Defaults to the directory containing `sourcePath`. Set it to
26
+ * the project root when the publication file or includes live outside the
27
+ * source directory. Files outside this directory are not readable by the
28
+ * transform.
29
+ */
30
+ projectDir?: string;
31
+ /**
32
+ * Supply the files the document refers to — xi:include targets, the
33
+ * context document, the publication file, the docinfo source — from
34
+ * somewhere other than the platform: an in-memory project in a browser,
35
+ * an editor's unsaved buffers. Called with each file's absolute, normalized
36
+ * path; `undefined` falls through to the platform's own read (disk under
37
+ * Node, an absolute URL in the browser), so the reader can overlay just a
38
+ * few files or stand in for a filesystem entirely. See {@link SourceReader}.
39
+ *
40
+ * This is what lets the browser build resolve `xi:include`s at all, and
41
+ * what the per-file parse cache (`cache`) keys on: hand it the same string
42
+ * for an unchanged file and that file is not parsed again.
43
+ */
44
+ readSource?: SourceReader;
45
+ /**
46
+ * The same as `readSource`, as a map from absolute path to content, for
47
+ * hosts whose project simply is such a map. Consulted before `readSource`.
48
+ */
49
+ files?: Record<string, string>;
50
+ /**
51
+ * Reuse the parse of every file whose content has not changed since the
52
+ * last render (see source-cache.ts). On by default, with one cache shared
53
+ * by every render in the process; pass a {@link SourceCache} to scope it
54
+ * (one per project, say, so `invalidate()` has a clear meaning), or
55
+ * `false` to parse everything afresh each time.
56
+ *
57
+ * What it buys: a fragment preview placed in its document
58
+ * (`contextSourcePath`) and a division preview of a complete document
59
+ * (`subtree`) both parse the *whole* document to prune it to a skeleton;
60
+ * with the cache, a keystroke re-parses only the file being edited.
61
+ */
62
+ cache?: SourceCache | false;
63
+ }
64
+ export interface RenderOptions extends SourceOptions {
10
65
  /**
11
66
  * Path to the project's *main* source file — the one holding `<pretext>`.
12
67
  * Defaults to `sourcePath`, which is correct whenever a complete document is
@@ -21,19 +76,26 @@ export interface RenderOptions {
21
76
  */
22
77
  mainSourcePath?: string;
23
78
  /**
24
- * Source text to transform instead of reading `sourcePath` from disk.
25
- * `sourcePath` is still used to resolve relative xi:includes. Lets callers
26
- * render unsaved editor content.
27
- */
28
- sourceContent?: string;
29
- /**
30
- * Directory served to the transform for xi:includes and relative
31
- * references. Defaults to the directory containing `sourcePath`. Set it to
32
- * the project root when the publication file or includes live outside the
33
- * source directory. Files outside this directory are not readable by the
34
- * transform.
79
+ * Preview one division of the document instead of all of it — the one
80
+ * around the author's cursor (`line`, and `file` when that is not the file
81
+ * being rendered) or the one carrying an `id` — numbered and
82
+ * cross-referenced exactly as the whole document would be, by the same
83
+ * skeleton pruning a fragment placed in its document gets (see
84
+ * skeleton.ts). The cost of a render then tracks the division, not the
85
+ * document, which is what makes previewing a large single-file book as
86
+ * you type feasible at all.
87
+ *
88
+ * `level` chooses the page by PreTeXt's chunk-level rules, and
89
+ * `wholeDocumentUpTo` keeps small documents previewing whole; see
90
+ * {@link SubtreeOptions}. With `fragment` and a context document, the
91
+ * selection is made within the placed fragment (so a cursor line narrows
92
+ * the preview to the subsection it is in); without `subtree` the fragment's
93
+ * own root is the division, as before.
94
+ *
95
+ * Ignored when no division can be selected — the document then renders
96
+ * whole, and {@link RenderResult.subtree} is absent.
35
97
  */
36
- projectDir?: string;
98
+ subtree?: SubtreeOptions;
37
99
  /**
38
100
  * Path to a publication file. Its settings are respected except
39
101
  * `<html><platform portable="yes"/></html>`, which the preview forces.
@@ -246,9 +308,52 @@ export interface RenderOptions {
246
308
  */
247
309
  printPreview?: string;
248
310
  }
311
+ /** How big a document is, as {@link measureDocument} reports it. */
312
+ export interface DocumentSize {
313
+ /** Length of the xi:include-merged source, in UTF-16 code units. */
314
+ bytes: number;
315
+ /**
316
+ * Number of elements in the merged source. The better predictor of render
317
+ * time: PreTeXt's assembly walks the tree in a dozen passes, so cost tracks
318
+ * nodes rather than text. For scale, a small article is a few hundred, a
319
+ * long chapter a few thousand, a whole book tens of thousands.
320
+ */
321
+ elements: number;
322
+ /**
323
+ * Every file the document spans — the source first, then each xi:included
324
+ * file in the order first reached. What to watch for changes.
325
+ */
326
+ files: string[];
327
+ }
249
328
  export interface RenderResult {
250
329
  /** Complete standalone HTML page (CDN-hosted css/js/MathJax). */
251
330
  html: string;
331
+ /**
332
+ * The size of the document the render assembled — the whole context
333
+ * document for a fragment placed in it, the whole document for a `subtree`
334
+ * preview — before any pruning. What to compare against a threshold when
335
+ * deciding how much of a document to preview next time.
336
+ */
337
+ size: DocumentSize;
338
+ /**
339
+ * Present when one division was emitted rather than the whole document:
340
+ * `id` is its `xml:id`, which is also its HTML id on the page; `level` its
341
+ * numbering level; `collapsed` whether the divisions nested inside it were
342
+ * reduced to headings (see {@link SubtreeOptions.level}).
343
+ */
344
+ subtree?: {
345
+ id: string;
346
+ level: number;
347
+ collapsed: boolean;
348
+ /**
349
+ * When `collapsed`, the ids of the divisions the summary page lists, in
350
+ * document order — each the `xml:id` (authored or injected) its link
351
+ * names in `data-ptx-division`, and its id in the source map. A host
352
+ * following the cursor re-renders when it enters one of these. Empty
353
+ * for a division shown whole.
354
+ */
355
+ children: string[];
356
+ };
252
357
  /**
253
358
  * The conversion that actually ran — as asked for, or as detected. Lets an
254
359
  * embedder tell a deck from a document without re-inspecting the source,
@@ -293,6 +398,22 @@ export declare function defaultXslDir(): string;
293
398
  export declare function isJspiAvailable(): boolean;
294
399
  /** Quote a string as an XPath 1.0 string literal. */
295
400
  export declare function xpathStringLiteral(value: string): string;
401
+ /**
402
+ * The parse cache renders use when {@link SourceOptions.cache} is not given.
403
+ * Exposed so a host can drop it (`invalidate()`) or read its hit counts.
404
+ */
405
+ export declare function defaultSourceCache(): SourceCache;
406
+ /**
407
+ * Measure a document without rendering it: resolve its xi:includes and count.
408
+ * Cheap — with the parse cache warm, a copy of the tree and a walk — so a
409
+ * host can decide before each render whether to preview the whole document
410
+ * or one division of it (see {@link SubtreeOptions.wholeDocumentUpTo}), and
411
+ * learn which files to watch.
412
+ *
413
+ * Measures the document at `sourcePath` as given: to size the book a
414
+ * fragment belongs to, pass the main file.
415
+ */
416
+ export declare function measureDocument(options: SourceOptions): Promise<DocumentSize>;
296
417
  /**
297
418
  * Render a PreTeXt document to a single standalone HTML page.
298
419
  *
@@ -1,4 +1,9 @@
1
1
  import { Element, Root } from 'xast';
2
+ /**
3
+ * True for a division upstream will accept as a `subtree` root — the
4
+ * `&STRUCTURAL;` set, which is also what the skeleton keeps shells of.
5
+ */
6
+ export declare function isStructural(element: Element): boolean;
2
7
  /** A pruned document, ready to render as a fragment preview. */
3
8
  export interface Skeleton {
4
9
  /** The pruned document, serialized. */
@@ -7,16 +12,72 @@ export interface Skeleton {
7
12
  divisionId: string;
8
13
  /** That division's numbering level; pass as the `subtree-level` param. */
9
14
  level: number;
15
+ /**
16
+ * Whether the division's own child divisions were reduced to title shells
17
+ * (see {@link SkeletonOptions.collapseChildren}).
18
+ */
19
+ collapsed: boolean;
20
+ }
21
+ export interface SkeletonOptions {
22
+ /**
23
+ * Keep the previewed division's own content but reduce the divisions
24
+ * nested inside it to shells — a heading each, no prose — the way a
25
+ * chunked build's page for an intermediate division shows its introduction
26
+ * and then only a summary of what is below. What makes previewing a
27
+ * chapter's introduction cheap when the chapter itself is long.
28
+ *
29
+ * Cross-references from the kept content into a collapsed child still
30
+ * resolve: the child holding the target is stripped of text rather than
31
+ * emptied, exactly like any other target division.
32
+ */
33
+ collapseChildren?: boolean;
34
+ /**
35
+ * How deep the table of contents lists divisions (`tableofcontents/@level`
36
+ * in the publication file). Shells of divisions are kept down to this
37
+ * level everywhere in the document, so the preview's contents list is the
38
+ * built book's; deeper divisions survive only where numbering needs them.
39
+ * Defaults to PreTeXt's own default for the document's structure.
40
+ */
41
+ tocLevel?: number;
42
+ /**
43
+ * The level within which blocks — theorems, examples, figures, equations
44
+ * and the rest — are numbered (the `numbering/*​/@level` family in the
45
+ * publication file; the deepest of them, if they differ). Divisions deeper
46
+ * than this that precede the previewed division within its scope are kept
47
+ * with their text stripped, so the blocks in them are counted. Defaults to
48
+ * PreTeXt's own default for the document's structure.
49
+ */
50
+ numberingLevel?: number;
51
+ /**
52
+ * The deepest level anything is numbered to (`numbering/divisions/@level`),
53
+ * which caps `numberingLevel` and its default.
54
+ */
55
+ maxNumberingLevel?: number;
10
56
  }
57
+ /** Depth-first search for the element carrying `@xml:id` equal to `id`. */
58
+ export declare function findById(node: Root | Element, id: string): Element | undefined;
11
59
  /**
12
- * A division's numbering level, mirroring `mode="level"` in
13
- * pretext-numbers.xsl. `ancestors` runs from the document element down to (and
14
- * including) the division itself.
15
- *
16
- * `hasParts` is upstream's `$b-has-parts` (`boolean($root/book/part)`), which
17
- * pushes a book's chapters down a level.
60
+ * The chain of elements from the document root down to `target`, inclusive.
61
+ * Returns undefined when `target` is not in the tree.
62
+ */
63
+ export declare function pathTo(node: Root | Element, target: Element): Element[] | undefined;
64
+ /**
65
+ * A division's numbering level. `ancestors` runs from the document element
66
+ * down to (and including) the division itself.
18
67
  */
19
68
  export declare function divisionLevel(ancestors: Element[], hasParts: boolean): number;
69
+ /**
70
+ * PreTeXt's default table-of-contents depth for a document, by its structure
71
+ * — the `common/tableofcontents/pi:pub-attribute[@name='level']` default in
72
+ * publisher-variables.xsl.
73
+ */
74
+ export declare function defaultTocLevel(documentElement: Element | undefined): number;
75
+ /**
76
+ * PreTeXt's default numbering level for blocks, projects, equations, figures
77
+ * and footnotes, by the document's structure — `$default-numbering-level` in
78
+ * publisher-variables.xsl.
79
+ */
80
+ export declare function defaultNumberingLevel(documentElement: Element | undefined): number;
20
81
  /**
21
82
  * Swap the division carrying `id` for `replacement`, in place. Returns false
22
83
  * when the tree holds no such division.
@@ -38,4 +99,4 @@ export declare function replaceDivision(tree: Root, id: string, replacement: Ele
38
99
  * whose `@xml:id` is not yet in the main document, say — which the caller
39
100
  * should treat as "fall back to the standalone fragment wrapper".
40
101
  */
41
- export declare function buildSkeleton(tree: Root, divisionId: string): Skeleton | undefined;
102
+ export declare function buildSkeleton(tree: Root, divisionId: string, options?: SkeletonOptions): Skeleton | undefined;
@@ -0,0 +1,36 @@
1
+ import { Root, RootContent } from 'xast';
2
+ export interface SourceCacheOptions {
3
+ /**
4
+ * How many files to keep. The least recently used entry is evicted when a
5
+ * new file would exceed it. Defaults to 1024 — enough for any project with
6
+ * one file per division, which is the layout that produces the most files.
7
+ */
8
+ maxEntries?: number;
9
+ }
10
+ export declare class SourceCache {
11
+ private readonly entries;
12
+ private readonly maxEntries;
13
+ /** Cumulative hit/miss counts, for diagnostics and tests. */
14
+ hits: number;
15
+ misses: number;
16
+ constructor(options?: SourceCacheOptions);
17
+ /**
18
+ * The parse of `content`, as a fresh tree the caller may mutate freely.
19
+ * `key` names the file — a path — so that a changed file replaces its own
20
+ * entry instead of accumulating one per version.
21
+ *
22
+ * Throws what `fromXml` throws for malformed content; nothing is cached
23
+ * then.
24
+ */
25
+ parse(key: string, content: string): Root;
26
+ /** Number of files currently held. */
27
+ get size(): number;
28
+ /** Drop one file (when the host knows it is gone), or everything. */
29
+ invalidate(key?: string): void;
30
+ }
31
+ /**
32
+ * Deep-copy an xast tree. Positions are shared (nothing ever mutates them);
33
+ * attributes, children and `data` are copied, since the renderer mutates all
34
+ * three (tagging included roots, injecting an `xml:id`, splicing and pruning).
35
+ */
36
+ export declare function cloneTree<T extends Root | RootContent>(node: T): T;
@@ -1,4 +1,4 @@
1
- import { Root } from 'xast';
1
+ import { Element, Root } from 'xast';
2
2
  /** One element of the rendered document, in document order. */
3
3
  export interface SourceMapEntry {
4
4
  /** The element's @unique-id — its HTML id when the page emits one. */
@@ -32,6 +32,16 @@ export declare function computeSourceMap(tree: Root, rootFile: string, options?:
32
32
  parentId?: string;
33
33
  position?: number;
34
34
  }): PtxSourceMap;
35
+ /**
36
+ * The @unique-id pretext-assembly.xsl will stamp on `target` — authored or
37
+ * positional — or undefined when `target` is not in `tree` (or is foreign
38
+ * vocabulary, which is never stamped). Same walk and same seating as
39
+ * {@link computeSourceMap}.
40
+ */
41
+ export declare function stampedIdOf(tree: Root, target: Element, options?: {
42
+ parentId?: string;
43
+ position?: number;
44
+ }): string | undefined;
35
45
  /**
36
46
  * The entry to sync to for a cursor at `line`, given the entries of ONE file
37
47
  * in document order (start lines are non-decreasing within a file): the last
@@ -0,0 +1,79 @@
1
+ import { Element, Root } from 'xast';
2
+ export interface SubtreeOptions {
3
+ /**
4
+ * The `xml:id` of the element to preview. An element that is not itself a
5
+ * division selects the division enclosing it. Takes precedence over
6
+ * `file`/`line`.
7
+ */
8
+ id?: string;
9
+ /**
10
+ * The 1-based source line the author is at, selecting the innermost
11
+ * division containing it. A line outside every division (in the prolog or
12
+ * `<docinfo>`, say) selects the nearest division after it, else before it.
13
+ */
14
+ line?: number;
15
+ /**
16
+ * Which file `line` is in — an absolute path, as given to `sourcePath` and
17
+ * resolved the same way. Defaults to the file being rendered, which is the
18
+ * right answer for a single-file document; a line in an xi:included file
19
+ * needs its own path, since each file's lines start at 1.
20
+ */
21
+ file?: string;
22
+ /**
23
+ * Chunk level, with PreTeXt's meaning: the depth at which divisions become
24
+ * pages of their own (1 for chapters of a book or sections of an article,
25
+ * 2 one deeper, and so on). The preview is the page that would hold the
26
+ * selection in a build chunked at that level:
27
+ *
28
+ * - a selection deeper than `level` previews its ancestor at `level`,
29
+ * whole, since that whole ancestor is one page there;
30
+ * - a selection at `level` previews that division, whole;
31
+ * - a selection shallower than `level` — a chapter's introduction, say —
32
+ * previews that division as a summary page: its own content, then
33
+ * links to the divisions nested in it, since those are pages of their
34
+ * own and only summarized on the shallower page.
35
+ *
36
+ * Omitted, every division is a page of its own: the innermost division
37
+ * around the selection is previewed, as a summary page whenever it
38
+ * contains divisions. Only leaf divisions then render in full, and a
39
+ * cursor at the top of a book shows the book's front matter and a table
40
+ * of its chapters, not the book.
41
+ */
42
+ level?: number;
43
+ /**
44
+ * Render the whole document instead when it has no more than this many
45
+ * elements. Small documents preview whole as fast as any division of them
46
+ * would, and showing all of one is the better preview; this is the knob
47
+ * for "never show the entire document unless it is small". Counted on the
48
+ * xi:include-merged document, which {@link measureDocument} reports.
49
+ */
50
+ wholeDocumentUpTo?: number;
51
+ }
52
+ /** The division {@link selectDivision} chose. */
53
+ export interface SelectedDivision {
54
+ element: Element;
55
+ /** Its `xml:id` — authored, or injected (see {@link ensureXmlId}). */
56
+ id: string;
57
+ /** Whether its child divisions should be collapsed (see `level`). */
58
+ collapse: boolean;
59
+ }
60
+ /**
61
+ * Pick the division to preview (see the module comment). Returns undefined
62
+ * when the document has no division to pick — an `id` that names nothing,
63
+ * a file with no divisions — which the caller should treat as "render the
64
+ * whole document".
65
+ */
66
+ export declare function selectDivision(tree: Root, options: SubtreeOptions,
67
+ /** The file the tree's root was parsed from; what `file` defaults to. */
68
+ defaultFile: string): SelectedDivision | undefined;
69
+ /**
70
+ * The element's `xml:id`, injecting one when it has none — the very id
71
+ * pretext-assembly.xsl would stamp on it anyway (`parent-id + "-" +
72
+ * position`), so the rendered page's ids, and with them the source map and
73
+ * in-place patching, are the same as without the injection. Needed because
74
+ * both upstream's `subtree` parameter and the skeleton address a division
75
+ * by `xml:id`, and most divisions in a single-file document carry none.
76
+ */
77
+ export declare function ensureXmlId(tree: Root, element: Element): string;
78
+ /** Number of elements in the tree — what the assembly passes' cost tracks. */
79
+ export declare function countElements(tree: Root | Element): number;
@@ -1,10 +1,34 @@
1
1
  import { Element, Root } from 'xast';
2
+ import { SourceCache } from './source-cache.js';
3
+ /**
4
+ * How a file the document refers to is read: by absolute, normalized path
5
+ * (as `path.resolve` spells it on the platform — posix in the browser build),
6
+ * returning its text, or `undefined` for a file that does not exist.
7
+ *
8
+ * Lets a host that holds its project in memory — a browser editor, an
9
+ * extension with unsaved buffers — supply files without a filesystem.
10
+ * Returning `undefined` falls through to the host platform's own read (the
11
+ * disk under Node, an absolute URL in the browser), so a reader can also just
12
+ * overlay a few files on top of what is there.
13
+ */
14
+ export type SourceReader = (file: string) => Promise<string | undefined> | string | undefined;
15
+ /** Options shared by everything that resolves includes. */
16
+ export interface ResolveOptions {
17
+ /** See {@link SourceReader}. */
18
+ readSource?: SourceReader;
19
+ /** Reuse parses of unchanged files across calls (see source-cache.ts). */
20
+ cache?: SourceCache;
21
+ }
22
+ /**
23
+ * Read a file through the caller's reader first, then the platform's.
24
+ */
25
+ export declare function readWith(options: ResolveOptions | undefined, file: string): Promise<string | undefined>;
2
26
  /**
3
27
  * Return `sourceContent` with every xi:include replaced by the contents of
4
28
  * the referenced files. `sourcePath` anchors relative hrefs; `projectDir`
5
29
  * bounds which files may be included.
6
30
  */
7
- export declare function resolveXIncludes(sourceContent: string, sourcePath: string, projectDir: string): Promise<string>;
31
+ export declare function resolveXIncludes(sourceContent: string, sourcePath: string, projectDir: string, options?: ResolveOptions): Promise<string>;
8
32
  /** Result of resolveXIncludesToTree. */
9
33
  export interface ResolvedTree {
10
34
  /**
@@ -16,18 +40,31 @@ export interface ResolvedTree {
16
40
  tree: Root;
17
41
  /** The merged document serialized, as resolveXIncludes would return it. */
18
42
  content: string;
43
+ /**
44
+ * Every file the document spans — the source itself first, then each
45
+ * xi:included file in the order first reached. What a host should watch
46
+ * for changes that affect this document.
47
+ */
48
+ files: string[];
49
+ /**
50
+ * Total length of those files' contents: the size of the merged document,
51
+ * near enough, without serializing it.
52
+ */
53
+ bytes: number;
19
54
  }
20
55
  /**
21
56
  * Like resolveXIncludes, but also return the merged tree with per-file
22
57
  * position attribution, for source-map computation.
23
58
  */
24
- export declare function resolveXIncludesToTree(sourceContent: string, sourcePath: string, projectDir: string): Promise<ResolvedTree>;
59
+ export declare function resolveXIncludesToTree(sourceContent: string, sourcePath: string, projectDir: string, options?: ResolveOptions): Promise<ResolvedTree>;
25
60
  /**
26
61
  * File a spliced-in element was parsed from, tagged by expandInclude.
27
62
  * Undefined for nodes of the file being resolved (callers track that file
28
63
  * themselves). Stored on the unist `data` field, which serializers ignore.
29
64
  */
30
65
  export declare function includedFileOf(element: Element): string | undefined;
66
+ /** Record that `element` was parsed from `file` (see includedFileOf). */
67
+ export declare function tagIncludedFile(element: Element, file: string): void;
31
68
  /**
32
69
  * Extract the `<docinfo>` element from a complete PreTeXt source file as an XML
33
70
  * string, resolving xi:includes along the way. Handles the two shapes authors
@@ -42,4 +79,4 @@ export declare function includedFileOf(element: Element): string | undefined;
42
79
  * macros beats a failed render). `mainPath` anchors relative hrefs;
43
80
  * `projectDir` bounds which files may be read.
44
81
  */
45
- export declare function extractDocinfo(mainContent: string, mainPath: string, projectDir: string): Promise<string | undefined>;
82
+ export declare function extractDocinfo(mainContent: string, mainPath: string, projectDir: string, options?: ResolveOptions): Promise<string | undefined>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pretextbook/pretext-html",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Convert PreTeXt documents to HTML in pure JavaScript using the official PreTeXt XSLT stylesheets via libxslt-wasm. No Python or PreTeXt installation required.",
5
5
  "author": "Oscar Levin",
6
6
  "license": "MIT",