@pretextbook/pretext-html 0.7.0 → 0.9.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 (43) hide show
  1. package/README.md +31 -2
  2. package/assets/preview-html.xsl +16 -0
  3. package/assets/upstream.json +1 -1
  4. package/assets/xsl/README.md +25 -24
  5. package/assets/xsl/entities.ent +11 -0
  6. package/assets/xsl/extract-dynamic.xsl +54 -3
  7. package/assets/xsl/extract-gdscript.xsl +61 -0
  8. package/assets/xsl/extract-sageplot.xsl +3 -0
  9. package/assets/xsl/localizations/README.md +24 -24
  10. package/assets/xsl/localizations/it-IT.xml +37 -41
  11. package/assets/xsl/pretext-assembly.xsl +190 -30
  12. package/assets/xsl/pretext-beamer.xsl +57 -12
  13. package/assets/xsl/pretext-common.xsl +175 -30
  14. package/assets/xsl/pretext-epub.xsl +4 -6
  15. package/assets/xsl/pretext-fo.xsl +127 -67
  16. package/assets/xsl/pretext-html.xsl +350 -94
  17. package/assets/xsl/pretext-jupyter.xsl +1 -0
  18. package/assets/xsl/pretext-latex-classic.xsl +2 -2
  19. package/assets/xsl/pretext-latex-common.xsl +296 -151
  20. package/assets/xsl/pretext-latex.xsl +16 -6
  21. package/assets/xsl/pretext-numbers.xsl +10 -0
  22. package/assets/xsl/pretext-revealjs.xsl +69 -4
  23. package/assets/xsl/pretext-runestone-fitb.xsl +179 -84
  24. package/assets/xsl/pretext-runestone-static.xsl +72 -20
  25. package/assets/xsl/pretext-runestone.xsl +32 -25
  26. package/assets/xsl/pretext-text-utilities.xsl +7 -0
  27. package/assets/xsl/pretext-text.xsl +17 -0
  28. package/assets/xsl/publisher-variables.xsl +109 -111
  29. package/assets/xsl/support/play-button/README.md +1 -3
  30. package/assets/xsl/tests/README.md +1 -1
  31. package/assets/xsl/utilities/README.md +6 -8
  32. package/assets/xsl-bundle.json +1 -1
  33. package/dist/cli-BUrNZxov.js +1098 -0
  34. package/dist/cli.js +1 -1
  35. package/dist/html-static.d.ts +20 -0
  36. package/dist/index.browser.js +598 -374
  37. package/dist/index.d.ts +4 -0
  38. package/dist/index.js +35 -30
  39. package/dist/renderer.d.ts +40 -1
  40. package/dist/skeleton.d.ts +41 -0
  41. package/dist/xrefs.d.ts +54 -0
  42. package/package.json +2 -1
  43. package/dist/cli-D0m0Ha1j.js +0 -856
@@ -1,856 +0,0 @@
1
- import { readFile as A, writeFile as U } from "node:fs/promises";
2
- import * as b from "node:process";
3
- import * as l from "node:path";
4
- import { fileURLToPath as he } from "node:url";
5
- import { fromXml as y } from "xast-util-from-xml";
6
- import { toXml as $ } from "xast-util-to-xml";
7
- import { injectRevealBridge as we } from "./reveal.js";
8
- import { injectThemeBridge as be } from "./theme.js";
9
- const ge = "ptxPreviewBannerDismissed", ve = "About live preview";
10
- function N(e) {
11
- return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12
- }
13
- function xe(e) {
14
- return [
15
- '<div id="ptx-preview-banner" class="ptx-preview-banner" role="note">',
16
- ` <span class="ptx-preview-banner-text">${N(e)}</span>`,
17
- ' <button type="button" class="ptx-preview-banner-dismiss" aria-label="Dismiss">&times;</button>',
18
- "</div>",
19
- `<button type="button" id="ptx-preview-banner-restore" class="ptx-preview-banner-restore" hidden>${N(ve)}</button>`
20
- ].join(`
21
- `);
22
- }
23
- function ye() {
24
- return [
25
- "<style>",
26
- ".ptx-preview-banner {",
27
- " display: flex;",
28
- " align-items: center;",
29
- " gap: 0.75em;",
30
- " padding: 0.5em 1em;",
31
- " font-size: 0.9em;",
32
- " background: #fff8e1;",
33
- " color: #6b5300;",
34
- " border-bottom: 1px solid #f0c36d;",
35
- "}",
36
- // The [hidden] content attribute only hides an element via the
37
- // user-agent stylesheet's `[hidden] { display: none }` rule, and a
38
- // normal-priority *author* rule always wins over a normal-priority UA
39
- // rule regardless of selector specificity — so the unconditional
40
- // `display: flex` above would otherwise keep the banner visible even
41
- // after previewBannerScript sets `banner.hidden = true`.
42
- ".ptx-preview-banner[hidden] {",
43
- " display: none;",
44
- "}",
45
- ".ptx-preview-banner-text {",
46
- " flex: 1 1 auto;",
47
- "}",
48
- ".ptx-preview-banner-dismiss {",
49
- " flex: 0 0 auto;",
50
- " background: transparent;",
51
- " border: none;",
52
- " font-size: 1.2em;",
53
- " line-height: 1;",
54
- " cursor: pointer;",
55
- " color: inherit;",
56
- " padding: 0 0.25em;",
57
- "}",
58
- "html.dark-mode .ptx-preview-banner {",
59
- " background: #3a2f00;",
60
- " color: #f2d27a;",
61
- " border-bottom-color: #6b5300;",
62
- "}",
63
- ".ptx-preview-banner-restore {",
64
- " position: fixed;",
65
- " right: 0.5em;",
66
- " bottom: 0.5em;",
67
- " z-index: 1000;",
68
- " background: transparent;",
69
- " border: none;",
70
- " padding: 0.15em 0.4em;",
71
- " font-size: 0.75em;",
72
- " color: inherit;",
73
- " opacity: 0.45;",
74
- " text-decoration: underline;",
75
- " cursor: pointer;",
76
- "}",
77
- ".ptx-preview-banner-restore:hover {",
78
- " opacity: 0.85;",
79
- "}",
80
- "</style>"
81
- ].join(`
82
- `);
83
- }
84
- function Ee() {
85
- return [
86
- "<script>",
87
- "(function () {",
88
- " var KEY = " + JSON.stringify(ge) + ";",
89
- ' var banner = document.getElementById("ptx-preview-banner");',
90
- ' var restore = document.getElementById("ptx-preview-banner-restore");',
91
- " if (!banner || !restore) { return; }",
92
- // localStorage can throw (disabled cookies/storage, sandboxed iframe);
93
- // fall back to always showing the banner rather than crashing the page.
94
- " function isDismissed() {",
95
- " try { return window.localStorage.getItem(KEY) === '1'; }",
96
- " catch (e) { return false; }",
97
- " }",
98
- " function setDismissed(value) {",
99
- " try {",
100
- " if (value) { window.localStorage.setItem(KEY, '1'); }",
101
- " else { window.localStorage.removeItem(KEY); }",
102
- " } catch (e) {}",
103
- " }",
104
- " function apply(dismissed) {",
105
- " banner.hidden = dismissed;",
106
- " restore.hidden = !dismissed;",
107
- " }",
108
- " apply(isDismissed());",
109
- ' var dismissBtn = banner.querySelector(".ptx-preview-banner-dismiss");',
110
- " if (dismissBtn) {",
111
- " dismissBtn.addEventListener('click', function () {",
112
- " setDismissed(true);",
113
- " apply(true);",
114
- " });",
115
- " }",
116
- " restore.addEventListener('click', function () {",
117
- " setDismissed(false);",
118
- " apply(false);",
119
- " });",
120
- "})();",
121
- "<\/script>"
122
- ].join(`
123
- `);
124
- }
125
- const Te = "<!--ptx-preview-banner-->", $e = "<!--/ptx-preview-banner-->", Se = /\n?<!--ptx-preview-banner-->[\s\S]*?<!--\/ptx-preview-banner-->/;
126
- function ke(e, r) {
127
- const t = Se.exec(e), n = t ? e.slice(0, t.index) + e.slice(t.index + t[0].length) : e;
128
- if (!/<body[^>]*>/i.test(n))
129
- return n;
130
- const o = `
131
- ${Te}
132
- ${ye()}
133
- ${xe(r.message)}
134
- ${Ee()}
135
- ${$e}`;
136
- return n.replace(/<body([^>]*)>/i, `<body$1>${o}`);
137
- }
138
- async function ee(e, r) {
139
- const t = l.resolve(e), n = l.resolve(t, `.${l.posix.normalize(r)}`);
140
- if (n !== t && !n.startsWith(t + l.sep)) {
141
- console.error(
142
- `pretext-html: refusing to serve ${r} from outside ${t}`
143
- );
144
- return;
145
- }
146
- try {
147
- return new Uint8Array(await A(n));
148
- } catch {
149
- return;
150
- }
151
- }
152
- async function j(e) {
153
- try {
154
- return await A(e, "utf8");
155
- } catch {
156
- return;
157
- }
158
- }
159
- let te;
160
- function yt(e) {
161
- te = e;
162
- }
163
- function I() {
164
- return te ?? process.env.PRETEXT_HTML_ASSETS ?? l.resolve(l.dirname(he(import.meta.url)), "..", "assets");
165
- }
166
- function Pe(e, r) {
167
- return l.join(e, r);
168
- }
169
- const De = "born-hidden-knowl", Ie = /<details\b([^>]*)>(\s*)(?:<summary\b([^>]*)>)?/g;
170
- function Le(e) {
171
- const r = /\bclass="([^"]*)"/.exec(e);
172
- return r ? r[1].trim().split(/\s+/) : [];
173
- }
174
- function Re(e) {
175
- return /(^|\s)open(\s|=|$)/.test(e);
176
- }
177
- function H(e) {
178
- return Re(e) ? e : ` open${e}`;
179
- }
180
- function Ae(e) {
181
- return e.replace(
182
- Ie,
183
- (r, t, n, o) => {
184
- if (!Le(t).includes(De))
185
- return r;
186
- const s = `<details${H(t)}>`;
187
- return o === void 0 ? `${s}${n}` : `${s}${n}<summary${H(o)}>`;
188
- }
189
- );
190
- }
191
- const B = /* @__PURE__ */ new Map(), re = /* @__PURE__ */ new Map();
192
- let L, je = 0, ne = ee;
193
- function Et(e) {
194
- ne = e;
195
- }
196
- function Be(e, r) {
197
- const t = typeof e == "string" ? e : e instanceof URL ? e.href : e.url, n = re.get(t);
198
- if (n !== void 0)
199
- return Promise.resolve(new Response(n, { status: 200 }));
200
- let o;
201
- try {
202
- o = new URL(t).host;
203
- } catch {
204
- o = "";
205
- }
206
- const s = B.get(o);
207
- return s !== void 0 ? Ce(s, t) : L(e, r);
208
- }
209
- const Me = '<?xml version="1.0"?><pretext-preview-missing-file/>';
210
- async function Ce(e, r) {
211
- const t = decodeURIComponent(new URL(r).pathname), n = await ne(e, t);
212
- if (n === void 0)
213
- return new Response(Me, { status: 200 });
214
- const o = typeof n == "string" ? n : new Uint8Array(n);
215
- return new Response(o, { status: 200 });
216
- }
217
- function oe() {
218
- L || (L = globalThis.fetch, globalThis.fetch = Be);
219
- }
220
- function se(e) {
221
- oe();
222
- const r = `mnt${++je}.ptx.invalid`;
223
- return B.set(r, e), `http://${r}`;
224
- }
225
- function Xe(e) {
226
- B.delete(new URL(e).host);
227
- }
228
- function Fe(e, r) {
229
- oe(), re.set(e, r);
230
- }
231
- const R = `<?xml version="1.0" encoding="UTF-8"?>
232
- <publication>
233
- <source>
234
- <directories external="../assets" generated="../generated-assets" />
235
- </source>
236
- <html>
237
- <platform portable="yes"/>
238
- </html>
239
- </publication>
240
- `, _e = ["theme", "style", "shell"];
241
- function w(e, r) {
242
- for (const t of e.children)
243
- if (t.type === "element" && t.name === r)
244
- return t;
245
- }
246
- function g(e, r) {
247
- let t = w(e, r);
248
- return t || (t = { type: "element", name: r, attributes: {}, children: [] }, e.children.push(t)), t;
249
- }
250
- function Oe(e, r) {
251
- const t = w(e, "css");
252
- if (t && _e.some((o) => t.attributes?.[o]))
253
- return;
254
- const n = t ?? g(e, "css");
255
- n.attributes = { ...n.attributes, theme: r };
256
- }
257
- function We(e, r) {
258
- const t = w(e, "appearance");
259
- if (t?.attributes?.theme)
260
- return;
261
- const n = t ?? g(e, "appearance");
262
- n.attributes = { ...n.attributes, theme: r };
263
- }
264
- function Ue(e) {
265
- const r = g(e, "resources");
266
- r.attributes = {
267
- ...r.attributes,
268
- host: "cdn",
269
- math: "online"
270
- };
271
- }
272
- function Ne(e, r = {}) {
273
- const t = r.cssTheme?.trim(), n = r.revealTheme?.trim(), o = r.target === "slides";
274
- if (!e && !t && !o)
275
- return R;
276
- const s = y(e ?? R), a = w(s, "publication");
277
- if (!a)
278
- throw new Error(
279
- "Invalid publication file: no root <publication> element found"
280
- );
281
- const i = g(a, "html"), u = g(i, "platform");
282
- if (u.attributes = { ...u.attributes, portable: "yes" }, t && Oe(i, t), o) {
283
- const c = g(a, "revealjs");
284
- Ue(c), n && We(c, n);
285
- }
286
- return $(s);
287
- }
288
- function J(e) {
289
- if (!(e === void 0 || e === "" || e.startsWith("/")))
290
- return e.endsWith("/") ? e : `${e}/`;
291
- }
292
- function He(e) {
293
- const r = y(e ?? R), t = w(r, "publication"), n = t && w(t, "source"), o = n && w(n, "directories"), s = J(
294
- o?.attributes?.external ?? void 0
295
- ), a = J(
296
- o?.attributes?.generated ?? void 0
297
- );
298
- return {
299
- external: s,
300
- generated: a,
301
- managed: s !== void 0 && a !== void 0
302
- };
303
- }
304
- const ie = "http://www.w3.org/2001/XInclude", K = 64;
305
- async function Je(e, r, t) {
306
- return e.includes("include") ? (await ae(e, r, t)).content : e;
307
- }
308
- async function ae(e, r, t) {
309
- const n = y(e), o = {
310
- projectDir: l.resolve(t),
311
- stack: [l.resolve(r)]
312
- }, s = await x(
313
- n,
314
- l.dirname(l.resolve(r)),
315
- { "": "" },
316
- o
317
- );
318
- return { tree: n, content: s ? $(n) : e };
319
- }
320
- function Ke(e) {
321
- return e.data?.ptxIncludedFile;
322
- }
323
- function ze(e, r) {
324
- const t = e.data ?? (e.data = {});
325
- t.ptxIncludedFile = r;
326
- }
327
- function S(e, r) {
328
- let t = e;
329
- for (const [n, o] of Object.entries(r.attributes))
330
- (n === "xmlns" || n.startsWith("xmlns:")) && (t === e && (t = { ...e }), t[n === "xmlns" ? "" : n.slice(6)] = o ?? "");
331
- return t;
332
- }
333
- function ce(e, r) {
334
- const t = e.name.indexOf(":"), n = t === -1 ? "" : e.name.slice(0, t);
335
- return (t === -1 ? e.name : e.name.slice(t + 1)) === "include" && r[n] === ie;
336
- }
337
- async function x(e, r, t, n) {
338
- let o = !1;
339
- for (let s = 0; s < e.children.length; s++) {
340
- const a = e.children[s];
341
- if (a.type !== "element")
342
- continue;
343
- const i = S(t, a);
344
- if (ce(a, i)) {
345
- const u = await le(
346
- a,
347
- r,
348
- i,
349
- n
350
- );
351
- e.children.splice(s, 1, ...u), s += u.length - 1, o = !0;
352
- } else await x(a, r, i, n) && (o = !0);
353
- }
354
- return o;
355
- }
356
- async function le(e, r, t, n) {
357
- const o = n.stack[n.stack.length - 1];
358
- if (e.attributes.xpointer)
359
- throw new Error(
360
- `xi:include with xpointer is not supported by the JS preview build (in ${o})`
361
- );
362
- const s = e.attributes.href;
363
- if (!s)
364
- throw new Error(`xi:include without href (in ${o})`);
365
- let a = s;
366
- try {
367
- a = decodeURIComponent(s);
368
- } catch {
369
- }
370
- const i = l.resolve(r, a);
371
- if (i !== n.projectDir && !i.startsWith(n.projectDir + l.sep))
372
- throw new Error(
373
- `xi:include escapes the project directory: ${s} (in ${o})`
374
- );
375
- if (n.stack.includes(i))
376
- throw new Error(
377
- `Circular xi:include: ${[...n.stack, i].join(" -> ")}`
378
- );
379
- if (n.stack.length >= K)
380
- throw new Error(`xi:include nesting exceeds ${K} levels`);
381
- const u = await j(i);
382
- if (u === void 0) {
383
- const p = qe(e, t);
384
- if (p)
385
- return await x(p, r, t, n), p.children;
386
- throw new Error(`xi:include target not found: ${s} (in ${o})`);
387
- }
388
- if (e.attributes.parse === "text")
389
- return [{ type: "text", value: u }];
390
- let c;
391
- try {
392
- c = y(u);
393
- } catch (p) {
394
- throw new Error(
395
- `Could not parse xi:include target ${i} as XML: ${p instanceof Error ? p.message : p}. (Included files must be well-formed, with a single root element.)`
396
- );
397
- }
398
- n.stack.push(i);
399
- try {
400
- await x(c, l.dirname(i), { "": "" }, n);
401
- } finally {
402
- n.stack.pop();
403
- }
404
- const f = c.children.filter(
405
- (p) => p.type === "element"
406
- );
407
- for (const p of f)
408
- ze(p, i);
409
- return f;
410
- }
411
- function z(e) {
412
- return e.name === "docinfo";
413
- }
414
- async function Ye(e, r, t) {
415
- try {
416
- const o = y(e).children.find(
417
- (c) => c.type === "element"
418
- );
419
- if (!o)
420
- return;
421
- const s = l.resolve(r), a = l.dirname(s), i = {
422
- projectDir: l.resolve(t),
423
- stack: [s]
424
- }, u = S({ "": "" }, o);
425
- for (const c of o.children) {
426
- if (c.type !== "element")
427
- continue;
428
- const f = S(u, c);
429
- if (z(c))
430
- return await x(c, a, f, i), $(c);
431
- if (ce(c, f)) {
432
- const m = (await le(
433
- c,
434
- a,
435
- f,
436
- i
437
- )).find(
438
- (h) => h.type === "element" && z(h)
439
- );
440
- if (m)
441
- return $(m);
442
- continue;
443
- }
444
- break;
445
- }
446
- return;
447
- } catch {
448
- return;
449
- }
450
- }
451
- function qe(e, r) {
452
- for (const t of e.children) {
453
- if (t.type !== "element")
454
- continue;
455
- const n = S(r, t), o = t.name.indexOf(":"), s = o === -1 ? "" : t.name.slice(0, o);
456
- if ((o === -1 ? t.name : t.name.slice(o + 1)) === "fallback" && n[s] === ie)
457
- return t;
458
- }
459
- }
460
- function ue(e) {
461
- return typeof e == "object" && e !== null && e.type === "element";
462
- }
463
- function Ge(e) {
464
- return /^(pf|xhtml):/.test(e.name);
465
- }
466
- function Ve(e, r, t) {
467
- const n = [], o = e.children.find(ue);
468
- if (o) {
469
- const s = t?.parentId ?? "root";
470
- de(o, s, t?.position ?? 1, r, s, n);
471
- }
472
- return n;
473
- }
474
- function de(e, r, t, n, o, s) {
475
- const a = Ke(e) ?? n;
476
- let i, u;
477
- if (Ge(e))
478
- u = "root";
479
- else {
480
- const f = e.attributes.label ?? e.attributes["xml:id"];
481
- i = f ?? `${r}-${t}`, s.push({
482
- id: i,
483
- file: a,
484
- line: e.position?.start.line ?? 1,
485
- column: e.position?.start.column ?? 1,
486
- endLine: e.position?.end.line ?? e.position?.start.line ?? 1,
487
- parent: o
488
- }), u = i;
489
- }
490
- let c = 0;
491
- for (const f of e.children)
492
- ue(f) && (c += 1, de(
493
- f,
494
- u,
495
- c,
496
- a,
497
- i ?? o,
498
- s
499
- ));
500
- }
501
- function Tt(e, r) {
502
- let t;
503
- for (const n of e)
504
- n.line <= r && (t = n);
505
- return t ?? e[0];
506
- }
507
- function Ze(e) {
508
- const r = e.replace(/<!--[\s\S]*?-->/g, " ").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, " ");
509
- return /<\s*slide(?:show)?[\s/>]/.test(r) ? "slides" : "html";
510
- }
511
- function Qe() {
512
- return Pe(I(), "xsl");
513
- }
514
- function et() {
515
- return "Suspending" in WebAssembly;
516
- }
517
- function tt() {
518
- if (!et())
519
- throw new Error(
520
- "WebAssembly JSPI is not enabled. Run Node with --experimental-wasm-jspi (or use the pretext-html CLI, which re-launches itself with the flag)."
521
- );
522
- }
523
- function Y(e) {
524
- return e.includes("'") ? e.includes('"') ? `concat(${e.split("'").map((t) => `'${t}'`).join(`, "'", `)})` : `"${e}"` : `'${e}'`;
525
- }
526
- function rt(e) {
527
- return e.replace(
528
- /from '\.\/(https:\/\/[^']+)'/g,
529
- (r, t) => `from '${t}'`
530
- );
531
- }
532
- const nt = "https://cdn.jsdelivr.net/gh/PreTeXtBook/html-static@latest/dist/";
533
- function ot(e) {
534
- return e.replace(
535
- /(<link\b[^>]*\bhref=["'])_static\//gi,
536
- `$1${nt}_static/`
537
- );
538
- }
539
- function st(e) {
540
- return e.slice(0, 65536).replace(/<\?[\s\S]*?\?>/g, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/<!DOCTYPE[^>]*>/gi, " ").match(/<\s*([A-Za-z][\w:-]*)/)?.[1];
541
- }
542
- async function q(e) {
543
- const r = await j(e);
544
- if (r === void 0)
545
- throw new Error(
546
- `Could not read ${e}. (In the browser build only absolute URLs are readable — pass sourceContent instead of relying on sourcePath.)`
547
- );
548
- return r;
549
- }
550
- async function it(e, r) {
551
- const t = l.resolve(e), n = await j(t);
552
- if (n !== void 0)
553
- return Ye(n, t, r);
554
- }
555
- function at(e, r, t, n) {
556
- const o = e.replace(/^\uFEFF/, "").replace(/<\?xml[\s\S]*?\?>/, "").replace(/<!DOCTYPE[^>]*>/i, ""), s = t === "slides" ? "slideshow" : r === "chapter" || r === "part" ? "book" : "article";
557
- return `<pretext>
558
- ${n?.trim() ? `${n.trim()}
559
- ` : ""}<${s}>
560
- <title/>
561
- ${o}
562
- </${s}>
563
- </pretext>
564
- `;
565
- }
566
- let fe = !1;
567
- function ct(e) {
568
- return e instanceof Error && /\bAborted\(/.test(e.message);
569
- }
570
- function lt(e) {
571
- return e instanceof Error && /memory access|out of bounds/i.test(e.message);
572
- }
573
- function ut() {
574
- if (fe)
575
- throw new Error(
576
- "The WebAssembly renderer aborted earlier in this process and cannot be reused. Restart the process (or reload the page) to render again."
577
- );
578
- }
579
- function G(e) {
580
- if (ct(e))
581
- throw fe = !0, new Error(
582
- "The WebAssembly renderer aborted and cannot be reused. Restart the process (or reload the page) to render again.",
583
- { cause: e }
584
- );
585
- if (lt(e))
586
- throw new Error(
587
- "The WebAssembly renderer hit a memory fault. Most often the document is too large for this build's stack — whole-book builds are a known limitation, so try a smaller document, or see the README about rebuilding libxslt-wasm with a larger stack. The same fault also results from running two renders concurrently against the shared libxslt state.",
588
- { cause: e }
589
- );
590
- }
591
- let P;
592
- async function pe() {
593
- return P || (P = (async () => {
594
- const [e, r] = await Promise.all([
595
- import("@pretextbook/libxslt-wasm"),
596
- import("@pretextbook/libxslt-wasm/exslt")
597
- ]);
598
- return r.registerAll(), e;
599
- })()), P;
600
- }
601
- const D = /* @__PURE__ */ new Map(), dt = {
602
- html: "preview-html.xsl",
603
- slides: "preview-revealjs.xsl"
604
- };
605
- async function ft(e, r) {
606
- const t = dt[r], n = `${r}\0${e}`;
607
- let o = D.get(n);
608
- return o || (o = (async () => {
609
- const { XmlDocument: s, XsltStylesheet: a } = await pe(), i = se(e), u = await ee(I(), `/${t}`);
610
- if (u === void 0)
611
- throw new Error(
612
- `Could not read ${t} from ${I()}. Check the assets location (PRETEXT_HTML_ASSETS under Node, setAssetsBase() in the browser).`
613
- );
614
- const c = new TextDecoder().decode(u), f = await s.fromString(c, {
615
- url: `${i}/${t}`,
616
- options: { noEnt: !0, dtdLoad: !0, huge: !0 }
617
- });
618
- return a.fromXmlDocument(f);
619
- })(), D.set(n, o), o.catch(() => D.delete(n))), o;
620
- }
621
- let V = Promise.resolve();
622
- function pt(e) {
623
- const r = V.then(
624
- () => Z(e),
625
- () => Z(e)
626
- );
627
- return V = r.catch(() => {
628
- }), r;
629
- }
630
- async function Z(e) {
631
- tt(), ut();
632
- const { XmlDocument: r } = await pe(), t = l.resolve(e.sourcePath), n = l.resolve(
633
- e.projectDir ?? l.dirname(t)
634
- ), o = e.sourceContent ?? await q(t), s = l.relative(n, t);
635
- if (s.startsWith(".."))
636
- throw new Error(
637
- `sourcePath (${t}) must live inside projectDir (${n})`
638
- );
639
- const a = l.relative(
640
- n,
641
- l.resolve(e.mainSourcePath ?? t)
642
- ), i = a.startsWith("..") ? s : a, u = se(n);
643
- try {
644
- let c, f = `${u}/__pretext-preview-publication.xml`;
645
- if (e.publicationPath) {
646
- const d = l.resolve(e.publicationPath);
647
- c = await q(d);
648
- const v = l.relative(n, d);
649
- v.startsWith("..") || (f = `${u}/${v.split(l.sep).join("/")}`);
650
- }
651
- let p, m;
652
- if (e.sourceMap) {
653
- const d = await ae(
654
- o,
655
- t,
656
- n
657
- );
658
- p = d.tree, m = d.content;
659
- } else
660
- m = await Je(
661
- o,
662
- t,
663
- n
664
- );
665
- const h = e.target ?? Ze(m), me = await ft(e.xslDir ?? Qe(), h), M = Ne(c, {
666
- cssTheme: e.cssTheme,
667
- revealTheme: e.revealTheme,
668
- target: h
669
- });
670
- Fe(f, M);
671
- const E = He(M), C = l.dirname(l.resolve(n, i)), X = E.external !== void 0 && E.generated !== void 0 ? {
672
- external: l.resolve(C, E.external),
673
- generated: l.resolve(C, E.generated)
674
- } : void 0, T = st(m);
675
- let F = { parentId: "root", position: 1 };
676
- if (T !== "pretext" && T !== "mathbook")
677
- if (e.fragment) {
678
- const d = e.docinfo ?? (e.docinfoSourcePath ? await it(e.docinfoSourcePath, n) : void 0);
679
- m = at(
680
- m,
681
- T,
682
- h,
683
- d
684
- ), F = { parentId: d?.trim() ? "root-1-2" : "root-1-1", position: 2 };
685
- } else
686
- throw new Error(
687
- `The document root is <${T ?? "?"}>, not <pretext> — this looks like an xi:included fragment. Render the project's main source file instead, or pass the fragment option.`
688
- );
689
- const _ = p ? Ve(p, t, F) : void 0, O = await r.fromString(m, {
690
- url: `${u}/${i.split(l.sep).join("/")}`,
691
- options: { noEnt: !0, dtdLoad: !0, huge: !0 }
692
- }), W = {
693
- publisher: Y(f)
694
- };
695
- for (const [d, v] of Object.entries(e.stringParams ?? {}))
696
- W[d] = Y(v);
697
- let k;
698
- try {
699
- k = await me.apply(O, W);
700
- } catch (d) {
701
- throw G(d), new Error(
702
- "PreTeXt XSLT transform failed; see the PTX:ERROR/PTX:FATAL messages on stderr for details.",
703
- { cause: d }
704
- );
705
- } finally {
706
- O.delete();
707
- }
708
- try {
709
- let d = rt(k.toHtmlString());
710
- return (e.openKnowls ?? !0) && (d = Ae(d)), h === "slides" ? (d = ot(d), d = we(d, e.revealView ?? "scroll", {
711
- zoom: e.revealZoom
712
- })) : e.theme && (d = be(d, e.theme)), e.previewBanner && (d = ke(d, e.previewBanner)), {
713
- html: d,
714
- target: h,
715
- ..._ ? { sourceMap: _ } : {},
716
- ...X ? { assetDirs: X } : {}
717
- };
718
- } catch (d) {
719
- throw G(d), d;
720
- } finally {
721
- k.delete();
722
- }
723
- } finally {
724
- Xe(u);
725
- }
726
- }
727
- const Q = `Usage: pretext-html <source.ptx> [options]
728
-
729
- Render a PreTeXt document to a single standalone HTML page (portable build:
730
- one page, css/js/MathJax from CDN). No PreTeXt installation required.
731
-
732
- Options:
733
- -o, --output <file> Write HTML to a file instead of stdout
734
- --publication <file> Publication file (portable html is forced on)
735
- --css-theme <name> HTML theme to use when the publication file names
736
- none of its own: default-modern (PreTeXt's default),
737
- denver, tacoma, salem, greeley or boulder
738
- --project-dir <dir> Directory served to the transform for xi:includes
739
- (default: the source file's directory)
740
- --param <name=value> Extra XSLT string parameter (repeatable)
741
- --xsl-dir <dir> Use PreTeXt stylesheets from this directory
742
- instead of the vendored copy
743
- --fragment Allow a non-root source file: wrap the fragment
744
- in a minimal <pretext> document (an <article>,
745
- or a <book> for <chapter>/<part> fragments)
746
- --docinfo <file> File whose contents (a <docinfo> element) are
747
- injected into the wrapper in --fragment mode, so
748
- the fragment keeps the project's LaTeX macros
749
- --docinfo-source <file> Complete source file (e.g. main.ptx) to lift the
750
- <docinfo> from for --fragment mode, resolving
751
- xi:includes (used when --docinfo is not given)
752
- --source-map <file> Also write a JSON source map: HTML id → source
753
- file/line for every element (for editor sync)
754
- --no-open-knowls Leave solutions, hints and other born-hidden
755
- knowls collapsed, as a real PreTeXt build does.
756
- They are expanded by default, since these pages
757
- are previews of work in progress
758
- -h, --help Show this help
759
- `;
760
- function mt(e) {
761
- let r, t, n, o;
762
- const s = {}, a = {};
763
- for (let i = 0; i < e.length; i++) {
764
- const u = e[i], c = () => {
765
- if (i += 1, i >= e.length)
766
- throw new Error(`Missing value for ${u}`);
767
- return e[i];
768
- };
769
- switch (u) {
770
- case "-h":
771
- case "--help":
772
- b.stdout.write(Q), b.exit(0);
773
- break;
774
- case "-o":
775
- case "--output":
776
- t = c();
777
- break;
778
- case "--publication":
779
- s.publicationPath = c();
780
- break;
781
- case "--css-theme":
782
- s.cssTheme = c();
783
- break;
784
- case "--project-dir":
785
- s.projectDir = c();
786
- break;
787
- case "--xsl-dir":
788
- s.xslDir = c();
789
- break;
790
- case "--fragment":
791
- s.fragment = !0;
792
- break;
793
- case "--no-open-knowls":
794
- s.openKnowls = !1;
795
- break;
796
- case "--docinfo":
797
- n = c();
798
- break;
799
- case "--docinfo-source":
800
- s.docinfoSourcePath = c();
801
- break;
802
- case "--source-map":
803
- o = c(), s.sourceMap = !0;
804
- break;
805
- case "--param": {
806
- const f = c(), p = f.indexOf("=");
807
- if (p === -1)
808
- throw new Error(`--param expects name=value, got: ${f}`);
809
- a[f.slice(0, p)] = f.slice(p + 1);
810
- break;
811
- }
812
- default:
813
- if (u.startsWith("-"))
814
- throw new Error(`Unknown option: ${u}`);
815
- if (r)
816
- throw new Error(`Unexpected extra argument: ${u}`);
817
- r = u;
818
- }
819
- }
820
- if (!r)
821
- throw new Error(`No source file given.
822
-
823
- ` + Q);
824
- return Object.keys(a).length > 0 && (s.stringParams = a), {
825
- options: { ...s, sourcePath: r },
826
- output: t,
827
- docinfoPath: n,
828
- sourceMapPath: o
829
- };
830
- }
831
- async function $t(e) {
832
- const { options: r, output: t, docinfoPath: n, sourceMapPath: o } = mt(e);
833
- n && (r.docinfo = await A(n, "utf8"));
834
- const s = Date.now(), { html: a, sourceMap: i } = await pt(r);
835
- b.stderr.write(`pretext-html: rendered in ${Date.now() - s}ms
836
- `), o && i && (await U(o, JSON.stringify(i, null, 2)), b.stderr.write(`pretext-html: wrote ${o}
837
- `)), t ? (await U(t, a), b.stderr.write(`pretext-html: wrote ${t}
838
- `)) : b.stdout.write(a);
839
- }
840
- export {
841
- ge as P,
842
- Ze as a,
843
- Ne as b,
844
- et as c,
845
- Qe as d,
846
- Et as e,
847
- Tt as f,
848
- mt as g,
849
- ke as i,
850
- $t as m,
851
- Ae as o,
852
- Ee as p,
853
- pt as r,
854
- yt as s,
855
- Y as x
856
- };