explico 0.12.0 → 0.13.1
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.
- package/CHANGELOG.md +1137 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +4 -3
- package/dist/compiler/astro.js +45 -15
- package/dist/compiler/cli.d.ts +26 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +9 -1
- package/dist/compiler/collections.js +55 -16
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +14 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +87 -6
- package/dist/compiler/manifest.js +174 -31
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +2 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +2 -2
- package/dist/reference/base-operators.mjs +2 -2
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +34 -4
- package/dist/reference/page-notation.js +54 -2
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +104 -10
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +84 -20
- package/dist/reference/render-lab-math.d.ts +2 -0
- package/dist/reference/render-lab-math.js +17 -5
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +191 -30
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +79 -24
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +32 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +111 -6
- package/docs/authoring/migrating.md +707 -0
- package/docs/authoring/notation.md +281 -29
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +10 -41
- package/docs/authoring/structure.md +53 -2
- package/docs/authoring/visualizations.md +144 -18
- package/package.json +12 -7
- package/src/compiler/astro.ts +57 -17
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +92 -19
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +299 -28
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +12 -9
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/figure/Figure.astro +11 -0
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +321 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +47 -9
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +13 -21
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +2 -2
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +100 -3
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +154 -8
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +84 -20
- package/src/reference/render-lab-math.ts +29 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +205 -29
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +291 -75
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
%% explico.cls — the book class of a course's LaTeX source.
|
|
2
|
+
%%
|
|
3
|
+
%% explico writes this file next to every LaTeX download, and builds the PDF
|
|
4
|
+
%% it offers from that same folder. Edit it freely in a download: it only sets
|
|
5
|
+
%% the layout and defines the commands the chapter files use.
|
|
6
|
+
%%
|
|
7
|
+
%% Engines: LuaLaTeX (preferred) or pdfLaTeX, TeX Live 2025 or later.
|
|
8
|
+
%%
|
|
9
|
+
%% Numbering follows the course website: parts and chapters are numbered
|
|
10
|
+
%% ‹part›.‹chapter›, sections ‹part›.‹chapter›.‹section›, and equations,
|
|
11
|
+
%% figures, tables, diagrams, worked examples and knowledge checks run per
|
|
12
|
+
%% chapter (‹part›.‹chapter›.‹n›) or, with \ExplicoFloatsByPart, per part
|
|
13
|
+
%% (‹part›.‹n›). LaTeX does the counting; explico checks every number against
|
|
14
|
+
%% the website when it builds the PDF.
|
|
15
|
+
\NeedsTeXFormat{LaTeX2e}
|
|
16
|
+
\ProvidesClass{explico}[2026/10/04 explico course book class]
|
|
17
|
+
|
|
18
|
+
%% `scripts`: the document holds Greek, Cyrillic, CJK or emoji (the exporter
|
|
19
|
+
%% sets it when it does), so LuaLaTeX loads the fallback fonts below.
|
|
20
|
+
\newif\ifexplico@scripts
|
|
21
|
+
\DeclareOption{scripts}{\explico@scriptstrue}
|
|
22
|
+
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{book}}
|
|
23
|
+
\ProcessOptions\relax
|
|
24
|
+
\LoadClass[11pt,oneside,openany]{book}
|
|
25
|
+
|
|
26
|
+
%% --- Engine and fonts ------------------------------------------------------
|
|
27
|
+
\RequirePackage{iftex}
|
|
28
|
+
\RequirePackage{amsmath,amssymb,mathtools}
|
|
29
|
+
%% Rule N17's engine half, as on the website (src/reference/katex-delimiters.mjs):
|
|
30
|
+
%% a negative \delimitershortfall makes every \left...\right pair strictly taller
|
|
31
|
+
%% than its content, so a nest grows outward at each level. TeX's default (5pt)
|
|
32
|
+
%% lets nested pairs round to the same glyph.
|
|
33
|
+
\delimitershortfall=-1pt
|
|
34
|
+
%% Whether a text font sets Greek; if none does, a Greek letter in prose is
|
|
35
|
+
%% set as its math symbol (below, with the other Unicode characters).
|
|
36
|
+
\newif\ifexplico@greek
|
|
37
|
+
\ifPDFTeX
|
|
38
|
+
\RequirePackage[T1]{fontenc}
|
|
39
|
+
\RequirePackage{lmodern}
|
|
40
|
+
\RequirePackage{textcomp}
|
|
41
|
+
\RequirePackage{bm}
|
|
42
|
+
%% A character no pdfTeX font sets (accented Greek, Chinese, an emoji) stays
|
|
43
|
+
%% blank instead of stopping the compile, and the log says so in LuaLaTeX's
|
|
44
|
+
%% words, which the export turns into its warning about blank characters.
|
|
45
|
+
\def\UTFviii@undefined@err#1{%
|
|
46
|
+
\typeout{Missing character: There is no
|
|
47
|
+
\expandafter\UTFviii@splitcsname\string#1\relax\space in font pdftex!}}
|
|
48
|
+
\else
|
|
49
|
+
%% Latin Modern for text and math. unicode-math is also what lets a tagged
|
|
50
|
+
%% PDF carry MathML for every formula (luamml needs it); bm does not work
|
|
51
|
+
%% with it, so \bm becomes \boldsymbol.
|
|
52
|
+
\RequirePackage{unicode-math}
|
|
53
|
+
\providecommand{\bm}{\boldsymbol}
|
|
54
|
+
%% Latin Modern has no Greek, Cyrillic, Chinese, Japanese, Korean or emoji.
|
|
55
|
+
%% With `scripts`, prose in those scripts comes from fallback fonts: for each
|
|
56
|
+
%% script, the first of the fonts below this machine has (CMU Serif, from
|
|
57
|
+
%% TeX Live's cm-unicode, matches Latin Modern). A script none of them
|
|
58
|
+
%% covers stays blank, and the export warns about it.
|
|
59
|
+
\ifexplico@scripts
|
|
60
|
+
\def\explico@fallbacks{}
|
|
61
|
+
\def\explico@fallback#1#2{%
|
|
62
|
+
\let\explico@found\@empty
|
|
63
|
+
\@for\explico@candidate:=#1\do{%
|
|
64
|
+
\ifx\explico@found\@empty
|
|
65
|
+
\IfFontExistsTF{\explico@candidate}{%
|
|
66
|
+
\edef\explico@fallbacks{\explico@fallbacks"\explico@candidate:mode=harf;",}%
|
|
67
|
+
\let\explico@found\explico@candidate}{}%
|
|
68
|
+
\fi}%
|
|
69
|
+
\ifx\explico@found\@empty\else#2\fi}
|
|
70
|
+
\explico@fallback{CMU Serif,Noto Serif,DejaVu Serif,FreeSerif}{\explico@greektrue}
|
|
71
|
+
\explico@fallback{Noto Serif CJK SC,Noto Sans CJK SC,FandolSong,Source Han Serif SC}{}
|
|
72
|
+
\explico@fallback{Noto Color Emoji,Twemoji Mozilla,Symbola}{}
|
|
73
|
+
\ifx\explico@fallbacks\@empty\else
|
|
74
|
+
\directlua{luaotfload.add_fallback("explico", {\explico@fallbacks})}%
|
|
75
|
+
\setmainfont{Latin Modern Roman}[RawFeature={fallback=explico}]%
|
|
76
|
+
\fi
|
|
77
|
+
\fi
|
|
78
|
+
\fi
|
|
79
|
+
\RequirePackage{microtype}
|
|
80
|
+
|
|
81
|
+
%% --- Page and colour --------------------------------------------------------
|
|
82
|
+
\RequirePackage[margin=1in]{geometry}
|
|
83
|
+
\RequirePackage{xcolor}
|
|
84
|
+
\definecolor{explicoaccent}{HTML}{12775C}
|
|
85
|
+
\definecolor{explicoframe}{HTML}{9DB8AD}
|
|
86
|
+
\definecolor{explicoback}{HTML}{F3F8F6}
|
|
87
|
+
\definecolor{explicoasidecaution}{HTML}{B5651D}
|
|
88
|
+
\definecolor{explicoasidecautionback}{HTML}{FBF3EA}
|
|
89
|
+
\definecolor{explicorule}{HTML}{8A9A93}
|
|
90
|
+
|
|
91
|
+
%% --- Floats, tables and captions -------------------------------------------
|
|
92
|
+
\RequirePackage{graphicx}
|
|
93
|
+
\RequirePackage{array,booktabs,tabularx,longtable}
|
|
94
|
+
\RequirePackage[export]{adjustbox}
|
|
95
|
+
\RequirePackage{caption}
|
|
96
|
+
\RequirePackage{newfloat}
|
|
97
|
+
\DeclareFloatingEnvironment[
|
|
98
|
+
name=Diagram,
|
|
99
|
+
listname={List of Diagrams},
|
|
100
|
+
fileext=lod,
|
|
101
|
+
placement=htbp,
|
|
102
|
+
]{diagram}
|
|
103
|
+
%% Tagging names each float type's structures from TeX Live 2026 on, and a
|
|
104
|
+
%% caption in a type it was not told about stops LuaLaTeX. TeX Live 2025 has
|
|
105
|
+
%% no such key and tags every float alike.
|
|
106
|
+
\ExplSyntaxOn
|
|
107
|
+
\keys_if_exist:nnT { __tag/setup } { float/new }
|
|
108
|
+
{ \tagpdfsetup { float/new = diagram } }
|
|
109
|
+
\ExplSyntaxOff
|
|
110
|
+
%% Contents and lists: room for explico's numbers (`2.1`, `2.1.10`), wider
|
|
111
|
+
%% than the book class's one-level chapter numbers.
|
|
112
|
+
\RequirePackage{etoolbox}
|
|
113
|
+
\patchcmd{\l@chapter}{1.5em}{2.6em}{}{}
|
|
114
|
+
\renewcommand*{\l@section}{\@dottedtocline{1}{2.6em}{3.4em}}
|
|
115
|
+
\renewcommand*{\l@subsection}{\@dottedtocline{2}{6.0em}{4.2em}}
|
|
116
|
+
\renewcommand*{\l@figure}{\@dottedtocline{1}{0em}{3.4em}}
|
|
117
|
+
\let\l@table\l@figure
|
|
118
|
+
\let\l@diagram\l@figure
|
|
119
|
+
\captionsetup{font=small,labelsep=quad,format=plain,justification=justified,singlelinecheck=true}
|
|
120
|
+
\captionsetup[table]{position=top}
|
|
121
|
+
%% With \DocumentMetadata, which every export's main.tex has, the kernel's
|
|
122
|
+
%% tagging code sets a caption itself (latex-lab's \@makecaption, installed at
|
|
123
|
+
%% begin document) and none of the \captionsetup above applies. Its caption is
|
|
124
|
+
%% the kernel's: \abovecaptionskip above, \belowcaptionskip below, "Table 2.1:"
|
|
125
|
+
%% before the text. A table's caption stands above the table, so it gets the
|
|
126
|
+
%% same space on both sides, whichever code sets it (the caption package swaps
|
|
127
|
+
%% the two for `position=top`); and the label and the size are the ones the
|
|
128
|
+
%% caption package would give, and the web page shows: "Table 2.1", a quad,
|
|
129
|
+
%% the caption in small type.
|
|
130
|
+
\AtBeginEnvironment{table}{%
|
|
131
|
+
\setlength{\abovecaptionskip}{8pt}\setlength{\belowcaptionskip}{8pt}}
|
|
132
|
+
\ExplSyntaxOn
|
|
133
|
+
\socket_if_exist:nT { caption/label }
|
|
134
|
+
{
|
|
135
|
+
\NewSocketPlug { caption/label } { explico } { #1 \quad }
|
|
136
|
+
\AssignSocketPlug { caption/label } { explico }
|
|
137
|
+
\AddToHookWithArguments { cmd/@makecaption/before } { \small }
|
|
138
|
+
}
|
|
139
|
+
\ExplSyntaxOff
|
|
140
|
+
%% A float set where it stands, inside a memo or a worked example, which a
|
|
141
|
+
%% float cannot leave: the float package's [H]. Tagging then gives the float
|
|
142
|
+
%% its caption, as PDF/UA-2 asks. (TeX Live 2026 tags a minipage as a Div,
|
|
143
|
+
%% which a validator looks through, so a \captionof caption in one sits in
|
|
144
|
+
%% the middle of the box's text.) Without the float package: a minipage whose
|
|
145
|
+
%% \caption is the float's, as \captionof does it.
|
|
146
|
+
\newif\ifexplico@float
|
|
147
|
+
\IfFileExists{float.sty}{\RequirePackage{float}\explico@floattrue}{}
|
|
148
|
+
\ifexplico@float
|
|
149
|
+
\newenvironment{ExplicoHere}[1]{%
|
|
150
|
+
\def\explico@herekind{#1}\begin{#1}[H]\centering
|
|
151
|
+
}{\expandafter\end\expandafter{\explico@herekind}}
|
|
152
|
+
\else
|
|
153
|
+
\newenvironment{ExplicoHere}[1]{%
|
|
154
|
+
\par\medskip\noindent\begin{minipage}{\linewidth}\centering
|
|
155
|
+
\captionsetup{type=#1}%
|
|
156
|
+
}{\end{minipage}\par\medskip}
|
|
157
|
+
\fi
|
|
158
|
+
%% explico's short caption, run in bold before the long one.
|
|
159
|
+
\newcommand*{\ExplicoCaptionTitle}[1]{\textbf{#1}}
|
|
160
|
+
|
|
161
|
+
%% --- Diagrams ---------------------------------------------------------------
|
|
162
|
+
\RequirePackage{tikz}
|
|
163
|
+
\usetikzlibrary{arrows.meta}
|
|
164
|
+
\tikzset{
|
|
165
|
+
explico diagram node/.style={
|
|
166
|
+
draw=explicorule, fill=explicoback, rounded corners=3pt, line width=0.5pt,
|
|
167
|
+
align=center, inner sep=3pt, font=\small,
|
|
168
|
+
},
|
|
169
|
+
explico diagram edge/.style={
|
|
170
|
+
draw=explicorule, line width=0.6pt, -{Stealth[length=5pt,width=4pt]},
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
%% --- Boxes: memos, notes, asides, worked examples, checks ------------------
|
|
175
|
+
\RequirePackage[most]{tcolorbox}
|
|
176
|
+
\tcbset{
|
|
177
|
+
explico/.style={
|
|
178
|
+
enhanced, breakable, colback=explicoback, colframe=explicoframe,
|
|
179
|
+
boxrule=0.5pt, arc=2pt, left=6pt, right=6pt, top=4pt, bottom=4pt,
|
|
180
|
+
fonttitle=\bfseries\small, coltitle=black, colbacktitle=explicoback!60!white,
|
|
181
|
+
titlerule=0.4pt, before skip=10pt plus 2pt, after skip=10pt plus 2pt,
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
\RequirePackage{alphalph}
|
|
185
|
+
\RequirePackage{enumitem}
|
|
186
|
+
|
|
187
|
+
%% --- Unicode in text that the default fonts lack ---------------------------
|
|
188
|
+
\RequirePackage{newunicodechar}
|
|
189
|
+
\newunicodechar{°}{\ifmmode^\circ\else\textdegree\fi}
|
|
190
|
+
\newunicodechar{−}{\ensuremath{-}}
|
|
191
|
+
\newunicodechar{×}{\ensuremath{\times}}
|
|
192
|
+
\newunicodechar{±}{\ensuremath{\pm}}
|
|
193
|
+
\newunicodechar{≤}{\ensuremath{\le}}
|
|
194
|
+
\newunicodechar{≥}{\ensuremath{\ge}}
|
|
195
|
+
\newunicodechar{≈}{\ensuremath{\approx}}
|
|
196
|
+
\newunicodechar{≠}{\ensuremath{\neq}}
|
|
197
|
+
\newunicodechar{→}{\ensuremath{\rightarrow}}
|
|
198
|
+
\newunicodechar{←}{\ensuremath{\leftarrow}}
|
|
199
|
+
\newunicodechar{↑}{\ensuremath{\uparrow}}
|
|
200
|
+
\newunicodechar{↓}{\ensuremath{\downarrow}}
|
|
201
|
+
\newunicodechar{⟨}{\ensuremath{\langle}}
|
|
202
|
+
\newunicodechar{⟩}{\ensuremath{\rangle}}
|
|
203
|
+
\newunicodechar{⋮}{\ensuremath{\vdots}}
|
|
204
|
+
\newunicodechar{√}{\ensuremath{\surd}}
|
|
205
|
+
\newunicodechar{∞}{\ensuremath{\infty}}
|
|
206
|
+
\newunicodechar{′}{\ensuremath{'}}
|
|
207
|
+
\newunicodechar{𝒩}{\ensuremath{\mathcal{N}}}
|
|
208
|
+
\newunicodechar{①}{\textcircled{\scriptsize 1}}
|
|
209
|
+
\newunicodechar{②}{\textcircled{\scriptsize 2}}
|
|
210
|
+
\newunicodechar{③}{\textcircled{\scriptsize 3}}
|
|
211
|
+
\newunicodechar{④}{\textcircled{\scriptsize 4}}
|
|
212
|
+
\newunicodechar{⑤}{\textcircled{\scriptsize 5}}
|
|
213
|
+
\newunicodechar{₀}{\textsubscript{0}}
|
|
214
|
+
\newunicodechar{₁}{\textsubscript{1}}
|
|
215
|
+
\newunicodechar{₂}{\textsubscript{2}}
|
|
216
|
+
\newunicodechar{₃}{\textsubscript{3}}
|
|
217
|
+
\newunicodechar{¹}{\textsuperscript{1}}
|
|
218
|
+
\newunicodechar{²}{\textsuperscript{2}}
|
|
219
|
+
\newunicodechar{³}{\textsuperscript{3}}
|
|
220
|
+
%% A Greek letter on its own is a symbol (the polar coordinates ρ and φ in a
|
|
221
|
+
%% caption, which holds no math): it is set as its math symbol. Inside a Greek
|
|
222
|
+
%% word, which the exporter marks \ExplicoGreekWord{…}, it is a letter, set
|
|
223
|
+
%% from the text font's Greek where one is loaded (`scripts`).
|
|
224
|
+
\newif\ifexplico@word
|
|
225
|
+
\DeclareRobustCommand{\ExplicoGreekWord}[1]{{\explico@wordtrue#1}}
|
|
226
|
+
%% Protected, as \ensuremath is: the text of an equation is expanded for its
|
|
227
|
+
%% tagging (alt text, MathML), and an expandable body breaks it there.
|
|
228
|
+
\protected\def\explico@greekletter#1#2{%
|
|
229
|
+
\ifmmode#2\else
|
|
230
|
+
\ifexplico@word
|
|
231
|
+
\ifexplico@greek\char#1\relax\else\ensuremath{#2}\fi
|
|
232
|
+
\else\ensuremath{#2}\fi
|
|
233
|
+
\fi}
|
|
234
|
+
\newunicodechar{α}{\explico@greekletter{"03B1}{\alpha}}
|
|
235
|
+
\newunicodechar{β}{\explico@greekletter{"03B2}{\beta}}
|
|
236
|
+
\newunicodechar{γ}{\explico@greekletter{"03B3}{\gamma}}
|
|
237
|
+
\newunicodechar{δ}{\explico@greekletter{"03B4}{\delta}}
|
|
238
|
+
\newunicodechar{ε}{\explico@greekletter{"03B5}{\varepsilon}}
|
|
239
|
+
\newunicodechar{θ}{\explico@greekletter{"03B8}{\theta}}
|
|
240
|
+
\newunicodechar{λ}{\explico@greekletter{"03BB}{\lambda}}
|
|
241
|
+
\newunicodechar{μ}{\explico@greekletter{"03BC}{\mu}}
|
|
242
|
+
\newunicodechar{π}{\explico@greekletter{"03C0}{\pi}}
|
|
243
|
+
\newunicodechar{ρ}{\explico@greekletter{"03C1}{\rho}}
|
|
244
|
+
\newunicodechar{σ}{\explico@greekletter{"03C3}{\sigma}}
|
|
245
|
+
\newunicodechar{τ}{\explico@greekletter{"03C4}{\tau}}
|
|
246
|
+
\newunicodechar{φ}{\explico@greekletter{"03C6}{\varphi}}
|
|
247
|
+
\newunicodechar{ω}{\explico@greekletter{"03C9}{\omega}}
|
|
248
|
+
\newunicodechar{Γ}{\explico@greekletter{"0393}{\Gamma}}
|
|
249
|
+
\newunicodechar{Δ}{\explico@greekletter{"0394}{\Delta}}
|
|
250
|
+
\newunicodechar{Θ}{\explico@greekletter{"0398}{\Theta}}
|
|
251
|
+
\newunicodechar{Λ}{\explico@greekletter{"039B}{\Lambda}}
|
|
252
|
+
\newunicodechar{Π}{\explico@greekletter{"03A0}{\Pi}}
|
|
253
|
+
\newunicodechar{Σ}{\explico@greekletter{"03A3}{\Sigma}}
|
|
254
|
+
\newunicodechar{Φ}{\explico@greekletter{"03A6}{\Phi}}
|
|
255
|
+
\newunicodechar{Ω}{\explico@greekletter{"03A9}{\Omega}}
|
|
256
|
+
|
|
257
|
+
%% --- Links ------------------------------------------------------------------
|
|
258
|
+
\RequirePackage[colorlinks,linkcolor=explicoaccent,urlcolor=explicoaccent,citecolor=explicoaccent,bookmarksnumbered]{hyperref}
|
|
259
|
+
\pdfstringdefDisableCommands{\let\ExplicoGreekWord\@firstofone}
|
|
260
|
+
|
|
261
|
+
%% --- Numbering --------------------------------------------------------------
|
|
262
|
+
\renewcommand{\thepart}{\arabic{part}}
|
|
263
|
+
\counterwithin*{chapter}{part}
|
|
264
|
+
\renewcommand{\thechapter}{\thepart.\arabic{chapter}}
|
|
265
|
+
\newcounter{explicoexample}
|
|
266
|
+
\newcounter{explicocheck}
|
|
267
|
+
\newcounter{explicomemo}[chapter]
|
|
268
|
+
\renewcommand{\theexplicomemo}{\alphalph{\value{explicomemo}}}
|
|
269
|
+
\counterwithin{equation}{chapter}
|
|
270
|
+
\counterwithin{figure}{chapter}
|
|
271
|
+
\counterwithin{table}{chapter}
|
|
272
|
+
\counterwithin{diagram}{chapter}
|
|
273
|
+
\counterwithin{explicoexample}{chapter}
|
|
274
|
+
\counterwithin{explicocheck}{chapter}
|
|
275
|
+
%% Floats, examples and checks run on across each part's chapters.
|
|
276
|
+
\newcommand{\ExplicoFloatsByPart}{%
|
|
277
|
+
\@for\explico@kind:=equation,figure,table,diagram,explicoexample,explicocheck\do{%
|
|
278
|
+
\expandafter\counterwithout\expandafter{\explico@kind}{chapter}%
|
|
279
|
+
\expandafter\counterwithin\expandafter{\explico@kind}{part}%
|
|
280
|
+
}%
|
|
281
|
+
}
|
|
282
|
+
%% Outline numbering down to explico's `numbering.sections.depth`
|
|
283
|
+
%% (2 = ## … 6 = ######); 1 numbers no sections.
|
|
284
|
+
\newcommand{\ExplicoSectionDepth}[1]{%
|
|
285
|
+
\setcounter{secnumdepth}{\numexpr#1-1\relax}%
|
|
286
|
+
\setcounter{tocdepth}{\numexpr#1-1\relax}%
|
|
287
|
+
}
|
|
288
|
+
\ExplicoSectionDepth{4}
|
|
289
|
+
%% A chapter on its own starts where the course leaves it: part and chapter
|
|
290
|
+
%% number, and how many floats of each kind come earlier in the part.
|
|
291
|
+
%% #1 part, #2 chapter, #3 equations, #4 tables, #5 figures, #6 diagrams,
|
|
292
|
+
%% #7 checks, #8 examples.
|
|
293
|
+
\newcommand{\ExplicoStartChapterAt}[8]{%
|
|
294
|
+
\setcounter{part}{#1}%
|
|
295
|
+
\setcounter{chapter}{\numexpr#2-1\relax}%
|
|
296
|
+
\gdef\explico@offsets{{#3}{#4}{#5}{#6}{#7}{#8}}%
|
|
297
|
+
}
|
|
298
|
+
\gdef\explico@offsets{}
|
|
299
|
+
%% After \chapter, so a chapter's own reset cannot undo them.
|
|
300
|
+
\newcommand{\ExplicoApplyOffsets}{%
|
|
301
|
+
\ifx\explico@offsets\@empty\else
|
|
302
|
+
\expandafter\explico@applyoffsets\explico@offsets
|
|
303
|
+
\gdef\explico@offsets{}%
|
|
304
|
+
\fi
|
|
305
|
+
}
|
|
306
|
+
\newcommand{\explico@applyoffsets}[6]{%
|
|
307
|
+
\setcounter{equation}{#1}\setcounter{table}{#2}\setcounter{figure}{#3}%
|
|
308
|
+
\setcounter{diagram}{#4}\setcounter{explicocheck}{#5}\setcounter{explicoexample}{#6}%
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
%% --- Chapter front line -----------------------------------------------------
|
|
312
|
+
%% Under a chapter's title: where it comes from and where its live version is.
|
|
313
|
+
\newcommand{\ExplicoSource}[3]{%
|
|
314
|
+
\begingroup\small\color{black!65}%
|
|
315
|
+
\noindent From \emph{#1}%
|
|
316
|
+
\if\relax\detokenize{#2}\relax\else, version~#2\fi.%
|
|
317
|
+
\if\relax\detokenize{#3}\relax\else\ Interactive version: \url{#3}\fi
|
|
318
|
+
\par\endgroup\medskip
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
%% --- Books: a part's or the course's PDF ------------------------------------
|
|
322
|
+
%% The title page. #1 title, #2 what it belongs to (empty for the course),
|
|
323
|
+
%% #3 content version, #4 authors, #5 website.
|
|
324
|
+
\newcommand{\ExplicoTitlePage}[5]{%
|
|
325
|
+
%% The title page shares page number i with the contents: no anchor of its own.
|
|
326
|
+
\hypersetup{pageanchor=false}%
|
|
327
|
+
\begin{titlepage}
|
|
328
|
+
\centering
|
|
329
|
+
\vspace*{0.18\textheight}
|
|
330
|
+
{\Huge\bfseries #1\par}
|
|
331
|
+
\if\relax\detokenize{#2}\relax\else\vspace{0.8em}{\Large #2\par}\fi
|
|
332
|
+
\if\relax\detokenize{#4}\relax\else\vspace{2.5em}{\large #4\par}\fi
|
|
333
|
+
\vfill
|
|
334
|
+
{Content version~#3\par}
|
|
335
|
+
\if\relax\detokenize{#5}\relax\else\vspace{0.4em}{\small\url{#5}\par}\fi
|
|
336
|
+
\end{titlepage}%
|
|
337
|
+
\hypersetup{pageanchor=true}%
|
|
338
|
+
}
|
|
339
|
+
%% Under a chapter's title in a book: its live version. The title page names
|
|
340
|
+
%% the course and its version once.
|
|
341
|
+
\newcommand{\ExplicoInteractive}[1]{%
|
|
342
|
+
\begingroup\small\color{black!65}%
|
|
343
|
+
\noindent Interactive version: \url{#1}\par\endgroup\medskip
|
|
344
|
+
}
|
|
345
|
+
%% A part opens on its own page, numbered as on the website.
|
|
346
|
+
\newcommand{\ExplicoPart}[2]{\setcounter{part}{\numexpr#1-1\relax}\part{#2}}
|
|
347
|
+
|
|
348
|
+
%% --- Notation ---------------------------------------------------------------
|
|
349
|
+
%% \explain{key}{tex} and \slot{key}{tex} are explico's markers in math: the
|
|
350
|
+
%% website opens a card for the key; on paper they print their content.
|
|
351
|
+
\providecommand{\explain}[2]{#2}
|
|
352
|
+
\providecommand{\slot}[2]{#2}
|
|
353
|
+
%% \ExplicoNotation{target}{tex}: a formula's symbol that links to its notation entry
|
|
354
|
+
%% (the serializer writes it only where the book has that entry).
|
|
355
|
+
\providecommand{\ExplicoNotation}[2]{\hyperlink{#1}{#2}}
|
|
356
|
+
%% A term in prose with a notation card on the website.
|
|
357
|
+
\newcommand{\ExplicoTerm}[2]{#2}
|
|
358
|
+
|
|
359
|
+
%% --- Cross-references ---------------------------------------------------------
|
|
360
|
+
%% #1 label, #2 text before the number, #3 text after it.
|
|
361
|
+
\newcommand{\ExplicoRef}[3]{\hyperref[#1]{#2\ref*{#1}#3}}
|
|
362
|
+
\newcommand{\ExplicoEqRef}[1]{\hyperref[#1]{(\ref*{#1})}}
|
|
363
|
+
|
|
364
|
+
%% --- Memos --------------------------------------------------------------------
|
|
365
|
+
\newenvironment{ExplicoMemo}[1]{%
|
|
366
|
+
\refstepcounter{explicomemo}%
|
|
367
|
+
\begin{tcolorbox}[explico,title={Memo~\theexplicomemo:\enspace #1}]%
|
|
368
|
+
}{\end{tcolorbox}}
|
|
369
|
+
\newcommand{\ExplicoMemoMark}[1]{\textsuperscript{\hyperref[#1]{\ref*{#1}}}}
|
|
370
|
+
|
|
371
|
+
%% --- Short notes ----------------------------------------------------------------
|
|
372
|
+
\newenvironment{ExplicoNote}[2]{%
|
|
373
|
+
\begin{tcolorbox}[explico,colback=white,title={#2}]%
|
|
374
|
+
\hypertarget{#1}{}%
|
|
375
|
+
}{\end{tcolorbox}}
|
|
376
|
+
\newcommand{\ExplicoNoteMark}[2]{\hyperlink{#1}{#2}}
|
|
377
|
+
|
|
378
|
+
%% --- Starlight asides -------------------------------------------------------------
|
|
379
|
+
\newenvironment{ExplicoAside}[2]{%
|
|
380
|
+
\def\explico@variant{#1}\def\explico@caution{caution}\def\explico@danger{danger}%
|
|
381
|
+
\ifx\explico@variant\explico@caution
|
|
382
|
+
\tcbset{explico/.append style={colframe=explicoasidecaution,colback=explicoasidecautionback}}%
|
|
383
|
+
\else\ifx\explico@variant\explico@danger
|
|
384
|
+
\tcbset{explico/.append style={colframe=explicoasidecaution,colback=explicoasidecautionback}}%
|
|
385
|
+
\fi\fi
|
|
386
|
+
\begin{tcolorbox}[explico,title={#2}]%
|
|
387
|
+
}{\end{tcolorbox}}
|
|
388
|
+
|
|
389
|
+
%% --- Worked examples ---------------------------------------------------------------
|
|
390
|
+
\newenvironment{ExplicoExamples}[1]{%
|
|
391
|
+
\refstepcounter{explicoexample}%
|
|
392
|
+
\begin{tcolorbox}[explico,title={Example~\theexplicoexample:\enspace #1}]%
|
|
393
|
+
}{\end{tcolorbox}}
|
|
394
|
+
\newcommand{\ExplicoExample}[1]{\par\medskip\noindent\textbf{#1}\par\nopagebreak\smallskip}
|
|
395
|
+
|
|
396
|
+
%% --- Knowledge checks -----------------------------------------------------------
|
|
397
|
+
\newenvironment{ExplicoCheck}[1]{%
|
|
398
|
+
\refstepcounter{explicocheck}%
|
|
399
|
+
\begin{tcolorbox}[explico,colback=white,title={Knowledge check~\theexplicocheck:\enspace #1}]%
|
|
400
|
+
}{\end{tcolorbox}}
|
|
401
|
+
\newcommand{\ExplicoCheckAnswerNote}[1]{\par\smallskip{\small\itshape Answers: \hyperlink{#1}{end of the chapter}.}\par}
|
|
402
|
+
|
|
403
|
+
%% --- References ---------------------------------------------------------------------
|
|
404
|
+
%% The chapter's reference list, numbered as on the website.
|
|
405
|
+
\newenvironment{ExplicoReferences}[1]{%
|
|
406
|
+
\section*{References}%
|
|
407
|
+
\list{\@biblabel{\@arabic\c@enumiv}}{%
|
|
408
|
+
\settowidth\labelwidth{\@biblabel{#1}}%
|
|
409
|
+
\leftmargin\labelwidth\advance\leftmargin\labelsep
|
|
410
|
+
\@openbib@code\usecounter{enumiv}\let\p@enumiv\@empty
|
|
411
|
+
\renewcommand\theenumiv{\@arabic\c@enumiv}}%
|
|
412
|
+
\sloppy\clubpenalty4000\@clubpenalty\clubpenalty\widowpenalty4000\sfcode`\.\@m
|
|
413
|
+
}{\def\@noitemerr{\@latex@warning{Empty `ExplicoReferences' environment}}\endlist}
|
|
414
|
+
|
|
415
|
+
\endinput
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Block, StaticPage } from '../static-tree';
|
|
2
|
+
import { labelOf } from './serialize';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The LaTeX source counts its own numbers (`\label`, `\ref`), so an edited
|
|
6
|
+
* download renumbers itself. When explico compiles the source unchanged,
|
|
7
|
+
* every number LaTeX prints must be the number the website prints: this
|
|
8
|
+
* module reads both and lists any disagreement, which fails the build.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** The number the website gives each labelled anchor of a page, by LaTeX label. */
|
|
12
|
+
export function websiteNumbers(page: StaticPage, chapterNumber: string): Map<string, string> {
|
|
13
|
+
const numbers = new Map<string, string>([[labelOf(page.route, '_top'), chapterNumber]]);
|
|
14
|
+
const add = (anchor: string | undefined, number: string | undefined) => {
|
|
15
|
+
if (anchor && number) numbers.set(labelOf(page.route, anchor), number);
|
|
16
|
+
};
|
|
17
|
+
const visit = (blocks: readonly Block[]) => {
|
|
18
|
+
for (const block of blocks) {
|
|
19
|
+
switch (block.kind) {
|
|
20
|
+
case 'heading':
|
|
21
|
+
add(block.anchor, block.number);
|
|
22
|
+
break;
|
|
23
|
+
case 'equation':
|
|
24
|
+
case 'figure':
|
|
25
|
+
case 'table':
|
|
26
|
+
case 'diagram':
|
|
27
|
+
case 'examples':
|
|
28
|
+
case 'check':
|
|
29
|
+
add(block.anchor, block.number);
|
|
30
|
+
break;
|
|
31
|
+
case 'memo':
|
|
32
|
+
add(block.anchor, block.label);
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
if (block.kind === 'list') block.items.forEach(visit);
|
|
38
|
+
if (block.kind === 'examples') block.items.forEach((item) => visit(item.children));
|
|
39
|
+
if (
|
|
40
|
+
'children' in block &&
|
|
41
|
+
block.kind !== 'paragraph' &&
|
|
42
|
+
block.kind !== 'heading' &&
|
|
43
|
+
Array.isArray(block.children)
|
|
44
|
+
) {
|
|
45
|
+
visit(block.children as readonly Block[]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
visit(page.blocks);
|
|
50
|
+
return numbers;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** `\newlabel{label}{{number}{page}…}` lines of a LaTeX `.aux` file. */
|
|
54
|
+
export function auxLabels(aux: string): Map<string, string> {
|
|
55
|
+
const labels = new Map<string, string>();
|
|
56
|
+
for (const match of aux.matchAll(/^\\newlabel\{([^}]*)\}\{\{([^}]*)\}/gmu)) {
|
|
57
|
+
labels.set(match[1]!, match[2]!);
|
|
58
|
+
}
|
|
59
|
+
return labels;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Every label whose LaTeX number differs from the website's, or that LaTeX never set. */
|
|
63
|
+
export function numberingMismatches(
|
|
64
|
+
website: ReadonlyMap<string, string>,
|
|
65
|
+
latex: ReadonlyMap<string, string>,
|
|
66
|
+
): string[] {
|
|
67
|
+
const problems: string[] = [];
|
|
68
|
+
for (const [label, expected] of website) {
|
|
69
|
+
const actual = latex.get(label);
|
|
70
|
+
if (actual === undefined) problems.push(`${label}: no number in LaTeX (website: ${expected})`);
|
|
71
|
+
else if (actual !== expected) problems.push(`${label}: LaTeX ${actual}, website ${expected}`);
|
|
72
|
+
}
|
|
73
|
+
return problems;
|
|
74
|
+
}
|