@pretextbook/pretext-html 0.1.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 (110) hide show
  1. package/README.md +160 -0
  2. package/assets/preview-html.xsl +230 -0
  3. package/assets/upstream.json +7 -0
  4. package/assets/xsl/README.md +31 -0
  5. package/assets/xsl/entities.ent +154 -0
  6. package/assets/xsl/extract-asymptote.xsl +68 -0
  7. package/assets/xsl/extract-biblio-csl.xsl +327 -0
  8. package/assets/xsl/extract-datafile.xsl +71 -0
  9. package/assets/xsl/extract-dynamic.xsl +139 -0
  10. package/assets/xsl/extract-identity.xsl +136 -0
  11. package/assets/xsl/extract-interactive.xsl +81 -0
  12. package/assets/xsl/extract-latex-image.xsl +118 -0
  13. package/assets/xsl/extract-mermaid.xsl +58 -0
  14. package/assets/xsl/extract-mom.xsl +63 -0
  15. package/assets/xsl/extract-pg.xsl +2897 -0
  16. package/assets/xsl/extract-prefigure.xsl +157 -0
  17. package/assets/xsl/extract-qrcode.xsl +100 -0
  18. package/assets/xsl/extract-runestone-page-template.xsl +139 -0
  19. package/assets/xsl/extract-sageplot.xsl +166 -0
  20. package/assets/xsl/extract-stack.xsl +56 -0
  21. package/assets/xsl/extract-trace.xsl +134 -0
  22. package/assets/xsl/extract-youtube.xsl +63 -0
  23. package/assets/xsl/html-symbols.xsl +3344 -0
  24. package/assets/xsl/latex/pretext-latex-AIM.xsl +56 -0
  25. package/assets/xsl/latex/pretext-latex-CLP.xsl +148 -0
  26. package/assets/xsl/latex/pretext-latex-chaos.xsl +317 -0
  27. package/assets/xsl/latex/pretext-latex-dyslexic-font.xsl +76 -0
  28. package/assets/xsl/latex/pretext-latex-guide.xsl +104 -0
  29. package/assets/xsl/latex/pretext-latex-texstyle.xsl +862 -0
  30. package/assets/xsl/localizations/README.md +56 -0
  31. package/assets/xsl/localizations/af-ZA.xml +276 -0
  32. package/assets/xsl/localizations/bg-BG.xml +276 -0
  33. package/assets/xsl/localizations/ca-ES.xml +285 -0
  34. package/assets/xsl/localizations/cs-CZ.xml +280 -0
  35. package/assets/xsl/localizations/de-DE.xml +281 -0
  36. package/assets/xsl/localizations/en-US.xml +427 -0
  37. package/assets/xsl/localizations/es-ES.xml +287 -0
  38. package/assets/xsl/localizations/fi-FI.xml +275 -0
  39. package/assets/xsl/localizations/fr-CA.xml +276 -0
  40. package/assets/xsl/localizations/fr-FR.xml +280 -0
  41. package/assets/xsl/localizations/hu-HU.xml +280 -0
  42. package/assets/xsl/localizations/it-IT.xml +276 -0
  43. package/assets/xsl/localizations/ku-CKB.xml +275 -0
  44. package/assets/xsl/localizations/localizations.xml +48 -0
  45. package/assets/xsl/localizations/nl-NL.xml +275 -0
  46. package/assets/xsl/localizations/pt-BR.xml +288 -0
  47. package/assets/xsl/localizations/pt-PT.xml +292 -0
  48. package/assets/xsl/localizations/zh-HANS.xml +269 -0
  49. package/assets/xsl/pretext-assembly.xsl +4795 -0
  50. package/assets/xsl/pretext-basic-html.xsl +86 -0
  51. package/assets/xsl/pretext-beamer.xsl +662 -0
  52. package/assets/xsl/pretext-braille-preprint.xsl +2249 -0
  53. package/assets/xsl/pretext-common.xsl +12018 -0
  54. package/assets/xsl/pretext-dynamic.xsl +65 -0
  55. package/assets/xsl/pretext-epub.xsl +1483 -0
  56. package/assets/xsl/pretext-fo.xsl +4593 -0
  57. package/assets/xsl/pretext-html.xsl +14791 -0
  58. package/assets/xsl/pretext-json-manifest.xsl +150 -0
  59. package/assets/xsl/pretext-jupyter.xsl +868 -0
  60. package/assets/xsl/pretext-latex-classic.xsl +952 -0
  61. package/assets/xsl/pretext-latex-common.xsl +11563 -0
  62. package/assets/xsl/pretext-latex.xsl +47 -0
  63. package/assets/xsl/pretext-litprog.xsl +105 -0
  64. package/assets/xsl/pretext-merge.xsl +41 -0
  65. package/assets/xsl/pretext-numbers.xsl +875 -0
  66. package/assets/xsl/pretext-revealjs.xsl +522 -0
  67. package/assets/xsl/pretext-runestone-fitb.xsl +1233 -0
  68. package/assets/xsl/pretext-runestone-static.xsl +1438 -0
  69. package/assets/xsl/pretext-runestone.xsl +3083 -0
  70. package/assets/xsl/pretext-sage-doctest.xsl +289 -0
  71. package/assets/xsl/pretext-smc.xsl +492 -0
  72. package/assets/xsl/pretext-solution-manual-latex.xsl +323 -0
  73. package/assets/xsl/pretext-text-utilities.xsl +1217 -0
  74. package/assets/xsl/pretext-text.xsl +392 -0
  75. package/assets/xsl/pretext-units.xsl +195 -0
  76. package/assets/xsl/pretext-view-source.xsl +157 -0
  77. package/assets/xsl/pretext-ww-problem-sets.xsl +391 -0
  78. package/assets/xsl/publisher-variables.xsl +4756 -0
  79. package/assets/xsl/support/README.md +22 -0
  80. package/assets/xsl/support/extract-math.xsl +256 -0
  81. package/assets/xsl/support/package-math.xsl +141 -0
  82. package/assets/xsl/support/play-button/README.md +46 -0
  83. package/assets/xsl/support/play-button/play-button.png +0 -0
  84. package/assets/xsl/support/play-button/play-button.svg +3 -0
  85. package/assets/xsl/support/pretext-pg-macros.xsl +110 -0
  86. package/assets/xsl/support/webpack_static_imports.xml +14 -0
  87. package/assets/xsl/tests/README.md +24 -0
  88. package/assets/xsl/tests/null.xml +4 -0
  89. package/assets/xsl/tests/pretext-text-utilities-test.xsl +334 -0
  90. package/assets/xsl/utilities/README.md +31 -0
  91. package/assets/xsl/utilities/author-report.xsl +107 -0
  92. package/assets/xsl/utilities/deprecate-autoname.sed +18 -0
  93. package/assets/xsl/utilities/deprecate-index.sed +33 -0
  94. package/assets/xsl/utilities/fix-deprecations.xsl +663 -0
  95. package/assets/xsl/utilities/pretext-enhanced-source.xsl +112 -0
  96. package/assets/xsl/utilities/report-publisher-variables.xsl +162 -0
  97. package/assets/xsl/xml-to-json.xsl +326 -0
  98. package/assets/xsl/xml-to-string.xsl +328 -0
  99. package/cli.mjs +29 -0
  100. package/dist/cli-C6tfAVvi.js +553 -0
  101. package/dist/cli.d.ts +10 -0
  102. package/dist/cli.js +7 -0
  103. package/dist/index.d.ts +6 -0
  104. package/dist/index.js +10 -0
  105. package/dist/mounts.d.ts +23 -0
  106. package/dist/publication.d.ts +16 -0
  107. package/dist/renderer.d.ts +84 -0
  108. package/dist/sourcemap.d.ts +41 -0
  109. package/dist/xinclude.d.ts +45 -0
  110. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @pretextbook/pretext-html
2
+
3
+ Convert [PreTeXt](https://pretextbook.org) documents to HTML in pure
4
+ JavaScript — no Python, no PreTeXt installation. This runs the **official,
5
+ unmodified PreTeXt XSLT stylesheets** with
6
+ [`@pretextbook/libxslt-wasm`](https://github.com/oscarlevin/libxslt-wasm), a
7
+ WebAssembly build of libxml2/libxslt/libexslt (the same C libraries the Python
8
+ CLI uses via lxml), so the HTML matches a real `pretext build`. It is a fork of
9
+ [jeremy-code/libxslt-wasm](https://github.com/jeremy-code/libxslt-wasm) built
10
+ with a larger WASM stack so whole-book documents render without overflowing
11
+ (see [Forking libxslt-wasm](#forking-libxslt-wasm)).
12
+
13
+ The output is a single, standalone HTML page: PreTeXt's _portable HTML_ mode
14
+ is forced on, so theme css/js and MathJax load from public CDNs and the whole
15
+ document is rendered as one page. This is what powers the "Instant Preview"
16
+ in the PreTeXt-tools VS Code extension, and it is published so other tools
17
+ (e.g. pretext.plus) can render previews the same way.
18
+
19
+ ## Usage
20
+
21
+ ### CLI
22
+
23
+ ```sh
24
+ npx @pretextbook/pretext-html source/main.ptx \
25
+ --project-dir . \
26
+ --publication publication/publication.ptx \
27
+ -o preview.html
28
+ ```
29
+
30
+ HTML goes to stdout (or `--output`); diagnostics (`PTX:WARNING`, `PTX:ERROR`,
31
+ deprecation notices) go to stderr. Run `pretext-html --help` for all options.
32
+
33
+ The CLI relaunches itself with `--experimental-wasm-jspi` automatically (see
34
+ [Requirements](#requirements)).
35
+
36
+ ### API (Node)
37
+
38
+ ```js
39
+ import { renderHtml } from "@pretextbook/pretext-html";
40
+
41
+ const { html } = await renderHtml({
42
+ sourcePath: "source/main.ptx", // root document
43
+ projectDir: ".", // directory the transform may read from
44
+ publicationPath: "publication/publication.ptx", // optional
45
+ stringParams: {}, // optional extra XSLT stringparams
46
+ });
47
+ ```
48
+
49
+ - `sourceContent` lets you render unsaved editor text (with `sourcePath` still
50
+ anchoring relative `xi:include`s).
51
+ - `fragment: true` renders a non-root file (a lone `<section>`, `<chapter>`, …)
52
+ by wrapping it in a minimal `<pretext>` document. To keep the project's LaTeX
53
+ macros and custom settings, give it the docinfo: either `docinfoSourcePath`
54
+ (the project main file, whose `<docinfo>` is lifted out — resolving
55
+ `xi:include`s, including a docinfo that is itself included), or `docinfo` (a
56
+ `<docinfo>` element as a string, if you already have it). Both are ignored
57
+ for complete documents, which carry their own docinfo.
58
+ - `sourceMap: true` additionally returns a **source map** for editor/preview
59
+ sync: one entry per element, in document order, mapping the element's HTML
60
+ id to the source `file`/`line` it was authored in — through `xi:include`s.
61
+ This works because HTML ids are the `@unique-id` values that
62
+ `pretext-assembly.xsl` stamps with a deterministic walk
63
+ (`@label ?? @xml:id ?? parent-id + "-" + sibling-position`), which is
64
+ replicated over the merged tree in JS; the rendered page itself is
65
+ unchanged. Entries carry a `parent` id so clients can fall outward when an
66
+ element has no HTML id of its own, and `findSourceMapEntry(entries, line)`
67
+ picks the element nearest a cursor line. (This powers the two-way sync in
68
+ the VS Code Instant Preview; the same map works for any embedder.)
69
+ - The user's publication file is respected, except
70
+ `<html><platform portable="yes"/></html>` is always forced — that is what
71
+ makes single-page in-memory output possible.
72
+ - The compiled stylesheet is cached per `xslDir` (~1s to compile, then
73
+ ~100ms–1s per render depending on document size).
74
+
75
+ ## Requirements
76
+
77
+ - **Node ≥ 22** launched with **`--experimental-wasm-jspi`** (WebAssembly
78
+ stack switching). The flag is not allowed in `NODE_OPTIONS`; it must be on
79
+ the command line. The `pretext-html` CLI re-executes itself with the flag;
80
+ API users must supply it themselves (in tests, vitest's `execArgv` option
81
+ works — see `vite.config.mts`).
82
+ - Runtimes with V8 ≥ 13.7 (Chromium/Electron ≥ 137, and eventually Node
83
+ itself) ship JSPI **enabled by default and reject the flag** as a bad
84
+ option. Feature-detect with `"Suspending" in WebAssembly` (exported as
85
+ `isJspiAvailable()`) before adding the flag rather than assuming it is
86
+ needed.
87
+ - Network access _for the rendered page_ (theme css/js and MathJax come from
88
+ `cdn.jsdelivr.net`). The transform itself runs fully offline.
89
+
90
+ ## How it works
91
+
92
+ 1. **Vendored stylesheets** — `assets/xsl/` is a snapshot of the upstream
93
+ [`pretext/xsl`](https://github.com/PreTeXtBook/pretext/tree/master/xsl)
94
+ tree (GPL-licensed; see `assets/xsl/LICENSE-pretext`). Refresh with
95
+ `npm run refresh:xsl` from the monorepo root.
96
+ 2. **Generated wrapper** — `assets/preview-html.xsl` imports `pretext-html.xsl`
97
+ and overrides the `file-wrap` template with a verbatim copy minus its
98
+ `<exsl:document>` wrapper, so the complete page (head, theme links,
99
+ masthead, content) lands on the main result tree instead of on disk. All
100
+ other file-writing templates are stubbed. The wrapper is **generated** by
101
+ `scripts/refresh-xsl.mjs`, which also audits every `exsl:document` site
102
+ reachable from `pretext-html.xsl` and fails if upstream adds a writer we
103
+ don't cover.
104
+ 3. **Virtual-host fetch shim** — the WASM build has no filesystem
105
+ (`FILESYSTEM=0`); every resource load (stylesheet imports, `document()`
106
+ calls, the publication file) goes through the global `fetch`. We mount
107
+ fake origins like `http://mnt1.ptx.invalid` backed by local directories
108
+ and in-memory strings — no HTTP server involved.
109
+ 4. **JS XInclude** — `xi:include` is resolved in JavaScript before parsing
110
+ (libxml2's own XInclude pass cannot suspend in the current WASM build).
111
+ Supports nested includes, `parse="text"`, and `xi:fallback`; `xpointer` is
112
+ not supported.
113
+
114
+ ## Limitations (current WASM build)
115
+
116
+ | Limitation | Cause | Fix |
117
+ | ---------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
118
+ | No multi-file output (`exsl:document`) | Compiled with `FILESYSTEM=0` | Rebuild with `FILESYSTEM=1` (files land in MEMFS) |
119
+ | Node only, JSPI flag required | Loader fetches resources mid-transform via JSPI | Preload stylesheets into MEMFS at init, or wait for JSPI to ship unflagged |
120
+ | No generated images (latex-image, sageplot, …) | Produced by the Python toolchain, not XSLT | Out of scope; run `pretext generate` and the preview will pick the files up |
121
+ | `xi:include` with `xpointer` unsupported | JS resolver stands in for libxml2's | Rebuild adding `xmlXIncludeProcessFlags` to the JSPI export list |
122
+
123
+ The whole-book stack overflow ("memory access out of bounds") that the stock
124
+ `libxslt-wasm` build hit on large documents is **fixed** in the
125
+ `@pretextbook/libxslt-wasm` fork, which links with a larger WASM stack.
126
+
127
+ Missing generated assets degrade gracefully: the transform serves a stub for
128
+ missing files, PreTeXt emits its usual `PTX:ERROR` advice, and the preview
129
+ renders without the image.
130
+
131
+ ## Forking libxslt-wasm
132
+
133
+ This package depends on [`@pretextbook/libxslt-wasm`](https://github.com/oscarlevin/libxslt-wasm),
134
+ a fork of [jeremy-code/libxslt-wasm](https://github.com/jeremy-code/libxslt-wasm)
135
+ (MIT) rebuilt with different Emscripten link flags. The remaining limitations
136
+ above are also flag changes, not architecture — when ready to tackle them:
137
+
138
+ - `-sSTACK_SIZE` (already raised in the fork) — fixes whole-book stack
139
+ overflows; pair with `-sALLOW_MEMORY_GROWTH=1`.
140
+ - `-sFILESYSTEM=1` — enables `exsl:document` writes into in-memory MEMFS,
141
+ readable back from JS; unlocks real multi-file builds.
142
+ - Add `xmlXIncludeProcessFlags` to the JSPI exports list (the `Asyncify`/JSPI
143
+ `exportPattern` — see `ASYNCIFY_EXPORTS` in the build) so native XInclude can
144
+ suspend for fetches; then the JS resolver in `src/xinclude.ts` can be retired.
145
+ - To drop the JSPI requirement entirely (needed for Firefox/Safari/browser
146
+ use): preload `assets/xsl/` into MEMFS at module init so no fetch happens
147
+ mid-transform, and switch the entity loader to synchronous MEMFS reads.
148
+
149
+ **Refreshing the fork:** rebuild the WASM in the fork, `npm version` + `npm
150
+ publish` it, then bump the `@pretextbook/libxslt-wasm` version in this
151
+ package's `package.json`. Everything else — wrapper stylesheet, mounts, API —
152
+ stays the same.
153
+
154
+ ## Development
155
+
156
+ ```sh
157
+ npm run build -w @pretextbook/pretext-html # vite build to dist/
158
+ npm run test -w @pretextbook/pretext-html # vitest (JSPI via execArgv)
159
+ npm run refresh:xsl # re-vendor xsl + regenerate wrapper (from repo root)
160
+ ```
@@ -0,0 +1,230 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ GENERATED FILE - do not edit by hand.
4
+ Regenerate with: npm run refresh-xsl -w @pretextbook/pretext-html
5
+
6
+ Wrapper around pretext-html.xsl for single-page in-memory HTML builds
7
+ (previews). The "file-wrap" template below is a verbatim copy of the
8
+ upstream template with the <exsl:document> element removed, so the complete
9
+ page is emitted on the main result tree. Intended to be applied together
10
+ with a publication file that sets <html><platform portable="yes"/></html>,
11
+ which forces chunk level 0 (one page) and CDN-hosted css/js, and suppresses
12
+ most auxiliary file output. Remaining file writers are stubbed at the end.
13
+ -->
14
+ <xsl:stylesheet
15
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
16
+ xmlns:xml="http://www.w3.org/XML/1998/namespace"
17
+ xmlns:svg="http://www.w3.org/2000/svg"
18
+ xmlns:xlink="http://www.w3.org/1999/xlink"
19
+ xmlns:pi="http://pretextbook.org/2020/pretext/internal"
20
+ xmlns:exsl="http://exslt.org/common"
21
+ xmlns:date="http://exslt.org/dates-and-times"
22
+ xmlns:str="http://exslt.org/strings"
23
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
24
+ xmlns:pf="https://prefigure.org"
25
+ exclude-result-prefixes="svg xlink pi fn pf"
26
+ extension-element-prefixes="exsl date str"
27
+ >
28
+
29
+ <xsl:import href="pretext-html.xsl"/>
30
+ <xsl:output method="html" encoding="UTF-8" doctype-system="about:legacy-compat"/>
31
+
32
+ <!-- Copied from pretext-html.xsl (mode="file-wrap"), exsl:document removed -->
33
+ <xsl:template match="*" mode="file-wrap">
34
+ <xsl:param name="content" />
35
+ <xsl:param name="title" select="''"/>
36
+ <xsl:param name="filename" select="''"/>
37
+ <xsl:param name="b-has-printout" select="false()"/>
38
+ <xsl:param name="b-include-bottom-nav" select="true()"/>
39
+
40
+ <xsl:variable name="the-filename">
41
+ <xsl:choose>
42
+ <xsl:when test="not($filename = '')">
43
+ <xsl:value-of select="$filename"/>
44
+ </xsl:when>
45
+ <xsl:otherwise>
46
+ <xsl:apply-templates select="." mode="containing-filename" />
47
+ </xsl:otherwise>
48
+ </xsl:choose>
49
+ </xsl:variable>
50
+
51
+
52
+ <xsl:call-template name="converter-blurb-html-no-date"/>
53
+ <html>
54
+ <xsl:call-template name="language-attributes"/>
55
+ <xsl:call-template name="html-theme-attributes"/>
56
+ <xsl:call-template name="pretext-advertisement-and-style"/>
57
+ <!-- Open Graph Protocol only in "meta" elements, within "head" -->
58
+ <head xmlns:og="http://ogp.me/ns#" xmlns:book="https://ogp.me/ns/book#">
59
+ <!-- optional head content that needs to come prior to other content -->
60
+ <xsl:apply-templates select="." mode="file-wrap-head-pre"/>
61
+ <title>
62
+ <xsl:choose>
63
+ <xsl:when test="$title != ''">
64
+ <xsl:value-of select="$title"/>
65
+ </xsl:when>
66
+ <xsl:otherwise>
67
+ <!-- Leading with initials is useful for small tabs -->
68
+ <xsl:if test="$docinfo/initialism">
69
+ <xsl:apply-templates select="$docinfo/initialism" />
70
+ <xsl:text> </xsl:text>
71
+ </xsl:if>
72
+ <xsl:apply-templates select="." mode="title-plain" />
73
+ </xsl:otherwise>
74
+ </xsl:choose>
75
+ </title>
76
+ <!-- canonical link for better SEO -->
77
+ <xsl:call-template name="canonical-link">
78
+ <xsl:with-param name="filename" select="$the-filename"/>
79
+ </xsl:call-template>
80
+ <!-- grab the contents every page gets -->
81
+ <xsl:copy-of select="$file-wrap-full-head-cache"/>
82
+ <!-- now do anything that is or could be page-specific and comes after cache -->
83
+ <xsl:apply-templates select="." mode="knowl" />
84
+ <!-- webwork's iframeResizer needs to come before sagecell template -->
85
+ <xsl:apply-templates select="." mode="sagecell" />
86
+ <!-- optional head content that might override other content-->
87
+ <xsl:apply-templates select="." mode="file-wrap-head-post"/>
88
+ </head>
89
+ <body>
90
+ <xsl:if test="$b-has-stack">
91
+ <xsl:attribute name="onload">
92
+ <xsl:text>docHasLoaded()</xsl:text>
93
+ </xsl:attribute>
94
+ </xsl:if>
95
+
96
+ <!-- potential document-id per-page -->
97
+ <xsl:call-template name="document-id"/>
98
+ <!-- React flag -->
99
+ <xsl:call-template name="react-in-use-flag"/>
100
+ <!-- the first class controls the default icon -->
101
+ <xsl:attribute name="class">
102
+ <xsl:choose>
103
+ <xsl:when test="$root/book">pretext book</xsl:when>
104
+ <xsl:when test="$root/article">pretext article</xsl:when>
105
+ </xsl:choose>
106
+ <xsl:apply-templates select="." mode="file-wrap-body-attr-extra"/>
107
+ <!-- ignore MathJax signals everywhere, then enable selectively -->
108
+ <xsl:text> ignore-math</xsl:text>
109
+ </xsl:attribute>
110
+ <!-- assistive "Skip to main content" link -->
111
+ <!-- this *must* be first for maximum utility -->
112
+ <xsl:call-template name="skip-to-content-link" />
113
+ <!-- HTML5 body/header will be a "banner" landmark automatically -->
114
+ <header id="ptx-masthead" class="ptx-masthead">
115
+ <div class="ptx-banner">
116
+ <xsl:call-template name="brand-logo" />
117
+ <div class="title-container">
118
+ <h1 class="heading">
119
+ <xsl:variable name="root-filename">
120
+ <xsl:apply-templates select="$document-root" mode="containing-filename" />
121
+ </xsl:variable>
122
+ <a href="{$root-filename}">
123
+ <xsl:variable name="b-has-subtitle" select="boolean($document-root/subtitle)"/>
124
+ <span class="title">
125
+ <!-- Do not use shorttitle in masthead, -->
126
+ <!-- which is much like cover of a book -->
127
+ <xsl:apply-templates select="$document-root" mode="title-simple" />
128
+ </span>
129
+ <xsl:if test="$b-has-subtitle and $b-html-banner-subtitle">
130
+ <xsl:text> </xsl:text>
131
+ <span class="subtitle">
132
+ <xsl:apply-templates select="$document-root" mode="subtitle" />
133
+ </span>
134
+ </xsl:if>
135
+ </a>
136
+ </h1>
137
+ <!-- Serial list of authors/editors -->
138
+ <xsl:if test="$b-html-banner-byline">
139
+ <p class="byline">
140
+ <xsl:apply-templates select="$bibinfo/author" mode="name-list"/>
141
+ <xsl:apply-templates select="$bibinfo/editor" mode="name-list"/>
142
+ </p>
143
+ </xsl:if>
144
+ </div> <!-- title-container -->
145
+ </div> <!-- banner -->
146
+ </header> <!-- masthead -->
147
+ <xsl:apply-templates select="." mode="primary-navigation"/>
148
+ <xsl:apply-templates select="." mode="latex-macros"/>
149
+ <div class="ptx-page">
150
+ <xsl:apply-templates select="." mode="sidebars" />
151
+ <!-- HTML5 main will be a "main" landmark automatically -->
152
+ <main class="ptx-main">
153
+ <xsl:if test="$b-watermark">
154
+ <xsl:attribute name="style">
155
+ <xsl:value-of select="$watermark-css"/>
156
+ </xsl:attribute>
157
+ </xsl:if>
158
+ <div id="ptx-content" class="ptx-content">
159
+ <xsl:if test="$b-has-printout">
160
+ <xsl:apply-templates select="." mode="print-preview-header"/>
161
+ </xsl:if>
162
+ <!-- Alternative to "copy-of": convert $content to a -->
163
+ <!-- node-set, and then hit with an identity template -->
164
+ <!-- to duplicate. Experiment indicates no change in -->
165
+ <!-- output. (2023-01-11) -->
166
+ <xsl:copy-of select="$content" />
167
+ </div>
168
+ <xsl:if test="$b-include-bottom-nav">
169
+ <div id="ptx-content-footer" class="ptx-content-footer">
170
+ <xsl:apply-templates select="." mode="previous-button"/>
171
+ <xsl:variable name="top-localization">
172
+ <xsl:apply-templates select="." mode="type-name">
173
+ <xsl:with-param name="string-id" select="'top'"/>
174
+ </xsl:apply-templates>
175
+ </xsl:variable>
176
+ <a class="top-button button" href="#" title="{$top-localization}">
177
+ <xsl:call-template name="insert-symbol">
178
+ <xsl:with-param name="name" select="'expand_less'"/>
179
+ </xsl:call-template>
180
+ <span class="name">
181
+ <xsl:value-of select="$top-localization"/>
182
+ </span>
183
+ </a>
184
+ <xsl:apply-templates select="." mode="next-button"/>
185
+ </div>
186
+ </xsl:if>
187
+ </main>
188
+ </div>
189
+ <!-- formerly "extra" -->
190
+ <div id="ptx-page-footer" class="ptx-page-footer">
191
+ <xsl:apply-templates select="." mode="feedback-button"/>
192
+ <xsl:call-template name="pretext-link" />
193
+ <xsl:call-template name="runestone-link"/>
194
+ <xsl:call-template name="mathjax-link" />
195
+ </div>
196
+ <xsl:copy-of select="$file-wrap-full-endbody-cache"/>
197
+ <!-- For portable builds we stash the lunr search here -->
198
+ <xsl:if test="$b-portable-html and $has-native-search">
199
+ <xsl:call-template name="embedded-search-construction"/>
200
+ </xsl:if>
201
+ <!-- optional body content that needs to be inserted after all content -->
202
+ <!-- e.g. script tags to run immediately -->
203
+ <xsl:apply-templates select="." mode="file-wrap-body-post"/>
204
+ </body>
205
+ </html>
206
+
207
+ </xsl:template>
208
+
209
+ <!-- Stub out the remaining file writers (every other template reachable -->
210
+ <!-- from pretext-html.xsl that contains exsl:document). Under portable- -->
211
+ <!-- html several of these are already suppressed; the stubs cover the -->
212
+ <!-- rest and act as a safety net if publication settings change. Any -->
213
+ <!-- exsl:document that does fire aborts the FILESYSTEM=0 WASM build. -->
214
+ <xsl:template name="index-redirect-page"/>
215
+ <xsl:template match="*" mode="manufacture-knowl"/>
216
+ <xsl:template name="ol-marker-styles"/>
217
+ <xsl:template name="doc-manifest"/>
218
+ <xsl:template name="search-page-construction"/>
219
+ <xsl:template name="scorm-manifest"/>
220
+ <!-- standalone pages for videos and iframe pages for interactives -->
221
+ <xsl:template match="*" mode="standalone-page"/>
222
+ <xsl:template match="*" mode="create-iframe-page"/>
223
+ <!-- runestone-manifest lives in pretext-runestone.xsl -->
224
+ <xsl:template match="*" mode="runestone-manifest"/>
225
+ <xsl:template match="*" mode="simple-file-wrap">
226
+ <xsl:param name="content"/>
227
+ <xsl:copy-of select="$content"/>
228
+ </xsl:template>
229
+
230
+ </xsl:stylesheet>
@@ -0,0 +1,7 @@
1
+ {
2
+ "source": {
3
+ "repository": "PreTeXtBook/pretext",
4
+ "ref": "master"
5
+ },
6
+ "refreshed": "2026-07-08T00:48:30.933Z"
7
+ }
@@ -0,0 +1,31 @@
1
+ # eXtensible Stylesheet Language (XSL) Stylesheets
2
+
3
+ XSL stylesheets are the primary vehicle for converting PreTeXt XML
4
+ source into various output formats. As such, they are sometimes
5
+ simply called "conversions." Here we list **some** of the available
6
+ conversions, the list is not exhaustive. See _The PreTeXt Guide_
7
+ for detailed documentation of use, in chapters of the part
8
+ titled _Publisher's Guide_.
9
+
10
+ - `pretext-latex.xsl` - conversion to LaTeX, which can then
11
+ be converted to PDF, in print or electronic flavors.
12
+ - `pretext-html.xsl` - conversion to HTML for online use.
13
+ - `pretext-epub.xsl` - conversion to EPUB, which
14
+ requires significant additional processing. So this stylesheet
15
+ is not meant to be applied in isolation. See the `pretext/pretext`
16
+ Python script for an option to initiate the processing pipeline.
17
+ - `pretext-jupyter.xsl` - conversion to Jupyter notebooks.
18
+ - `pretext-revealjs.xsl` - conversion of slideshows to HTML.
19
+ - `pretext-beamer.xsl` - conversion of slideshows to PDF.
20
+ - `pretext-braille.xsl` - conversion to a precursor for braille output, which
21
+ requires significant further processing. So this stylesheet
22
+ is not meant to be applied in isolation. See the `pretext/pretext`
23
+ Python script for an option to initiate the processing pipeline.
24
+ - `pretext-common.xsl` - base templates, and not useful in isolation.
25
+ - `pretext-assembly.xsl` - pre-processing stylesheet, which creates an
26
+ enhanced version of source. Applied in a controlled way by other stylesheets.
27
+ See the `utilities\pretext-enhanced-source.xsl` stylesheet for a demonstration.
28
+ - `extract-*.xsl` - used to isolate particular parts of a PreTeXt
29
+ document, typically for subsequent processing by a script.
30
+
31
+ (Updated: 2020-06-12)
@@ -0,0 +1,154 @@
1
+ <!-- ********************************************************************* -->
2
+ <!-- Copyright 2016 -->
3
+ <!-- Robert A. Beezer -->
4
+ <!-- -->
5
+ <!-- This file is part of MathBook XML. -->
6
+ <!-- -->
7
+ <!-- MathBook XML is free software: you can redistribute it and/or modify -->
8
+ <!-- it under the terms of the GNU General Public License as published by -->
9
+ <!-- the Free Software Foundation, either version 2 or version 3 of the -->
10
+ <!-- License (at your option). -->
11
+ <!-- -->
12
+ <!-- MathBook XML is distributed in the hope that it will be useful, -->
13
+ <!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
14
+ <!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
15
+ <!-- GNU General Public License for more details. -->
16
+ <!-- -->
17
+ <!-- You should have received a copy of the GNU General Public License -->
18
+ <!-- along with MathBook XML. If not, see <http://www.gnu.org/licenses/>. -->
19
+ <!-- ********************************************************************* -->
20
+
21
+ <!-- XSLT Cookbook, 2nd Edition -->
22
+ <!-- Copyright 2006, O'Reilly Media, Inc. -->
23
+ <!-- Declaration and entity definition format from Recipe 2.8 -->
24
+ <!-- Unicode strings from http://stackoverflow.com/questions/586231 -->
25
+ <!ENTITY UPPERCASE "'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'">
26
+ <!ENTITY LOWERCASE "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'">
27
+
28
+ <!-- Some more of our own design -->
29
+ <!ENTITY DIGIT "'0123456789'">
30
+ <!ENTITY ALPHABET "'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'">
31
+ <!ENTITY SIMPLECHAR "concat(&DIGIT;,&ALPHABET;)">
32
+
33
+ <!-- for match/select -->
34
+ <!ENTITY STRUCTURAL "book|article|slideshow|letter|memo|frontmatter|part|chapter|appendix|index|preface|acknowledgement|biography|foreword|dedication|colophon|section|subsection|subsubsection|slide|exercises|worksheet|handout|reading-questions|solutions|references|glossary|backmatter">
35
+
36
+ <!ENTITY TRADITIONAL-DIVISION "book|article|part|chapter|section|subsection|subsubsection|appendix">
37
+
38
+ <!ENTITY SPECIALIZED-DIVISION "exercises|worksheet|handout|reading-questions|references|glossary|solutions">
39
+
40
+ <!-- for filtering nodes, eg *[&STRUCTURAL-FILTER;], *[not(&STRUCTURAL-FILTER;)] -->
41
+ <!ENTITY STRUCTURAL-FILTER "self::book or self::article or self::slideshow or self::letter or self::memo or self::frontmatter or self::part or self::chapter or self::appendix or self::index or self::preface or self::acknowledgement or self::biography or self::foreword or self::dedication or self::colophon or self::section or self::subsection or self::subsubsection or self::slide or self::exercises or self::worksheet or self::handout or self::reading-questions or self::solutions or self::references or self::glossary or self::backmatter">
42
+
43
+ <!ENTITY TRADITIONAL-DIVISION-FILTER "self::book or self::article or self::part or self::chapter or self::section or self::subsection or self::subsubsection or self::appendix">
44
+
45
+ <!ENTITY SPECIALIZED-DIVISION-FILTER "self::exercises or self::worksheet or self::handout or self::reading-questions or self::references or self::glossary or self::solutions">
46
+
47
+ <!-- NB: (2019-06-12) Only the two metadata "filters" seem to -->
48
+ <!-- be in use, so only those are being maintained. grep'ing on -->
49
+ <!-- METADATA v. METADATA-FILTER, and applying "wc" makes this evident. -->
50
+ <!-- (Include this comment in count!) -->
51
+
52
+ <!-- typical items in blocks that get special treatment -->
53
+ <!ENTITY METADATA "title|subtitle|caption|idx|index">
54
+ <!ENTITY METADATA-FILTER "self::title or self::subtitle or self::caption or self::idx or self::index[not(index-list)]">
55
+
56
+ <!-- Subdivisions and runs of paragraphs (like in a proof) -->
57
+ <!-- contain "invisible" items that get killed and then -->
58
+ <!-- used/accessed other ways. To see if something is -->
59
+ <!--first, last, preceded, or followed by other significant -->
60
+ <!-- items requires filtering out these items in forming a -->
61
+ <!-- node-set (so as to not be confused by their presence) -->
62
+ <!-- A super-lightweight "article" might have "frontmatter" -->
63
+ <!-- and "backmatter" as peers of content elements, and in -->
64
+ <!-- other cases it should not be a problem -->
65
+ <!-- Typical use: *[not(&SUBDIVISION-METADATA-FILTER;)] -->
66
+ <!ENTITY SUBDIVISION-METADATA "title|subtitle|index|notation|todo|frontmatter|backmatter">
67
+ <!ENTITY SUBDIVISION-METADATA-FILTER "self::title or self::subtitle or self::idx or self::index[not(index-list)] or self::notation or self::todo or self::frontmatter or self::backmatter">
68
+
69
+ <!-- To implement a new category of blocks, search on -->
70
+ <!-- "PROJECT-" (case-sensitive) since we will mark -->
71
+ <!-- non-obvious locations with the string PROJECT-LIKE -->
72
+ <!-- as we immplement this on 2016-07-17, other entities -->
73
+ <!-- below will also match this short form -->
74
+
75
+ <!-- definition, just a plain statement, but logically distinct -->
76
+ <!ENTITY DEFINITION-LIKE "definition">
77
+ <!ENTITY DEFINITION-FILTER "self::definition">
78
+
79
+ <!-- statement + proof -->
80
+ <!ENTITY THEOREM-LIKE "theorem|corollary|lemma|algorithm|proposition|claim|fact|identity">
81
+ <!ENTITY THEOREM-FILTER "self::theorem or self::corollary or self::lemma or self::algorithm or self::proposition or self::claim or self::fact or self::identity">
82
+
83
+ <!-- varieties of proofs -->
84
+ <!ENTITY PROOF-LIKE "proof|argument|justification|reasoning|explanation">
85
+ <!ENTITY PROOF-FILTER "self::proof or self::argument or self::justification or self::reasoning or self::explanation">
86
+
87
+ <!-- three types of PROOF-LIKE -->
88
+ <!-- in THEOREM-LIKE, detached/standalone, in solutions -->
89
+ <!-- INNER-PROOF-FILTER only used where heading levels are controlled -->
90
+ <!-- SOLUTION-PROOF-FILTER used extensively to control LaTeX environments/macros/styling -->
91
+ <!-- standalone/detached is just everything else (in division, or paragraphs, or...) -->
92
+ <!ENTITY INNER-PROOF-FILTER "(&PROOF-FILTER;) and (parent::theorem or parent::corollary or parent::lemma or parent::algorithm or parent::proposition or parent::claim or parent::fact or parent::identity)">
93
+ <!ENTITY SOLUTION-PROOF-FILTER "(&PROOF-FILTER;) and (ancestor::hint or ancestor::answer or ancestor::solution)">
94
+
95
+ <!-- a mathematical statement, but never with a proof -->
96
+ <!ENTITY AXIOM-LIKE "axiom|conjecture|principle|heuristic|hypothesis|assumption">
97
+ <!ENTITY AXIOM-FILTER "self::axiom or self::conjecture or self::principle or self::heuristic or self::hypothesis or self::assumption">
98
+
99
+ <!-- narrative, set off for structure, reference -->
100
+ <!ENTITY REMARK-LIKE "remark|convention|note|observation|warning|insight">
101
+ <!ENTITY REMARK-FILTER "self::remark or self::convention or self::note or self::observation or self::warning or self::insight">
102
+
103
+ <!-- about computations or technology -->
104
+ <!ENTITY COMPUTATION-LIKE "computation|technology|data">
105
+ <!ENTITY COMPUTATION-FILTER "self::computation or self::technology or self::data">
106
+
107
+ <!-- incidental, skippable, lightweight -->
108
+ <!ENTITY ASIDE-LIKE "aside|biographical|historical">
109
+ <!ENTITY ASIDE-FILTER "self::aside or self::biographical or self::historical">
110
+
111
+ <!-- blocks, or statement + solution -->
112
+ <!ENTITY EXAMPLE-LIKE "example|question|problem">
113
+ <!ENTITY EXAMPLE-FILTER "self::example or self::question or self::problem">
114
+
115
+ <!-- blocks, or statement + solution -->
116
+ <!-- save off lab, laboratory, experiment for science -->
117
+ <!-- NB: update comprehensive list in the Guide with any additions -->
118
+ <!ENTITY PROJECT-LIKE "project|activity|exploration|investigation">
119
+ <!ENTITY PROJECT-FILTER "self::project or self::activity or self::exploration or self::investigation">
120
+
121
+ <!-- blocks with meta-information in lists -->
122
+ <!-- TODO: add in "standards", "goals" -->
123
+ <!-- NB: update comprehensive list in the Guide with any additions -->
124
+ <!ENTITY GOAL-LIKE "objectives|outcomes">
125
+ <!ENTITY GOAL-FILTER "self::objectives or self::outcomes">
126
+
127
+ <!-- Open = research question/problem/conjecture -->
128
+ <!ENTITY OPENPROBLEM-LIKE "openproblem|openquestion|openconjecture">
129
+ <!ENTITY OPENPROBLEM-FILTER "self::openproblem or self::openquestion or self::openconjecture">
130
+
131
+ <!-- displays with captions -->
132
+ <!ENTITY FIGURE-LIKE "figure|table|listing|list">
133
+ <!ENTITY FIGURE-FILTER "self::figure or self::table or self::listing or self::list">
134
+
135
+ <!-- Composite filters for the numbering "serial-stamp" pass. The -->
136
+ <!-- "fundamental" blocks always share the overall blocks counter; a -->
137
+ <!-- "top" figure-like is a captioned display that earns a number (a -->
138
+ <!-- panel inside a captioned side-by-side earns a letter instead). -->
139
+ <!ENTITY FUNDAMENTAL-BLOCK-FILTER "(&DEFINITION-FILTER;) or (&THEOREM-FILTER;) or (&AXIOM-FILTER;) or (&REMARK-FILTER;) or (&COMPUTATION-FILTER;) or (&EXAMPLE-FILTER;)">
140
+ <!ENTITY TOP-FIGURE-FILTER "(&FIGURE-FILTER;) and not(parent::sidebyside/parent::figure or parent::sidebyside/parent::sbsgroup/parent::figure)">
141
+
142
+ <!-- appendages of examples, exercises, tasks -->
143
+ <!ENTITY SOLUTION-LIKE "hint|answer|solution">
144
+ <!ENTITY SOLUTION-FILTER "self::hint or self::answer or self::solution">
145
+
146
+ <!-- appendages of OPENPROBLEM-LIKE -->
147
+ <!ENTITY DISCUSSION-LIKE "context|discussion|opinion|status|suggestion">
148
+ <!ENTITY DISCUSSION-FILTER "self::context or self::discussion or self::opinion or self::status or self::suggestion">
149
+
150
+ <!-- When context is an inline "exercise", then this condition is -->
151
+ <!-- true. We are positive, so as new locations of "exercise" -->
152
+ <!-- are added, then this need not change -->
153
+ <!-- Typical use: self::exercise and boolean(&INLINE-EXERCISE-FILTER;) -->
154
+ <!ENTITY INLINE-EXERCISE-FILTER "parent::article|parent::paragraphs|parent::chapter|parent::appendix|parent::section|parent::subsection|parent::subsubsection|parent::handout">