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
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';
|
|
@@ -25,8 +26,8 @@ import '../rules/waivers.js';
|
|
|
25
26
|
import './knowledge-version.js';
|
|
26
27
|
import './lesson-derivation.js';
|
|
27
28
|
|
|
28
|
-
/** Match only a configured
|
|
29
|
-
declare function matchStandaloneDownload(pathname: string, base: string,
|
|
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;
|
|
30
31
|
/**
|
|
31
32
|
* Fail loudly instead of rendering math triggers whose local cards are
|
|
32
33
|
* missing. The manifest bundles every `notation.local` entry with its page,
|
package/dist/compiler/astro.js
CHANGED
|
@@ -9,7 +9,18 @@ import {
|
|
|
9
9
|
} from "./manifest.js";
|
|
10
10
|
import { missingNotationPayloadKeys } from "../reference/page-notation.js";
|
|
11
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";
|
|
12
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";
|
|
13
24
|
import remarkAbbreviations from "../reference/remark-abbreviations.mjs";
|
|
14
25
|
import remarkCitation from "../reference/remark-citation.mjs";
|
|
15
26
|
import remarkNotation from "../reference/remark-notation.mjs";
|
|
@@ -18,13 +29,13 @@ function normalizedBasePath(base) {
|
|
|
18
29
|
const segment = base.replace(/^\/+|\/+$/gu, "");
|
|
19
30
|
return segment ? `/${segment}/` : "/";
|
|
20
31
|
}
|
|
21
|
-
function matchStandaloneDownload(pathname, base,
|
|
32
|
+
function matchStandaloneDownload(pathname, base, pageSlugs) {
|
|
22
33
|
const prefix = `${normalizedBasePath(base)}downloads/`;
|
|
23
34
|
if (!pathname.startsWith(prefix) || !pathname.endsWith(".html")) return void 0;
|
|
24
35
|
const slug = pathname.slice(prefix.length, -".html".length);
|
|
25
|
-
return
|
|
36
|
+
return pageSlugs.includes(slug) ? slug : void 0;
|
|
26
37
|
}
|
|
27
|
-
async function buildDevelopmentDownloads(config,
|
|
38
|
+
async function buildDevelopmentDownloads(config, pageSlugs) {
|
|
28
39
|
const temporaryRoot = await mkdtemp(join(tmpdir(), "explico-standalone-"));
|
|
29
40
|
const outputRoot = join(temporaryRoot, "dist");
|
|
30
41
|
try {
|
|
@@ -71,7 +82,7 @@ ${diagnostic.trim()}` : "")
|
|
|
71
82
|
});
|
|
72
83
|
return new Map(
|
|
73
84
|
await Promise.all(
|
|
74
|
-
|
|
85
|
+
pageSlugs.map(async (slug) => [
|
|
75
86
|
slug,
|
|
76
87
|
await readFile(join(outputRoot, "downloads", `${slug}.html`))
|
|
77
88
|
])
|
|
@@ -132,8 +143,9 @@ function assertRemarkPluginsWired(manifest, markdown) {
|
|
|
132
143
|
${missing.map((line) => ` - ${line}`).join("\n")}`
|
|
133
144
|
);
|
|
134
145
|
}
|
|
135
|
-
async function
|
|
146
|
+
async function validateGeneratedPages(directory, manifest, warn) {
|
|
136
147
|
const root = fileURLToPath(directory);
|
|
148
|
+
const rendered = [];
|
|
137
149
|
const walk = async (path) => {
|
|
138
150
|
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
139
151
|
const child = join(path, entry.name);
|
|
@@ -141,12 +153,17 @@ async function validateGeneratedNotationPayloads(directory) {
|
|
|
141
153
|
await walk(child);
|
|
142
154
|
} else if (entry.isFile() && entry.name.endsWith(".html")) {
|
|
143
155
|
const html = await readFile(child, "utf8");
|
|
144
|
-
|
|
145
|
-
|
|
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));
|
|
146
162
|
}
|
|
147
163
|
}
|
|
148
164
|
};
|
|
149
165
|
await walk(root);
|
|
166
|
+
return rendered;
|
|
150
167
|
}
|
|
151
168
|
function replaceInPlace(target, source) {
|
|
152
169
|
if (Array.isArray(target) && Array.isArray(source)) {
|
|
@@ -243,16 +260,16 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
243
260
|
const slug = matchStandaloneDownload(
|
|
244
261
|
pathname,
|
|
245
262
|
configuredDevelopment.base,
|
|
246
|
-
manifest
|
|
263
|
+
standalonePageSlugs(manifest)
|
|
247
264
|
);
|
|
248
265
|
if (!slug) return next();
|
|
249
266
|
try {
|
|
250
267
|
logger.info(
|
|
251
|
-
developmentDownloads ? `Serving cached standalone
|
|
268
|
+
developmentDownloads ? `Serving cached standalone page ${slug}.html` : "Building standalone page downloads for local development\u2026"
|
|
252
269
|
);
|
|
253
270
|
developmentDownloads ??= buildDevelopmentDownloads(
|
|
254
271
|
configuredDevelopment,
|
|
255
|
-
manifest
|
|
272
|
+
standalonePageSlugs(manifest)
|
|
256
273
|
);
|
|
257
274
|
const currentDownloads = developmentDownloads;
|
|
258
275
|
currentDownloads.catch(() => {
|
|
@@ -262,7 +279,7 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
262
279
|
});
|
|
263
280
|
const artifact = (await currentDownloads).get(slug);
|
|
264
281
|
if (!artifact) return next();
|
|
265
|
-
const filename =
|
|
282
|
+
const filename = standaloneFilename(slug);
|
|
266
283
|
response.statusCode = 200;
|
|
267
284
|
response.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
268
285
|
response.setHeader("Content-Length", artifact.byteLength);
|
|
@@ -274,19 +291,32 @@ function explicoContentRefresh(courseConfig, manifest) {
|
|
|
274
291
|
response.end(request.method === "HEAD" ? void 0 : artifact);
|
|
275
292
|
} catch (error) {
|
|
276
293
|
const message = error instanceof Error ? error.message : String(error);
|
|
277
|
-
logger.error(`Could not build standalone
|
|
294
|
+
logger.error(`Could not build standalone page downloads: ${message}`);
|
|
278
295
|
response.statusCode = 500;
|
|
279
296
|
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
280
|
-
response.end(`Could not build standalone
|
|
297
|
+
response.end(`Could not build standalone page download.
|
|
281
298
|
${message}
|
|
282
299
|
`);
|
|
283
300
|
}
|
|
284
301
|
});
|
|
285
302
|
}
|
|
286
303
|
},
|
|
287
|
-
"astro:build:done": async ({ dir }) => {
|
|
288
|
-
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
|
+
}
|
|
289
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);
|
|
290
320
|
}
|
|
291
321
|
}
|
|
292
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';
|
|
@@ -52,6 +54,9 @@ import './lesson-derivation.js';
|
|
|
52
54
|
* on any renderability error (unparseable MDX, KaTeX error, unresolved
|
|
53
55
|
* notation, unknown `[[key]]`, unknown citation), on top of the manifest's
|
|
54
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.
|
|
55
60
|
*/
|
|
56
61
|
|
|
57
62
|
type ContentCliCode = 'unknown-command' | 'usage' | 'unknown-lesson' | 'unknown-kind' | 'invalid-id' | 'exists' | 'not-a-lesson' | 'no-git';
|
|
@@ -88,7 +93,7 @@ interface CliDiagnostic {
|
|
|
88
93
|
* when their message mentions the lesson; per-file checks (notation, math,
|
|
89
94
|
* equations, consistency) are filtered by `file`.
|
|
90
95
|
*/
|
|
91
|
-
declare function lessonDiagnostics(manifest: Manifest, lesson: ManifestLesson): CliDiagnostic[];
|
|
96
|
+
declare function lessonDiagnostics(manifest: Manifest, lesson: ManifestLesson, rendered?: readonly RenderDiagnostic[]): CliDiagnostic[];
|
|
92
97
|
interface RenderResult {
|
|
93
98
|
readonly rendered: boolean;
|
|
94
99
|
readonly diagnostics: readonly CliDiagnostic[];
|
|
@@ -118,6 +123,15 @@ interface TokenCounts {
|
|
|
118
123
|
/** Normalize `foundations/discount-factors` or the dotted id to the dotted id. */
|
|
119
124
|
declare function normalizeLessonId(raw: string): string;
|
|
120
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
|
+
};
|
|
121
135
|
interface DomainFileSignatures {
|
|
122
136
|
readonly file: string;
|
|
123
137
|
readonly signatures: readonly string[];
|
|
@@ -138,10 +152,6 @@ interface StatusReport {
|
|
|
138
152
|
readonly keyedDiagrams: number;
|
|
139
153
|
readonly keyedExamples: number;
|
|
140
154
|
};
|
|
141
|
-
readonly draftDebt: {
|
|
142
|
-
readonly lessons: readonly string[];
|
|
143
|
-
readonly notation: readonly string[];
|
|
144
|
-
};
|
|
145
155
|
readonly orphans: readonly CliDiagnostic[];
|
|
146
156
|
readonly diagnostics: {
|
|
147
157
|
readonly errors: number;
|
|
@@ -149,7 +159,7 @@ interface StatusReport {
|
|
|
149
159
|
readonly infos: number;
|
|
150
160
|
};
|
|
151
161
|
}
|
|
152
|
-
declare function contentStatus(manifest: Manifest): StatusReport;
|
|
162
|
+
declare function contentStatus(manifest: Manifest, rendered?: readonly RenderDiagnostic[]): StatusReport;
|
|
153
163
|
type DiagnosticThreshold = DiagnosticSeverity;
|
|
154
164
|
interface DiagnosticsReport {
|
|
155
165
|
readonly minimumSeverity: DiagnosticThreshold;
|
|
@@ -160,10 +170,13 @@ interface WarningsReport {
|
|
|
160
170
|
readonly count: number;
|
|
161
171
|
readonly warnings: readonly CliDiagnostic[];
|
|
162
172
|
}
|
|
163
|
-
/**
|
|
164
|
-
|
|
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;
|
|
165
178
|
/** Every warning exactly; errors and informational advice are excluded. */
|
|
166
|
-
declare function contentWarnings(manifest: Manifest): WarningsReport;
|
|
179
|
+
declare function contentWarnings(manifest: Manifest, rendered?: readonly RenderDiagnostic[]): WarningsReport;
|
|
167
180
|
interface RulesReport {
|
|
168
181
|
readonly filter: RulesFilter;
|
|
169
182
|
readonly count: number;
|
|
@@ -188,7 +201,6 @@ interface ContextReport {
|
|
|
188
201
|
readonly file: string;
|
|
189
202
|
readonly title: string;
|
|
190
203
|
readonly description: string;
|
|
191
|
-
readonly status: string;
|
|
192
204
|
readonly teaches: readonly string[];
|
|
193
205
|
readonly requires: readonly string[];
|
|
194
206
|
readonly assumptions: readonly string[];
|
|
@@ -272,6 +284,8 @@ interface CheckReport {
|
|
|
272
284
|
declare function changedLessonIds(): string[];
|
|
273
285
|
declare function contentCheck(manifest: Manifest, options: {
|
|
274
286
|
lesson?: string;
|
|
287
|
+
/** Several lessons, each checked; `lesson` is the one-lesson form. */
|
|
288
|
+
lessons?: readonly string[];
|
|
275
289
|
changed?: boolean;
|
|
276
290
|
}): Promise<CheckReport>;
|
|
277
291
|
interface Scaffold {
|
|
@@ -287,4 +301,4 @@ interface Scaffold {
|
|
|
287
301
|
declare function scaffoldLesson(rawId: string): Scaffold;
|
|
288
302
|
declare function scaffoldTerm(rawKey: string): Scaffold;
|
|
289
303
|
|
|
290
|
-
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 };
|