gutterpress 0.11.22 → 0.11.23-alpha.2

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 (76) hide show
  1. package/README.md +23 -24
  2. package/dist/{README-3nj919rm.md → README-8ef336pp.md} +1 -1
  3. package/dist/api/index.d.ts +4 -4
  4. package/dist/api/index.js +16 -22
  5. package/dist/{build-53bw14h7.js → build-encgnv0c.js} +9 -10
  6. package/dist/{chapter-01-rkpyvjna.md → chapter-01-gsbjt584.md} +1 -1
  7. package/dist/chapter-01-s71xrf5q.md +69 -0
  8. package/dist/{chapter-01-7jwqg1ct.md → chapter-01-wgjfz4w6.md} +1 -1
  9. package/dist/checks/source/character-table.d.ts +12 -6
  10. package/dist/{cli-habkc5ng.js → cli-a35w7wzg.js} +5 -4
  11. package/dist/{cli-kx4hbnx2.js → cli-aqh6brew.js} +1 -1
  12. package/dist/{cli-1hxxwbaq.js → cli-evg8sbht.js} +1 -1
  13. package/dist/{cli-cjftezxr.js → cli-kh8v4vvw.js} +2 -1
  14. package/dist/{cli-ntwqmdnw.js → cli-pwwfxdgb.js} +846 -13
  15. package/dist/{cli-8kg0wjdt.js → cli-pz4bn98t.js} +185 -9
  16. package/dist/{cli-zj5xaepv.js → cli-sdmv4bba.js} +57 -117
  17. package/dist/{cli-ke86zsz6.js → cli-xq6djqbj.js} +51 -54
  18. package/dist/{index-r7jcsk6h.js → cli-y28j019d.js} +19 -10
  19. package/dist/cli.js +12 -12
  20. package/dist/{doctor-xka1frnx.js → doctor-5gtpgpd1.js} +3 -3
  21. package/dist/{engine-p93f06gj.js → engine-mc5br8g8.js} +1 -2
  22. package/dist/{engine-0ndvy8vj.js → engine-tn13gk0b.js} +3 -3
  23. package/dist/{ext-dwfqyy1j.js → ext-wn2a5afq.js} +18 -33
  24. package/dist/{extension-restore-ct1wk344.js → extension-restore-g8jnmmzq.js} +5 -6
  25. package/dist/{extension-restore-7vp3vh77.js → extension-restore-s3x1618g.js} +4 -4
  26. package/dist/{index-apc8w9w8.js → index-0skhjx3e.js} +180 -1
  27. package/dist/{index-4v7e621e.js → index-2bjcghze.js} +847 -13
  28. package/dist/index-46ycxe6r.js +18 -0
  29. package/dist/{index-53nrm5j1.js → index-4x6y8krm.js} +2 -4
  30. package/dist/{cli-h3phdstf.js → index-5x42amh8.js} +19 -10
  31. package/dist/{index-93pqkvty.js → index-h6yk5tjx.js} +5 -4
  32. package/dist/{index-kh7fayjv.js → index-j5z86r4a.js} +57 -54
  33. package/dist/{index-6cmn2wpd.js → index-x3ema2w3.js} +69 -128
  34. package/dist/index.js +17 -23
  35. package/dist/lib/build-runner.d.ts +1 -1
  36. package/dist/lib/extension-manager.d.ts +16 -43
  37. package/dist/lib/extension-scaffold.d.ts +3 -3
  38. package/dist/lib/extension-specifier.d.ts +23 -6
  39. package/dist/lib/markdown/assemble.d.ts +7 -1
  40. package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
  41. package/dist/lib/markdown/index.d.ts +4 -0
  42. package/dist/lib/markdown/math.d.ts +43 -0
  43. package/dist/lib/markdown/renderer.d.ts +11 -8
  44. package/dist/lib/markdown/table.d.ts +46 -0
  45. package/dist/lib/markdown/typography.d.ts +12 -0
  46. package/dist/lib/npm-plugin-installer.d.ts +1 -1
  47. package/dist/lib/plugin-vendor.d.ts +11 -3
  48. package/dist/lib/presets.d.ts +1 -1
  49. package/dist/lib/project-gitignore.d.ts +2 -2
  50. package/dist/lib/project-scaffold.d.ts +6 -8
  51. package/dist/lib/project-templates.d.ts +6 -1
  52. package/dist/lib/snippets.d.ts +2 -1
  53. package/dist/lib/style-resolver.d.ts +1 -2
  54. package/dist/manifest-eagfhba6.yaml +19 -0
  55. package/dist/{manifest.schema-399bx3vc.json → manifest.schema-t7nx2stg.json} +12 -5
  56. package/dist/{new-1pawj2qf.js → new-mhs46pw3.js} +22 -21
  57. package/dist/{plugins-fr4fnzhb.js → plugins-1sxe0dkz.js} +4 -4
  58. package/dist/{plugins-g4dgw7mn.js → plugins-2cek4mz1.js} +2 -2
  59. package/dist/{preflight-ept9q57t.js → preflight-3k2b1x8e.js} +9 -10
  60. package/dist/preview/file-watcher.d.ts +1 -0
  61. package/dist/{preview-fxpnjv7k.js → preview-6p9v6rht.js} +9 -10
  62. package/dist/{publish-zhqqsgmr.js → publish-qgsngy8s.js} +9 -10
  63. package/dist/render.js +470 -11
  64. package/dist/schema/manifest.types.d.ts +8 -0
  65. package/dist/{source-provider-qbfknhyy.js → source-provider-98k5deda.js} +2 -2
  66. package/dist/{source-provider-2r74a7wp.js → source-provider-knmcam50.js} +2 -2
  67. package/dist/{validate-t68gvckq.js → validate-0v7xw6wa.js} +9 -10
  68. package/package.json +2 -1
  69. package/dist/cli-1ngqzg8s.js +0 -196
  70. package/dist/index-vay3ff1f.js +0 -213
  71. package/dist/package-97gm31sg.json +0 -10
  72. package/dist/package-gag6ykwn.json +0 -10
  73. package/dist/package-nrhkwf2m.json +0 -10
  74. package/dist/theme-h5recz6c.css +0 -61
  75. package/dist/theme-j2bagrfx.css +0 -59
  76. package/dist/theme-nn6d53zy.css +0 -71
@@ -41,6 +41,7 @@ export declare function injectPreviewScripts(html: string): string;
41
41
  */
42
42
  export declare function generateAndWriteHtml(inputPath: string, tempDir: string, config: {
43
43
  title?: string;
44
+ language?: string;
44
45
  styles?: string[];
45
46
  source?: {
46
47
  files?: string[] | null;
@@ -3,23 +3,23 @@ import {
3
3
  runBuild,
4
4
  splitOutPath,
5
5
  startPreviewServer
6
- } from "./cli-ke86zsz6.js";
7
- import"./cli-1hxxwbaq.js";
6
+ } from "./cli-xq6djqbj.js";
7
+ import"./cli-evg8sbht.js";
8
8
  import {
9
9
  previewArgs
10
10
  } from "./cli-75qkn0k5.js";
11
11
  import"./cli-ht1bcqdd.js";
12
- import"./cli-8kg0wjdt.js";
12
+ import"./cli-pz4bn98t.js";
13
13
  import"./cli-2ppw6q9v.js";
14
14
  import"./cli-eyyggect.js";
15
15
  import"./cli-asap4t1z.js";
16
- import"./cli-habkc5ng.js";
16
+ import"./cli-a35w7wzg.js";
17
17
  import"./cli-v5mp7a6q.js";
18
- import"./cli-zj5xaepv.js";
19
- import"./cli-ntwqmdnw.js";
18
+ import"./cli-sdmv4bba.js";
19
+ import"./cli-pwwfxdgb.js";
20
20
  import {
21
21
  log
22
- } from "./cli-kx4hbnx2.js";
22
+ } from "./cli-aqh6brew.js";
23
23
  import {
24
24
  UsageError,
25
25
  parseFormat,
@@ -28,12 +28,11 @@ import {
28
28
  rejectUnknownFlags,
29
29
  resolvePort
30
30
  } from "./cli-d8xjns66.js";
31
- import"./cli-cjftezxr.js";
32
- import"./cli-1ngqzg8s.js";
31
+ import"./cli-kh8v4vvw.js";
33
32
  import {
34
33
  BuildError
35
34
  } from "./cli-46ycxe6r.js";
36
- import"./cli-h3phdstf.js";
35
+ import"./cli-y28j019d.js";
37
36
  import"./cli-37x76zdn.js";
38
37
 
39
38
  // src/commands/preview.ts
@@ -10,36 +10,35 @@ import {
10
10
  resolvePublishFormat,
11
11
  resolvePublishProvider,
12
12
  runPublish
13
- } from "./cli-ke86zsz6.js";
13
+ } from "./cli-xq6djqbj.js";
14
14
  import {
15
15
  FileTokenStore
16
- } from "./cli-1hxxwbaq.js";
16
+ } from "./cli-evg8sbht.js";
17
17
  import"./cli-ht1bcqdd.js";
18
- import"./cli-8kg0wjdt.js";
18
+ import"./cli-pz4bn98t.js";
19
19
  import"./cli-2ppw6q9v.js";
20
20
  import"./cli-eyyggect.js";
21
21
  import"./cli-asap4t1z.js";
22
- import"./cli-habkc5ng.js";
22
+ import"./cli-a35w7wzg.js";
23
23
  import"./cli-v5mp7a6q.js";
24
24
  import {
25
25
  loadManifestWithPath
26
- } from "./cli-zj5xaepv.js";
27
- import"./cli-ntwqmdnw.js";
26
+ } from "./cli-sdmv4bba.js";
27
+ import"./cli-pwwfxdgb.js";
28
28
  import {
29
29
  log
30
- } from "./cli-kx4hbnx2.js";
30
+ } from "./cli-aqh6brew.js";
31
31
  import {
32
32
  UsageError,
33
33
  rejectExtraPositionals,
34
34
  rejectUnknownFlags
35
35
  } from "./cli-d8xjns66.js";
36
- import"./cli-cjftezxr.js";
37
- import"./cli-1ngqzg8s.js";
36
+ import"./cli-kh8v4vvw.js";
38
37
  import {
39
38
  BuildError,
40
39
  EXIT_CODES
41
40
  } from "./cli-46ycxe6r.js";
42
- import"./cli-h3phdstf.js";
41
+ import"./cli-y28j019d.js";
43
42
  import"./cli-37x76zdn.js";
44
43
 
45
44
  // src/commands/publish.ts
package/dist/render.js CHANGED
@@ -1428,6 +1428,38 @@ img.gp-shape {
1428
1428
  :where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }
1429
1429
  :where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }
1430
1430
  :where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }
1431
+
1432
+ /* Math (the bundled gutterpress-math feature, math.ts): MathJax's own rules
1433
+ for the <mjx-container> SVG output it emits, from its SVG output jax's
1434
+ stylesheet, less the ones for its interactive menu and tooltips. Inert in
1435
+ a book without formulas. */
1436
+ mjx-container[jax="SVG"] { direction: ltr; }
1437
+ mjx-container[jax="SVG"] > svg { overflow: visible; min-height: 1px; min-width: 1px; }
1438
+ mjx-container[jax="SVG"] > svg a { fill: blue; stroke: blue; }
1439
+ mjx-container[jax="SVG"][display="true"] { display: block; text-align: center; margin: 1em 0; }
1440
+ mjx-container[jax="SVG"][display="true"][width="full"] { display: flex; }
1441
+ mjx-container[jax="SVG"][justify="left"] { text-align: left; }
1442
+ mjx-container[jax="SVG"][justify="right"] { text-align: right; }
1443
+ mjx-container[jax="SVG"] path[data-c], mjx-container[jax="SVG"] use[data-c] { stroke-width: 3; }
1444
+ mjx-assistive-mml {
1445
+ position: absolute !important;
1446
+ top: 0px; left: 0px;
1447
+ clip: rect(1px, 1px, 1px, 1px);
1448
+ padding: 1px 0px 0px 0px !important;
1449
+ border: 0px !important;
1450
+ display: block !important;
1451
+ width: auto !important;
1452
+ overflow: hidden !important;
1453
+ user-select: none;
1454
+ }
1455
+ mjx-assistive-mml[display="block"] { width: 100% !important; }
1456
+ g[data-mml-node="merror"] > g { fill: red; stroke: red; }
1457
+ g[data-mml-node="merror"] > rect[data-background] { fill: yellow; stroke: none; }
1458
+ g[data-mml-node="mtable"] > line[data-line], svg[data-table] > g > line[data-line] { stroke-width: 70px; fill: none; }
1459
+ g[data-mml-node="mtable"] > rect[data-frame], svg[data-table] > g > rect[data-frame] { stroke-width: 70px; fill: none; }
1460
+ g[data-mml-node="mtable"] > .mjx-dashed, svg[data-table] > g > .mjx-dashed { stroke-dasharray: 140; }
1461
+ g[data-mml-node="mtable"] > .mjx-dotted, svg[data-table] > g > .mjx-dotted { stroke-linecap: round; stroke-dasharray: 0,140; }
1462
+ g[data-mml-node="mtable"] > g > svg { overflow: visible; }
1431
1463
  `;
1432
1464
  var GP_CLASSES = new Set([
1433
1465
  "gp-left",
@@ -1625,6 +1657,11 @@ function canonicalChapterId(p) {
1625
1657
  return s;
1626
1658
  }
1627
1659
 
1660
+ // src/lib/slug.ts
1661
+ function slugify(name, fallback = "") {
1662
+ return name.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || fallback;
1663
+ }
1664
+
1628
1665
  // src/lib/markdown/renderer.ts
1629
1666
  import MarkdownIt from "markdown-it";
1630
1667
 
@@ -1777,11 +1814,6 @@ function gpPinScope(md) {
1777
1814
  });
1778
1815
  }
1779
1816
 
1780
- // src/lib/slug.ts
1781
- function slugify(name, fallback = "") {
1782
- return name.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || fallback;
1783
- }
1784
-
1785
1817
  // src/lib/markdown/block-names.ts
1786
1818
  var BLOCK_OPEN = /^layout_(chapter|spread|page|section|component)_open$/;
1787
1819
  var BLOCK_CLOSE = /^layout_(chapter|spread|page|section|component)_close$/;
@@ -1923,6 +1955,275 @@ function gpBlockNames(md) {
1923
1955
  md.core.ruler.push("gp_block_names", (state) => nameBlocksAndHeadings(state.tokens));
1924
1956
  }
1925
1957
 
1958
+ // src/lib/markdown/table.ts
1959
+ import { isSpace } from "markdown-it/lib/common/utils.mjs";
1960
+ var scanCodeSpan = (src, start, max) => {
1961
+ let open = start;
1962
+ while (open < max && src.charCodeAt(open) === 96)
1963
+ open++;
1964
+ const length = open - start;
1965
+ let pos = open;
1966
+ while (pos < max) {
1967
+ if (src.charCodeAt(pos) !== 96) {
1968
+ pos++;
1969
+ continue;
1970
+ }
1971
+ let run = pos;
1972
+ while (run < max && src.charCodeAt(run) === 96)
1973
+ run++;
1974
+ if (run - pos === length)
1975
+ return run;
1976
+ pos = run;
1977
+ }
1978
+ return open;
1979
+ };
1980
+ var DEFAULT_SPANS = { 96: scanCodeSpan };
1981
+ function splitCells(str, spans) {
1982
+ const result = [];
1983
+ const max = str.length;
1984
+ let pos = 0;
1985
+ let lastPos = 0;
1986
+ let current = "";
1987
+ let isEscaped = false;
1988
+ while (pos < max) {
1989
+ const ch = str.charCodeAt(pos);
1990
+ if (ch === 124) {
1991
+ if (!isEscaped) {
1992
+ result.push(current + str.substring(lastPos, pos));
1993
+ current = "";
1994
+ lastPos = pos + 1;
1995
+ } else {
1996
+ current += str.substring(lastPos, pos - 1);
1997
+ lastPos = pos;
1998
+ }
1999
+ } else if (!isEscaped && spans[ch]) {
2000
+ pos = spans[ch](str, pos, max);
2001
+ continue;
2002
+ }
2003
+ isEscaped = ch === 92;
2004
+ pos++;
2005
+ }
2006
+ result.push(current + str.substring(lastPos));
2007
+ return result;
2008
+ }
2009
+ function getLine(state, line) {
2010
+ const pos = state.bMarks[line] + state.tShift[line];
2011
+ const max = state.eMarks[line];
2012
+ return state.src.slice(pos, max);
2013
+ }
2014
+ var MAX_AUTOCOMPLETED_CELLS = 65536;
2015
+ function warnExtraCells(env, line, cells, columns) {
2016
+ if (!env.layoutWarnings)
2017
+ env.layoutWarnings = [];
2018
+ const extra = cells - columns;
2019
+ env.layoutWarnings.push({
2020
+ line: line + 1,
2021
+ type: "table_extra_cells",
2022
+ message: `This row has ${cells} cells but the table has ${columns} columns, so its last ` + `${extra === 1 ? "cell is" : `${extra} cells are`} left out. ` + "A | inside a cell splits it: write \\| for a literal one."
2023
+ });
2024
+ }
2025
+ function tableRule(spans) {
2026
+ return function table(state, startLine, endLine, silent) {
2027
+ if (startLine + 2 > endLine)
2028
+ return false;
2029
+ let nextLine = startLine + 1;
2030
+ if (state.sCount[nextLine] < state.blkIndent)
2031
+ return false;
2032
+ if (state.sCount[nextLine] - state.blkIndent >= 4)
2033
+ return false;
2034
+ let pos = state.bMarks[nextLine] + state.tShift[nextLine];
2035
+ if (pos >= state.eMarks[nextLine])
2036
+ return false;
2037
+ const firstCh = state.src.charCodeAt(pos++);
2038
+ if (firstCh !== 124 && firstCh !== 45 && firstCh !== 58)
2039
+ return false;
2040
+ if (pos >= state.eMarks[nextLine])
2041
+ return false;
2042
+ const secondCh = state.src.charCodeAt(pos++);
2043
+ if (secondCh !== 124 && secondCh !== 45 && secondCh !== 58 && !isSpace(secondCh)) {
2044
+ return false;
2045
+ }
2046
+ if (firstCh === 45 && isSpace(secondCh))
2047
+ return false;
2048
+ while (pos < state.eMarks[nextLine]) {
2049
+ const ch = state.src.charCodeAt(pos);
2050
+ if (ch !== 124 && ch !== 45 && ch !== 58 && !isSpace(ch))
2051
+ return false;
2052
+ pos++;
2053
+ }
2054
+ let lineText2 = getLine(state, startLine + 1);
2055
+ let columns = lineText2.split("|");
2056
+ const aligns = [];
2057
+ for (let i = 0;i < columns.length; i++) {
2058
+ const t = columns[i].trim();
2059
+ if (!t) {
2060
+ if (i === 0 || i === columns.length - 1) {
2061
+ continue;
2062
+ } else {
2063
+ return false;
2064
+ }
2065
+ }
2066
+ if (!/^:?-+:?$/.test(t))
2067
+ return false;
2068
+ if (t.charCodeAt(t.length - 1) === 58) {
2069
+ aligns.push(t.charCodeAt(0) === 58 ? "center" : "right");
2070
+ } else if (t.charCodeAt(0) === 58) {
2071
+ aligns.push("left");
2072
+ } else {
2073
+ aligns.push("");
2074
+ }
2075
+ }
2076
+ lineText2 = getLine(state, startLine).trim();
2077
+ if (lineText2.indexOf("|") === -1)
2078
+ return false;
2079
+ if (state.sCount[startLine] - state.blkIndent >= 4)
2080
+ return false;
2081
+ columns = splitCells(lineText2, spans);
2082
+ if (columns.length && columns[0] === "")
2083
+ columns.shift();
2084
+ if (columns.length && columns[columns.length - 1] === "")
2085
+ columns.pop();
2086
+ const columnCount = columns.length;
2087
+ if (columnCount === 0 || columnCount !== aligns.length)
2088
+ return false;
2089
+ if (silent)
2090
+ return true;
2091
+ const oldParentType = state.parentType;
2092
+ state.parentType = "table";
2093
+ const terminatorRules = state.md.block.ruler.getRules("blockquote");
2094
+ const token_to = state.push("table_open", "table", 1);
2095
+ const tableLines = [startLine, 0];
2096
+ token_to.map = tableLines;
2097
+ const token_tho = state.push("thead_open", "thead", 1);
2098
+ token_tho.map = [startLine, startLine + 1];
2099
+ const token_htro = state.push("tr_open", "tr", 1);
2100
+ token_htro.map = [startLine, startLine + 1];
2101
+ for (let i = 0;i < columns.length; i++) {
2102
+ const token_ho = state.push("th_open", "th", 1);
2103
+ if (aligns[i]) {
2104
+ token_ho.attrs = [["style", "text-align:" + aligns[i]]];
2105
+ }
2106
+ const token_il = state.push("inline", "", 0);
2107
+ token_il.content = columns[i].trim();
2108
+ token_il.children = [];
2109
+ state.push("th_close", "th", -1);
2110
+ }
2111
+ state.push("tr_close", "tr", -1);
2112
+ state.push("thead_close", "thead", -1);
2113
+ let tbodyLines;
2114
+ let autocompletedCells = 0;
2115
+ for (nextLine = startLine + 2;nextLine < endLine; nextLine++) {
2116
+ if (state.sCount[nextLine] < state.blkIndent)
2117
+ break;
2118
+ let terminate = false;
2119
+ for (let i = 0, l = terminatorRules.length;i < l; i++) {
2120
+ if (terminatorRules[i](state, nextLine, endLine, true)) {
2121
+ terminate = true;
2122
+ break;
2123
+ }
2124
+ }
2125
+ if (terminate)
2126
+ break;
2127
+ lineText2 = getLine(state, nextLine).trim();
2128
+ if (!lineText2)
2129
+ break;
2130
+ if (state.sCount[nextLine] - state.blkIndent >= 4)
2131
+ break;
2132
+ columns = splitCells(lineText2, spans);
2133
+ if (columns.length && columns[0] === "")
2134
+ columns.shift();
2135
+ if (columns.length && columns[columns.length - 1] === "")
2136
+ columns.pop();
2137
+ if (columns.length > columnCount) {
2138
+ warnExtraCells(state.env, nextLine, columns.length, columnCount);
2139
+ }
2140
+ autocompletedCells += columnCount - columns.length;
2141
+ if (autocompletedCells > MAX_AUTOCOMPLETED_CELLS)
2142
+ break;
2143
+ if (nextLine === startLine + 2) {
2144
+ const token_tbo = state.push("tbody_open", "tbody", 1);
2145
+ token_tbo.map = tbodyLines = [startLine + 2, 0];
2146
+ }
2147
+ const token_tro = state.push("tr_open", "tr", 1);
2148
+ token_tro.map = [nextLine, nextLine + 1];
2149
+ for (let i = 0;i < columnCount; i++) {
2150
+ const token_tdo = state.push("td_open", "td", 1);
2151
+ if (aligns[i]) {
2152
+ token_tdo.attrs = [["style", "text-align:" + aligns[i]]];
2153
+ }
2154
+ const token_il = state.push("inline", "", 0);
2155
+ token_il.content = columns[i] ? columns[i].trim() : "";
2156
+ token_il.children = [];
2157
+ state.push("td_close", "td", -1);
2158
+ }
2159
+ state.push("tr_close", "tr", -1);
2160
+ }
2161
+ if (tbodyLines) {
2162
+ state.push("tbody_close", "tbody", -1);
2163
+ tbodyLines[1] = nextLine;
2164
+ }
2165
+ state.push("table_close", "table", -1);
2166
+ tableLines[1] = nextLine;
2167
+ state.parentType = oldParentType;
2168
+ state.line = nextLine;
2169
+ return true;
2170
+ };
2171
+ }
2172
+ function gpTable(md, options) {
2173
+ md.block.ruler.at("table", tableRule(options?.spans ?? DEFAULT_SPANS), { alt: ["paragraph", "reference"] });
2174
+ }
2175
+
2176
+ // src/lib/markdown/typography.ts
2177
+ var EM_DASH = /(^|[^-])---(?=[^-]|$)/gm;
2178
+ var EN_DASH_SPACED = /(^|\s)--(?=\s|$)/gm;
2179
+ var EN_DASH = /(^|[^-\s])--(?=[^-\s]|$)/gm;
2180
+ var ELLIPSIS = /\.\.\./g;
2181
+ var CANDIDATE = /--|\.\.\./;
2182
+ function replaceInText(children) {
2183
+ let insideAutolink = 0;
2184
+ for (let i = children.length - 1;i >= 0; i--) {
2185
+ const token = children[i];
2186
+ if (token.type === "text" && !insideAutolink && CANDIDATE.test(token.content)) {
2187
+ token.content = token.content.replace(ELLIPSIS, "…").replace(EM_DASH, "$1—").replace(EN_DASH_SPACED, "$1–").replace(EN_DASH, "$1–");
2188
+ }
2189
+ if (token.type === "link_close" && token.info === "auto")
2190
+ insideAutolink++;
2191
+ if (token.type === "link_open" && token.info === "auto")
2192
+ insideAutolink--;
2193
+ }
2194
+ }
2195
+ var QUOTES = {
2196
+ en: "“”‘’",
2197
+ de: "„“‚‘",
2198
+ "de-ch": "«»‹›",
2199
+ "de-li": "«»‹›",
2200
+ fr: ["« ", " »", "‹ ", " ›"],
2201
+ es: "«»“”",
2202
+ it: "«»“”",
2203
+ pt: "«»“”",
2204
+ "pt-br": "“”‘’",
2205
+ ru: "«»„“",
2206
+ pl: "„”«»",
2207
+ cs: "„“‚‘",
2208
+ sk: "„“‚‘",
2209
+ sv: "””’’",
2210
+ fi: "””’’"
2211
+ };
2212
+ function quotesFor(language) {
2213
+ const tag = (language ?? "en").toLowerCase();
2214
+ return QUOTES[tag] ?? QUOTES[tag.split("-")[0]] ?? QUOTES.en;
2215
+ }
2216
+ function gpTypography(md) {
2217
+ md.disable("replacements");
2218
+ md.core.ruler.after("linkify", "gp_typography", (state) => {
2219
+ for (const token of state.tokens) {
2220
+ if (token.type !== "inline" || !token.children || !CANDIDATE.test(token.content))
2221
+ continue;
2222
+ replaceInText(token.children);
2223
+ }
2224
+ });
2225
+ }
2226
+
1926
2227
  // src/lib/markdown/renderer.ts
1927
2228
  import markdownItSourceMap from "markdown-it-source-map";
1928
2229
  import markdownItDeflist from "markdown-it-deflist";
@@ -2026,6 +2327,159 @@ function gfmAlerts(md) {
2026
2327
  md.core.ruler.after("block", "gp_gfm_alerts", gfmAlertsRule);
2027
2328
  }
2028
2329
 
2330
+ // src/lib/markdown/math.ts
2331
+ import { mathjax } from "mathjax-full/js/mathjax.js";
2332
+ import { TeX } from "mathjax-full/js/input/tex.js";
2333
+ import { SVG } from "mathjax-full/js/output/svg.js";
2334
+ import { liteAdaptor } from "mathjax-full/js/adaptors/liteAdaptor.js";
2335
+ import { RegisterHTMLHandler } from "mathjax-full/js/handlers/html.js";
2336
+ import { AssistiveMmlHandler } from "mathjax-full/js/a11y/assistive-mml.js";
2337
+ import { AllPackages } from "mathjax-full/js/input/tex/AllPackages.js";
2338
+ function findInlineMathEnd(src, start, max) {
2339
+ const after = src.charCodeAt(start + 1);
2340
+ if (after === 32 || after === 9)
2341
+ return -1;
2342
+ let match = start + 1;
2343
+ while ((match = src.indexOf("$", match)) !== -1 && match < max) {
2344
+ let pos = match - 1;
2345
+ while (src.charCodeAt(pos) === 92)
2346
+ pos--;
2347
+ if ((match - pos) % 2 === 1)
2348
+ break;
2349
+ match++;
2350
+ }
2351
+ if (match === -1 || match >= max)
2352
+ return -1;
2353
+ if (match === start + 1)
2354
+ return -2;
2355
+ const before = src.charCodeAt(match - 1);
2356
+ const next = src.charCodeAt(match + 1);
2357
+ if (before === 32 || before === 9 || next >= 48 && next <= 57)
2358
+ return -1;
2359
+ return match;
2360
+ }
2361
+ var scanInlineMath = (src, start, max) => {
2362
+ const end = findInlineMathEnd(src, start, max);
2363
+ return end >= 0 ? end + 1 : end === -2 ? start + 2 : start + 1;
2364
+ };
2365
+ function mathInline(state, silent) {
2366
+ if (state.src.charCodeAt(state.pos) !== 36)
2367
+ return false;
2368
+ const end = findInlineMathEnd(state.src, state.pos, state.posMax);
2369
+ if (end < 0) {
2370
+ const literal = end === -2 ? "$$" : "$";
2371
+ if (!silent)
2372
+ state.pending += literal;
2373
+ state.pos += literal.length;
2374
+ return true;
2375
+ }
2376
+ if (!silent) {
2377
+ const token = state.push("math_inline", "math", 0);
2378
+ token.markup = "$";
2379
+ token.content = state.src.slice(state.pos + 1, end);
2380
+ }
2381
+ state.pos = end + 1;
2382
+ return true;
2383
+ }
2384
+ function mathBlock(state, start, end, silent) {
2385
+ let pos = state.bMarks[start] + state.tShift[start];
2386
+ let max = state.eMarks[start];
2387
+ if (pos + 2 > max)
2388
+ return false;
2389
+ if (state.src.slice(pos, pos + 2) !== "$$")
2390
+ return false;
2391
+ pos += 2;
2392
+ let firstLine = state.src.slice(pos, max);
2393
+ if (silent)
2394
+ return true;
2395
+ let found = false;
2396
+ let lastLine = "";
2397
+ if (firstLine.trim().slice(-2) === "$$") {
2398
+ firstLine = firstLine.trim().slice(0, -2);
2399
+ found = true;
2400
+ }
2401
+ let next = start;
2402
+ while (!found) {
2403
+ next++;
2404
+ if (next >= end)
2405
+ break;
2406
+ pos = state.bMarks[next] + state.tShift[next];
2407
+ max = state.eMarks[next];
2408
+ if (pos < max && state.tShift[next] < state.blkIndent) {
2409
+ break;
2410
+ }
2411
+ if (state.src.slice(pos, max).trim().slice(-2) === "$$") {
2412
+ const lastPos = state.src.slice(0, max).lastIndexOf("$$");
2413
+ lastLine = state.src.slice(pos, lastPos);
2414
+ found = true;
2415
+ }
2416
+ }
2417
+ state.line = next + 1;
2418
+ const token = state.push("math_block", "math", 0);
2419
+ token.block = true;
2420
+ token.content = (firstLine && firstLine.trim() ? firstLine + `
2421
+ ` : "") + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : "");
2422
+ token.map = [start, state.line];
2423
+ token.markup = "$$";
2424
+ return true;
2425
+ }
2426
+ var adaptor = null;
2427
+ function getAdaptor() {
2428
+ if (!adaptor) {
2429
+ adaptor = liteAdaptor();
2430
+ AssistiveMmlHandler(RegisterHTMLHandler(adaptor));
2431
+ }
2432
+ return adaptor;
2433
+ }
2434
+ var PACKAGES = AllPackages.filter((name) => name !== "noerrors" && name !== "noundefined");
2435
+ function gpMath(md) {
2436
+ const html = getAdaptor();
2437
+ let errors = [];
2438
+ const tex = new TeX({
2439
+ packages: PACKAGES,
2440
+ formatError: (jax, err) => {
2441
+ errors.push(err.message);
2442
+ return jax.formatError(err);
2443
+ }
2444
+ });
2445
+ const document = mathjax.document("", { InputJax: tex, OutputJax: new SVG({ fontCache: "none" }) });
2446
+ const typeset = (token, display, env) => {
2447
+ errors = [];
2448
+ const out = html.outerHTML(document.convert(token.content, { display }));
2449
+ for (const message of errors) {
2450
+ if (!env.layoutWarnings)
2451
+ env.layoutWarnings = [];
2452
+ env.layoutWarnings.push({
2453
+ line: token.meta?.line ?? (token.map?.[0] ?? 0) + 1,
2454
+ type: "math_error",
2455
+ message: `This formula could not be typeset: ${message}. It prints in red until it is fixed.`
2456
+ });
2457
+ }
2458
+ return display ? out + `
2459
+ ` : out;
2460
+ };
2461
+ md.inline.ruler.after("escape", "math_inline", mathInline);
2462
+ md.block.ruler.after("blockquote", "math_block", mathBlock, {
2463
+ alt: ["paragraph", "reference", "blockquote", "list"]
2464
+ });
2465
+ md.core.ruler.after("inline", "math_lines", (state) => {
2466
+ let line = 1;
2467
+ for (const token of state.tokens) {
2468
+ if (token.map)
2469
+ line = token.map[0] + 1;
2470
+ if (token.type !== "inline" || !token.children)
2471
+ continue;
2472
+ for (const child of token.children) {
2473
+ if (child.type === "math_inline")
2474
+ child.meta = { line };
2475
+ }
2476
+ }
2477
+ });
2478
+ md.renderer.rules.math_inline = (tokens, idx, _options, env) => typeset(tokens[idx], false, env);
2479
+ md.renderer.rules.math_block = (tokens, idx, _options, env) => typeset(tokens[idx], true, env);
2480
+ md.use(gpTable, { spans: { ...DEFAULT_SPANS, 36: scanInlineMath } });
2481
+ }
2482
+
2029
2483
  // src/lib/markdown/images.ts
2030
2484
  var isSrcsetSpace = (char) => char === "\t" || char === `
2031
2485
  ` || char === "\f" || char === "\r" || char === " ";
@@ -2452,14 +2906,17 @@ var BUILTIN_OPTIONAL_PLUGINS = {
2452
2906
  "markdown-it-sub": unwrapPlugin(markdownItSub),
2453
2907
  "markdown-it-sup": unwrapPlugin(markdownItSup),
2454
2908
  "markdown-it-abbr": unwrapPlugin(markdownItAbbr),
2455
- "gutterpress-gfm-alerts": gfmAlerts
2909
+ "gutterpress-gfm-alerts": gfmAlerts,
2910
+ "gutterpress-math": gpMath
2456
2911
  };
2457
- function createMarkdownRenderer(customPlugins) {
2912
+ function createMarkdownRenderer(customPlugins, options) {
2458
2913
  const md = new MarkdownIt({
2459
2914
  html: true,
2460
2915
  linkify: true,
2461
- typographer: true
2916
+ typographer: true,
2917
+ quotes: quotesFor(options?.language)
2462
2918
  });
2919
+ md.use(gpTypography);
2463
2920
  md.use(unwrapPlugin(markdownItAttrs));
2464
2921
  md.use(unwrapPlugin(markdownItFootnote));
2465
2922
  md.use(unwrapPlugin(markdownItDeflist));
@@ -2469,6 +2926,7 @@ function createMarkdownRenderer(customPlugins) {
2469
2926
  md.use(plugin, { declaredMarkers });
2470
2927
  md.use(gpPinScope);
2471
2928
  md.use(gpBlockNames);
2929
+ md.use(gpTable);
2472
2930
  md.use(gpTableAlign);
2473
2931
  md.use(gpTwoVersions);
2474
2932
  registerImageRule(md);
@@ -3108,11 +3566,12 @@ async function assembleBookHtml(opts) {
3108
3566
  const title = opts.title ?? "Document";
3109
3567
  const projectCss = opts.projectCss ?? "";
3110
3568
  const pluginCss = opts.pluginCss ?? "";
3569
+ const language = opts.language ?? "en";
3111
3570
  const files = opts.files;
3112
3571
  if (files.length === 0) {
3113
3572
  throw new Error("No markdown files to render");
3114
3573
  }
3115
- const md = createMarkdownRenderer(opts.plugins);
3574
+ const md = createMarkdownRenderer(opts.plugins, { language });
3116
3575
  let bodyContent = "";
3117
3576
  const imageRefs = new Set;
3118
3577
  for (const file of files) {
@@ -3124,7 +3583,7 @@ async function assembleBookHtml(opts) {
3124
3583
  const errorMsg = err instanceof Error ? err.message : String(err);
3125
3584
  throw new Error(`Failed to read file ${file}: ${errorMsg}`);
3126
3585
  }
3127
- const env = {};
3586
+ const env = { docId: slugify(chapterId) };
3128
3587
  if (opts.annotateSourceChapters)
3129
3588
  env.sourceChapter = chapterId;
3130
3589
  const rendered = md.render(content, env);
@@ -3170,7 +3629,7 @@ ${projectCss.trim()}` : null
3170
3629
  const lastPage = opts.print && lastPageMode(opts.print);
3171
3630
  const printAttrs = (opts.print?.signature && opts.print.signature > 1 ? ` data-gp-signature="${opts.print.signature}"` : "") + (lastPage ? ` data-gp-last-page="${lastPage}"` : "");
3172
3631
  return `<!DOCTYPE html>
3173
- <html lang="en"${printAttrs}>
3632
+ <html lang="${language}"${printAttrs}>
3174
3633
  <head>
3175
3634
  <meta charset="UTF-8">
3176
3635
  <meta name="viewport" content="width=device-width, initial-scale=1.0">${opts.printArea ? `
@@ -91,6 +91,12 @@ interface PublishSettings {
91
91
  export interface GutterpressManifest {
92
92
  title?: string;
93
93
  authors?: string[];
94
+ /**
95
+ * The book's language as a BCP 47 tag (`en`, `de-CH`, `pt-BR`); default
96
+ * `en`. It is the `lang` of the built HTML, which is what hyphenation
97
+ * follows, and the typographer sets quotation marks by it.
98
+ */
99
+ language?: string;
94
100
  publish?: PublishSettings;
95
101
  /** How the book is designed (ADR 0008). The registry in lib/presets.ts is authoritative. */
96
102
  preset?: "dtrpg" | "book" | "custom";
@@ -318,6 +324,8 @@ export interface PrintSpec {
318
324
  export interface ResolvedConfig {
319
325
  title: string;
320
326
  authors: string[];
327
+ /** BCP 47 language tag; `en` when the manifest sets none. */
328
+ language: string;
321
329
  /** The id of the preset this book resolved against (`dtrpg`, `book`, `custom`). */
322
330
  preset: string;
323
331
  /** The printer spec that preset follows, when it follows one: how a host credits the numbers it draws. */
@@ -21,8 +21,8 @@ import {
21
21
  switchBranch,
22
22
  whenGitIdle,
23
23
  withRepoLock
24
- } from "./index-93pqkvty.js";
25
- import"./index-r7jcsk6h.js";
24
+ } from "./index-h6yk5tjx.js";
25
+ import"./index-5x42amh8.js";
26
26
  import"./index-v5mp7a6q.js";
27
27
  import"./index-37x76zdn.js";
28
28
  export {