explico 0.11.1 → 0.13.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.
- package/CHANGELOG.md +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- 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 +15 -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 +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -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 +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- 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/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -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-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -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-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- 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 +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- 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 +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- 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 +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- 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 +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- 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 +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- 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/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -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 +300 -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 +66 -8
- 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 +14 -22
- 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 +8 -10
- 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/figure-symbols.ts +117 -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-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- 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-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- 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 +275 -23
- package/src/reference/render-lab-math.ts +40 -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 +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ What it gives a course:
|
|
|
22
22
|
per glyph per page, enforced corpus-wide. Named operators get the same
|
|
23
23
|
treatment one tier softer: a lesson's `\operatorname{Var}` is a warning
|
|
24
24
|
(`operator-explained`) until it carries an entry or the course lists it in
|
|
25
|
-
`
|
|
25
|
+
`rules.N8.allow`; a shipped baseline (`\exp`, `\int`, trig, …) is exempt.
|
|
26
26
|
- **Inline citations** — `[@source-id; locator]` → numbered marker + generated
|
|
27
27
|
reference list, resolved against a schema-checked source collection.
|
|
28
28
|
- **Equation identity** — `\label{eq:key}` gives a display equation a stable
|
|
@@ -187,8 +187,8 @@ or, without one, the numbers and short captions of the floats inside
|
|
|
187
187
|
|
|
188
188
|
### Lesson exports
|
|
189
189
|
|
|
190
|
-
A course can opt into
|
|
191
|
-
|
|
190
|
+
A course can opt into self-contained HTML downloads of each chapter, each part
|
|
191
|
+
and the whole course, and browser-native printing of every page:
|
|
192
192
|
|
|
193
193
|
```ts
|
|
194
194
|
export const courseConfig: CourseConfig = {
|
|
@@ -202,18 +202,36 @@ export const courseConfig: CourseConfig = {
|
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
The existing `explicoContentRefresh(courseConfig, manifest)` integration emits
|
|
205
|
-
`downloads/<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
`downloads/<docs-slug>.html` for each chapter after Astro's static build, and
|
|
206
|
+
adds a Download button to the top-right header cluster on each page. It opens a
|
|
207
|
+
menu of the scopes that contain the page — "This chapter" on a chapter, "This
|
|
208
|
+
part" on a chapter or its part's page, "Whole course" everywhere — with their
|
|
209
|
+
sizes, read from `downloads/index.json`, which the build writes last. A page
|
|
210
|
+
that is not a chapter (the landing page, a part's page, the glossary) has no
|
|
211
|
+
file of its own: it is in its part's file and the course's. The Print button
|
|
212
|
+
sits beside the menu, and Ctrl+P / Cmd+P run the same print preparation.
|
|
213
|
+
During `astro dev`, the first request for a chapter's file runs an isolated
|
|
214
|
+
static build and streams the resulting file; later requests use that result
|
|
215
|
+
until a watched source file changes. The downloaded file contains its CSS,
|
|
210
216
|
KaTeX fonts, images, client scripts, Astro island components, and renderer; it
|
|
211
217
|
opens directly through `file://` without a server or network access. Search,
|
|
212
218
|
sidebars, pagination, and other site chrome are omitted. Same-page references
|
|
213
|
-
stay local, while links that leave the
|
|
219
|
+
stay local, while links that leave the page use `canonicalBaseUrl` and
|
|
214
220
|
cross-lesson hover previews degrade to ordinary links. A retained theme control
|
|
215
221
|
lets an offline reader choose Light, Dark, or Auto; Auto follows changes to the
|
|
216
|
-
viewer’s system color scheme.
|
|
222
|
+
viewer’s system color scheme. Ctrl+P and Cmd+P load the file's labs before the
|
|
223
|
+
print dialog, as on the site.
|
|
224
|
+
|
|
225
|
+
Each part and the whole course also download as one offline file:
|
|
226
|
+
`downloads/part/<dir>.html` is the part's page and then its chapters, and
|
|
227
|
+
`downloads/course.html` is the landing page, the curriculum map, the figures and
|
|
228
|
+
tables, every part, and the glossary last, each opening with a list of
|
|
229
|
+
contents. They are assembled from the pages the build wrote, so each page keeps
|
|
230
|
+
its own cards, labs and checks. Every id gains the page as a suffix
|
|
231
|
+
(`eq-range--projectiles-projectile-range`), and a reference to another page in
|
|
232
|
+
the same file becomes a link into it, whose hover preview works offline. Each
|
|
233
|
+
page is a section with `content-visibility: auto`, which keeps a long course
|
|
234
|
+
responsive, and starts a new sheet when printed.
|
|
217
235
|
|
|
218
236
|
The **Print / save as PDF** action calls the browser's native print dialog; it
|
|
219
237
|
does not download or build a `.pdf` file itself. The print layout removes site
|
|
@@ -227,12 +245,72 @@ visual result, and keeps linked text clickable with canonical destinations.
|
|
|
227
245
|
Paper size, margins, browser-added headers/footers, final filename, and the
|
|
228
246
|
choice to save as PDF remain browser and reader settings.
|
|
229
247
|
|
|
230
|
-
Set `canonicalBaseUrl` to the deployed course root whenever retained
|
|
231
|
-
content links elsewhere in the course.
|
|
232
|
-
the
|
|
248
|
+
Set `canonicalBaseUrl` to the deployed course root whenever retained page
|
|
249
|
+
content links elsewhere in the course. With `standaloneHtml` on that is
|
|
250
|
+
practically always: a chapter links to the glossary and to other chapters. If such a link exists without the base, the build fails rather than
|
|
251
|
+
shipping a dead local link. An unresolved or remote
|
|
233
252
|
stylesheet, script, font, image, iframe, media source, worker, WASM file, or CSS
|
|
234
253
|
URL likewise fails the standalone export audit.
|
|
235
254
|
|
|
255
|
+
#### Markdown
|
|
256
|
+
|
|
257
|
+
`markdown: true` writes each chapter, each part and the whole course as
|
|
258
|
+
Markdown after Astro's static build: `downloads/<slug>-markdown.zip`
|
|
259
|
+
(`lesson.md` and its `assets/`), `downloads/part/<dir>-markdown.zip` and
|
|
260
|
+
`downloads/course-markdown.zip` (an `index.md`, one file per chapter, shared
|
|
261
|
+
`assets/`, relative links). It is GitHub's flavour with `$…$` math, so GitHub,
|
|
262
|
+
Obsidian or remark-math with KaTeX shows it as written. Headings, equations and
|
|
263
|
+
floats keep their numbers; each chapter ends with its references, its notation
|
|
264
|
+
and the answers to its checks. A figure the browser draws is a PNG at 2× (it
|
|
265
|
+
needs Playwright with Chromium, as LaTeX does); a `<Diagram>` is a PNG with its
|
|
266
|
+
boxes and arrows listed as text.
|
|
267
|
+
|
|
268
|
+
#### LaTeX source and PDF
|
|
269
|
+
|
|
270
|
+
`latex: true` adds two downloads per chapter, both built after Astro's static
|
|
271
|
+
build:
|
|
272
|
+
|
|
273
|
+
- `downloads/<slug>-latex.zip` — the chapter's LaTeX folder: `main.tex`,
|
|
274
|
+
explico's book class `explico.cls`, the chapter as readable source, its
|
|
275
|
+
figures, a `latexmkrc` and a README. Unzip it and run `latexmk`.
|
|
276
|
+
- `downloads/<slug>.pdf` — that same folder compiled: a tagged PDF 2.0
|
|
277
|
+
(PDF/UA-2) with the chapter's answer key at its end.
|
|
278
|
+
- `downloads/part/<dir>-latex.zip` and `.pdf`, `downloads/course-latex.zip`
|
|
279
|
+
and `.pdf` — each part and the whole course as a book: title page,
|
|
280
|
+
contents, lists of figures, tables and diagrams, each part opening with its
|
|
281
|
+
page's text, its chapters, and notation and abbreviation appendices.
|
|
282
|
+
|
|
283
|
+
Every document compiles at once, up to one per core.
|
|
284
|
+
|
|
285
|
+
Numbers are LaTeX's own (`\label`, `\ref`), set up to count the way the website
|
|
286
|
+
does; the build compiles the source unchanged and fails if any number differs
|
|
287
|
+
from the website's. Figures stay vector: a lab is captured from the finished
|
|
288
|
+
site by Chromium, and a `<Diagram>` is drawn as TikZ from its build-time
|
|
289
|
+
layout. `latexPaper` is `letter` (default) or `a4`.
|
|
290
|
+
|
|
291
|
+
Prose in another script reaches the PDF too. A Greek letter on its own is a
|
|
292
|
+
symbol and is set as math; a Greek word, Cyrillic, Chinese, Japanese, Korean
|
|
293
|
+
and emoji come from fallback fonts under LuaLaTeX, the first the build machine
|
|
294
|
+
has of CMU Serif (TeX Live's `cm-unicode`), Noto Serif or DejaVu Serif for
|
|
295
|
+
Greek and Cyrillic, Noto CJK or Fandol, and Noto Color Emoji. A character no
|
|
296
|
+
font sets stays blank, and the build warns with its name; under pdfLaTeX, which
|
|
297
|
+
has none of these fonts, every such character does.
|
|
298
|
+
|
|
299
|
+
The build needs TeX Live 2025 or later with `latexmk` and LuaLaTeX
|
|
300
|
+
(`EXPLICO_LATEX_ENGINE=pdflatex` switches to pdfLaTeX), and Playwright with
|
|
301
|
+
Chromium in the course for figures a browser draws. In CI (`CI` set) a missing
|
|
302
|
+
engine or browser fails the build; on a machine without them the build warns
|
|
303
|
+
and still writes the source zips. On GitHub Actions:
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
- uses: zauguin/install-texlive@v4
|
|
307
|
+
with:
|
|
308
|
+
texlive_version: 2026
|
|
309
|
+
package_file: node_modules/explico/src/compiler/exports/latex/texlive-packages.txt
|
|
310
|
+
- run: pnpm exec playwright install --with-deps chromium
|
|
311
|
+
- run: pnpm build
|
|
312
|
+
```
|
|
313
|
+
|
|
236
314
|
```jsonc
|
|
237
315
|
// package.json — the read-side CLI
|
|
238
316
|
"scripts": { "validate:content": "tsx scripts/compile-manifest.ts" }
|
package/dist/compiler/astro.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AstroConfig, AstroIntegration } from 'astro';
|
|
2
|
-
import { C as CourseConfig } from '../course-config-
|
|
2
|
+
import { C as CourseConfig } from '../course-config-rRtME5UV.js';
|
|
3
3
|
import { Manifest } from './manifest.js';
|
|
4
4
|
import '../rules/catalog.js';
|
|
5
5
|
import '../rules/course-rules.js';
|
|
@@ -7,6 +7,7 @@ import '../curriculum/validation.js';
|
|
|
7
7
|
import '../reference/consistency.js';
|
|
8
8
|
import './collections.js';
|
|
9
9
|
import '../reference/types.js';
|
|
10
|
+
import '../reference/gate-retired-keys.js';
|
|
10
11
|
import '../reference/lint-ignore.js';
|
|
11
12
|
import '../reference/equations-validate.js';
|
|
12
13
|
import '../reference/tables-validate.js';
|
|
@@ -17,6 +18,7 @@ import '../reference/examples-validate.js';
|
|
|
17
18
|
import '../reference/folds-validate.js';
|
|
18
19
|
import '../reference/knowledge-checks-validate.js';
|
|
19
20
|
import '../reference/raw-floats-validate.js';
|
|
21
|
+
import '../reference/lab-katex-validate.js';
|
|
20
22
|
import '../reference/gate-math.js';
|
|
21
23
|
import '../reference/mixed-content.js';
|
|
22
24
|
import '../reference/gloss.js';
|
|
@@ -24,9 +26,14 @@ import '../rules/waivers.js';
|
|
|
24
26
|
import './knowledge-version.js';
|
|
25
27
|
import './lesson-derivation.js';
|
|
26
28
|
|
|
27
|
-
/** Match only a configured
|
|
28
|
-
declare function matchStandaloneDownload(pathname: string, base: string,
|
|
29
|
-
/**
|
|
29
|
+
/** Match only a configured page artifact below Astro's deployment base. */
|
|
30
|
+
declare function matchStandaloneDownload(pathname: string, base: string, pageSlugs: readonly string[]): string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Fail loudly instead of rendering math triggers whose local cards are
|
|
33
|
+
* missing. The manifest bundles every `notation.local` entry with its page,
|
|
34
|
+
* so the two lists differ only when the manifest is older than the page, or
|
|
35
|
+
* when `validate:content` rejected an entry.
|
|
36
|
+
*/
|
|
30
37
|
declare function assertLocalNotationParity(lessonId: string, authoredKeys: readonly string[], renderedKeys: readonly string[]): void;
|
|
31
38
|
/** Fail an Astro build if final rendered HTML contains an unusable trigger. */
|
|
32
39
|
declare function assertNotationPayloadHtml(page: string, html: string): void;
|
package/dist/compiler/astro.js
CHANGED
|
@@ -8,7 +8,19 @@ import {
|
|
|
8
8
|
writeManifest
|
|
9
9
|
} from "./manifest.js";
|
|
10
10
|
import { missingNotationPayloadKeys } from "../reference/page-notation.js";
|
|
11
|
+
import { assertFigureSymbolsBound } from "../reference/figure-symbols.js";
|
|
12
|
+
import { undrawnFigurePictures, undrawnFigureWarning } from "../reference/figure-pictures.js";
|
|
13
|
+
import {
|
|
14
|
+
pageRenderDiagnostics,
|
|
15
|
+
writeRenderDiagnostics
|
|
16
|
+
} from "./render-diagnostics.js";
|
|
11
17
|
import { writeStandaloneLessonExports } from "./exports/standalone-html.js";
|
|
18
|
+
import { writeCombinedExports } from "./exports/combined-html.js";
|
|
19
|
+
import { writeLatexExports } from "./exports/latex-export.js";
|
|
20
|
+
import { writeMarkdownExports } from "./exports/markdown-export.js";
|
|
21
|
+
import { prepareChapters } from "./exports/export-chapters.js";
|
|
22
|
+
import { writeDownloadIndex } from "./exports/download-index.js";
|
|
23
|
+
import { standaloneFilename, standalonePageSlugs } from "./exports/export-pages.js";
|
|
12
24
|
import remarkAbbreviations from "../reference/remark-abbreviations.mjs";
|
|
13
25
|
import remarkCitation from "../reference/remark-citation.mjs";
|
|
14
26
|
import remarkNotation from "../reference/remark-notation.mjs";
|
|
@@ -17,13 +29,13 @@ function normalizedBasePath(base) {
|
|
|
17
29
|
const segment = base.replace(/^\/+|\/+$/gu, "");
|
|
18
30
|
return segment ? `/${segment}/` : "/";
|
|
19
31
|
}
|
|
20
|
-
function matchStandaloneDownload(pathname, base,
|
|
32
|
+
function matchStandaloneDownload(pathname, base, pageSlugs) {
|
|
21
33
|
const prefix = `${normalizedBasePath(base)}downloads/`;
|
|
22
34
|
if (!pathname.startsWith(prefix) || !pathname.endsWith(".html")) return void 0;
|
|
23
35
|
const slug = pathname.slice(prefix.length, -".html".length);
|
|
24
|
-
return
|
|
36
|
+
return pageSlugs.includes(slug) ? slug : void 0;
|
|
25
37
|
}
|
|
26
|
-
async function buildDevelopmentDownloads(config,
|
|
38
|
+
async function buildDevelopmentDownloads(config, pageSlugs) {
|
|
27
39
|
const temporaryRoot = await mkdtemp(join(tmpdir(), "explico-standalone-"));
|
|
28
40
|
const outputRoot = join(temporaryRoot, "dist");
|
|
29
41
|
try {
|
|
@@ -70,7 +82,7 @@ ${diagnostic.trim()}` : "")
|
|
|
70
82
|
});
|
|
71
83
|
return new Map(
|
|
72
84
|
await Promise.all(
|
|
73
|
-
|
|
85
|
+
pageSlugs.map(async (slug) => [
|
|
74
86
|
slug,
|
|
75
87
|
await readFile(join(outputRoot, "downloads", `${slug}.html`))
|
|
76
88
|
])
|
|
@@ -87,7 +99,7 @@ function assertLocalNotationParity(lessonId, authoredKeys, renderedKeys) {
|
|
|
87
99
|
return;
|
|
88
100
|
}
|
|
89
101
|
throw new Error(
|
|
90
|
-
`
|
|
102
|
+
`Explico notation mismatch for ${lessonId}: the page's frontmatter notation.local declares [${authored.join(", ")}], but the manifest's notation bundle for the page holds [${rendered.join(", ")}]. The manifest bundles every notation.local entry with its page, so either it is stale \u2014 pass courseConfig to loadManifest() and add explicoContentRefresh() to the Astro integrations \u2014 or \`pnpm validate:content\` rejected an entry: fix the errors it reports.`
|
|
91
103
|
);
|
|
92
104
|
}
|
|
93
105
|
function assertNotationPayloadHtml(page, html) {
|
|
@@ -131,19 +143,27 @@ function assertRemarkPluginsWired(manifest, markdown) {
|
|
|
131
143
|
${missing.map((line) => ` - ${line}`).join("\n")}`
|
|
132
144
|
);
|
|
133
145
|
}
|
|
134
|
-
async function
|
|
146
|
+
async function validateGeneratedPages(directory, manifest, warn) {
|
|
135
147
|
const root = fileURLToPath(directory);
|
|
148
|
+
const rendered = [];
|
|
136
149
|
const walk = async (path) => {
|
|
137
150
|
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
138
151
|
const child = join(path, entry.name);
|
|
139
152
|
if (entry.isDirectory()) {
|
|
140
153
|
await walk(child);
|
|
141
154
|
} else if (entry.isFile() && entry.name.endsWith(".html")) {
|
|
142
|
-
|
|
155
|
+
const html = await readFile(child, "utf8");
|
|
156
|
+
const page = relative(root, child);
|
|
157
|
+
assertNotationPayloadHtml(page, html);
|
|
158
|
+
assertFigureSymbolsBound(page, html);
|
|
159
|
+
const undrawn = undrawnFigurePictures(html);
|
|
160
|
+
if (undrawn.length > 0) warn(undrawnFigureWarning(page, undrawn));
|
|
161
|
+
rendered.push(...pageRenderDiagnostics(manifest, page, html));
|
|
143
162
|
}
|
|
144
163
|
}
|
|
145
164
|
};
|
|
146
165
|
await walk(root);
|
|
166
|
+
return rendered;
|
|
147
167
|
}
|
|
148
168
|
function replaceInPlace(target, source) {
|
|
149
169
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
@@ -240,16 +260,16 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
240
260
|
const slug = matchStandaloneDownload(
|
|
241
261
|
pathname,
|
|
242
262
|
configuredDevelopment.base,
|
|
243
|
-
manifest
|
|
263
|
+
standalonePageSlugs(manifest)
|
|
244
264
|
);
|
|
245
265
|
if (!slug) return next();
|
|
246
266
|
try {
|
|
247
267
|
logger.info(
|
|
248
|
-
developmentDownloads ? `Serving cached standalone
|
|
268
|
+
developmentDownloads ? `Serving cached standalone page ${slug}.html` : "Building standalone page downloads for local development\u2026"
|
|
249
269
|
);
|
|
250
270
|
developmentDownloads ??= buildDevelopmentDownloads(
|
|
251
271
|
configuredDevelopment,
|
|
252
|
-
manifest
|
|
272
|
+
standalonePageSlugs(manifest)
|
|
253
273
|
);
|
|
254
274
|
const currentDownloads = developmentDownloads;
|
|
255
275
|
currentDownloads.catch(() => {
|
|
@@ -259,7 +279,7 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
259
279
|
});
|
|
260
280
|
const artifact = (await currentDownloads).get(slug);
|
|
261
281
|
if (!artifact) return next();
|
|
262
|
-
const filename =
|
|
282
|
+
const filename = standaloneFilename(slug);
|
|
263
283
|
response.statusCode = 200;
|
|
264
284
|
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
265
285
|
response.setHeader("Content-Length", artifact.byteLength);
|
|
@@ -271,19 +291,32 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
271
291
|
response.end(request.method === "HEAD" ? void 0 : artifact);
|
|
272
292
|
} catch (error) {
|
|
273
293
|
const message = error instanceof Error ? error.message : String(error);
|
|
274
|
-
logger.error(`Could not build standalone
|
|
294
|
+
logger.error(`Could not build standalone page downloads: ${message}`);
|
|
275
295
|
response.statusCode = 500;
|
|
276
296
|
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
277
|
-
response.end(`Could not build standalone
|
|
297
|
+
response.end(`Could not build standalone page download.
|
|
278
298
|
${message}
|
|
279
299
|
`);
|
|
280
300
|
}
|
|
281
301
|
});
|
|
282
302
|
}
|
|
283
303
|
},
|
|
284
|
-
"astro:build:done": async ({ dir }) => {
|
|
285
|
-
await
|
|
304
|
+
"astro:build:done": async ({ dir, logger }) => {
|
|
305
|
+
const rendered = await validateGeneratedPages(
|
|
306
|
+
dir,
|
|
307
|
+
manifest,
|
|
308
|
+
(message) => logger.warn(message)
|
|
309
|
+
);
|
|
310
|
+
for (const diagnostic of writeRenderDiagnostics(rendered)) {
|
|
311
|
+
logger.warn(`[${diagnostic.code}] ${diagnostic.file}: ${diagnostic.message}`);
|
|
312
|
+
}
|
|
286
313
|
await writeStandaloneLessonExports(dir, manifest);
|
|
314
|
+
await writeCombinedExports(dir, manifest);
|
|
315
|
+
const { latex, markdown } = manifest.lessonExports;
|
|
316
|
+
const prepared = latex || markdown ? await prepareChapters(fileURLToPath(dir), manifest, { logger }) : void 0;
|
|
317
|
+
await writeLatexExports(dir, manifest, { logger, ...prepared ? { prepared } : {} });
|
|
318
|
+
await writeMarkdownExports(dir, manifest, { logger, ...prepared ? { prepared } : {} });
|
|
319
|
+
await writeDownloadIndex(dir);
|
|
287
320
|
}
|
|
288
321
|
}
|
|
289
322
|
};
|
package/dist/compiler/cli.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { DiagnosticSeverity } from '../reference/types.js';
|
|
2
2
|
import { EquationLink } from '../reference/gate-math.js';
|
|
3
3
|
import { Manifest, ManifestLesson } from './manifest.js';
|
|
4
|
+
import { RenderDiagnostic } from './render-diagnostics.js';
|
|
4
5
|
import { RulesFilter, RuleInEffect } from '../rules/in-effect.js';
|
|
5
6
|
import '../curriculum/validation.js';
|
|
6
7
|
import '../reference/consistency.js';
|
|
7
|
-
import '../course-config-
|
|
8
|
+
import '../course-config-rRtME5UV.js';
|
|
8
9
|
import '../rules/catalog.js';
|
|
9
10
|
import '../rules/course-rules.js';
|
|
10
11
|
import './collections.js';
|
|
12
|
+
import '../reference/gate-retired-keys.js';
|
|
11
13
|
import '../reference/lint-ignore.js';
|
|
12
14
|
import '../reference/equations-validate.js';
|
|
13
15
|
import '../reference/tables-validate.js';
|
|
@@ -18,6 +20,7 @@ import '../reference/examples-validate.js';
|
|
|
18
20
|
import '../reference/folds-validate.js';
|
|
19
21
|
import '../reference/knowledge-checks-validate.js';
|
|
20
22
|
import '../reference/raw-floats-validate.js';
|
|
23
|
+
import '../reference/lab-katex-validate.js';
|
|
21
24
|
import '../reference/mixed-content.js';
|
|
22
25
|
import '../reference/gloss.js';
|
|
23
26
|
import '../rules/waivers.js';
|
|
@@ -51,6 +54,9 @@ import './lesson-derivation.js';
|
|
|
51
54
|
* on any renderability error (unparseable MDX, KaTeX error, unresolved
|
|
52
55
|
* notation, unknown `[[key]]`, unknown citation), on top of the manifest's
|
|
53
56
|
* schema / ref / math / equation diagnostics for that lesson.
|
|
57
|
+
* - Beside the manifest's diagnostics, every command lists what the last
|
|
58
|
+
* `astro build` found on the rendered pages (`render-diagnostics.ts`),
|
|
59
|
+
* under the `render:` source.
|
|
54
60
|
*/
|
|
55
61
|
|
|
56
62
|
type ContentCliCode = 'unknown-command' | 'usage' | 'unknown-lesson' | 'unknown-kind' | 'invalid-id' | 'exists' | 'not-a-lesson' | 'no-git';
|
|
@@ -87,7 +93,7 @@ interface CliDiagnostic {
|
|
|
87
93
|
* when their message mentions the lesson; per-file checks (notation, math,
|
|
88
94
|
* equations, consistency) are filtered by `file`.
|
|
89
95
|
*/
|
|
90
|
-
declare function lessonDiagnostics(manifest: Manifest, lesson: ManifestLesson): CliDiagnostic[];
|
|
96
|
+
declare function lessonDiagnostics(manifest: Manifest, lesson: ManifestLesson, rendered?: readonly RenderDiagnostic[]): CliDiagnostic[];
|
|
91
97
|
interface RenderResult {
|
|
92
98
|
readonly rendered: boolean;
|
|
93
99
|
readonly diagnostics: readonly CliDiagnostic[];
|
|
@@ -117,6 +123,15 @@ interface TokenCounts {
|
|
|
117
123
|
/** Normalize `foundations/discount-factors` or the dotted id to the dotted id. */
|
|
118
124
|
declare function normalizeLessonId(raw: string): string;
|
|
119
125
|
declare function findLesson(manifest: Manifest, rawId: string): ManifestLesson;
|
|
126
|
+
/**
|
|
127
|
+
* A lesson file's frontmatter and its body for rendering: the frontmatter is
|
|
128
|
+
* blanked with spaces, as Astro's MDX plugin does, so line N of the body is
|
|
129
|
+
* line N of the file and a render error points where the build's would.
|
|
130
|
+
*/
|
|
131
|
+
declare function lessonSource(text: string): {
|
|
132
|
+
frontmatter: Record<string, unknown>;
|
|
133
|
+
body: string;
|
|
134
|
+
};
|
|
120
135
|
interface DomainFileSignatures {
|
|
121
136
|
readonly file: string;
|
|
122
137
|
readonly signatures: readonly string[];
|
|
@@ -137,10 +152,6 @@ interface StatusReport {
|
|
|
137
152
|
readonly keyedDiagrams: number;
|
|
138
153
|
readonly keyedExamples: number;
|
|
139
154
|
};
|
|
140
|
-
readonly draftDebt: {
|
|
141
|
-
readonly lessons: readonly string[];
|
|
142
|
-
readonly notation: readonly string[];
|
|
143
|
-
};
|
|
144
155
|
readonly orphans: readonly CliDiagnostic[];
|
|
145
156
|
readonly diagnostics: {
|
|
146
157
|
readonly errors: number;
|
|
@@ -148,7 +159,7 @@ interface StatusReport {
|
|
|
148
159
|
readonly infos: number;
|
|
149
160
|
};
|
|
150
161
|
}
|
|
151
|
-
declare function contentStatus(manifest: Manifest): StatusReport;
|
|
162
|
+
declare function contentStatus(manifest: Manifest, rendered?: readonly RenderDiagnostic[]): StatusReport;
|
|
152
163
|
type DiagnosticThreshold = DiagnosticSeverity;
|
|
153
164
|
interface DiagnosticsReport {
|
|
154
165
|
readonly minimumSeverity: DiagnosticThreshold;
|
|
@@ -159,10 +170,13 @@ interface WarningsReport {
|
|
|
159
170
|
readonly count: number;
|
|
160
171
|
readonly warnings: readonly CliDiagnostic[];
|
|
161
172
|
}
|
|
162
|
-
/**
|
|
163
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Manifest diagnostics at or above a severity, and those the last
|
|
175
|
+
* `astro build` found on rendered pages, normalized for tooling.
|
|
176
|
+
*/
|
|
177
|
+
declare function contentDiagnostics(manifest: Manifest, minimumSeverity?: DiagnosticThreshold, rendered?: readonly RenderDiagnostic[]): DiagnosticsReport;
|
|
164
178
|
/** Every warning exactly; errors and informational advice are excluded. */
|
|
165
|
-
declare function contentWarnings(manifest: Manifest): WarningsReport;
|
|
179
|
+
declare function contentWarnings(manifest: Manifest, rendered?: readonly RenderDiagnostic[]): WarningsReport;
|
|
166
180
|
interface RulesReport {
|
|
167
181
|
readonly filter: RulesFilter;
|
|
168
182
|
readonly count: number;
|
|
@@ -187,7 +201,6 @@ interface ContextReport {
|
|
|
187
201
|
readonly file: string;
|
|
188
202
|
readonly title: string;
|
|
189
203
|
readonly description: string;
|
|
190
|
-
readonly status: string;
|
|
191
204
|
readonly teaches: readonly string[];
|
|
192
205
|
readonly requires: readonly string[];
|
|
193
206
|
readonly assumptions: readonly string[];
|
|
@@ -271,6 +284,8 @@ interface CheckReport {
|
|
|
271
284
|
declare function changedLessonIds(): string[];
|
|
272
285
|
declare function contentCheck(manifest: Manifest, options: {
|
|
273
286
|
lesson?: string;
|
|
287
|
+
/** Several lessons, each checked; `lesson` is the one-lesson form. */
|
|
288
|
+
lessons?: readonly string[];
|
|
274
289
|
changed?: boolean;
|
|
275
290
|
}): Promise<CheckReport>;
|
|
276
291
|
interface Scaffold {
|
|
@@ -286,4 +301,4 @@ interface Scaffold {
|
|
|
286
301
|
declare function scaffoldLesson(rawId: string): Scaffold;
|
|
287
302
|
declare function scaffoldTerm(rawKey: string): Scaffold;
|
|
288
303
|
|
|
289
|
-
export { type CheckLessonResult, type CheckReport, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DomainFileSignatures, type RenderResult, type RulesReport, type Scaffold, type StatusReport, type TokenCounts, type WarningsReport, changedLessonIds, contentCheck, contentContext, contentDiagnostics, contentRules, contentStatus, contentWarnings, estimateTokens, findLesson, lessonDiagnostics, normalizeLessonId, parseRulesFilter, renderLesson, scaffoldLesson, scaffoldTerm };
|
|
304
|
+
export { type CheckLessonResult, type CheckReport, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DomainFileSignatures, type RenderResult, type RulesReport, type Scaffold, type StatusReport, type TokenCounts, type WarningsReport, changedLessonIds, contentCheck, contentContext, contentDiagnostics, contentRules, contentStatus, contentWarnings, estimateTokens, findLesson, lessonDiagnostics, lessonSource, normalizeLessonId, parseRulesFilter, renderLesson, scaffoldLesson, scaffoldTerm };
|