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
|
@@ -33,6 +33,713 @@ required config block throws with the section of this file to read.
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
+
## 0.13.0 → 0.13.1
|
|
37
|
+
|
|
38
|
+
**No course changes required.** This release has one fix, in the engine's
|
|
39
|
+
stylesheet: hovering a symbol in an equation, or in a card's formula, no longer
|
|
40
|
+
paints its highlight over the glyph to its left. No authoring rule,
|
|
41
|
+
`CourseConfig` field, Astro wiring, course script or CLI command changes. The
|
|
42
|
+
manifest schema stays v29.
|
|
43
|
+
|
|
44
|
+
### 1. Update the dependency
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm add -D explico@0.13.1
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Coming from 0.12.0 or earlier:** apply "0.12.0 → 0.13.0" below first, and
|
|
51
|
+
install 0.13.1 wherever it says to install 0.13.0.
|
|
52
|
+
|
|
53
|
+
### 2. Only if your course CSS or browser tests reach into the symbol highlight
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rg -n 'data-notation-key|is-notation-active|mix-blend-mode' src content tests
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
No hit means nothing to do. Otherwise:
|
|
60
|
+
|
|
61
|
+
- **The highlight** of a hovered or active `[data-notation-key]` inside
|
|
62
|
+
`.katex-html`, and of one inside `.notation-panel-body [data-slot-formula]`,
|
|
63
|
+
has `mix-blend-mode: screen` (`multiply` under `:root[data-theme='light']`).
|
|
64
|
+
The background colour is still `--sl-color-accent-low`. A course rule that
|
|
65
|
+
overrides that background keeps working; one that also relies on the
|
|
66
|
+
highlight covering the glyph beside it no longer does.
|
|
67
|
+
- **Screenshots** of a hovered symbol need re-recording.
|
|
68
|
+
|
|
69
|
+
### 3. Verify
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pnpm validate:content # run twice: the first run regenerates build/resolution/*
|
|
73
|
+
pnpm content check --changed
|
|
74
|
+
astro check
|
|
75
|
+
astro build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Then run the course's browser tests, if it has any.
|
|
79
|
+
|
|
80
|
+
## 0.12.0 → 0.13.0
|
|
81
|
+
|
|
82
|
+
**Course changes are required.** A course still on 0.11.1 applies
|
|
83
|
+
"0.11.1 → 0.12.0" below first. Each of these can fail a build that passed
|
|
84
|
+
on 0.12.0:
|
|
85
|
+
|
|
86
|
+
- the Astro, Starlight and `@astrojs/react` versions, which move with
|
|
87
|
+
explico (step 1);
|
|
88
|
+
- `editorialStatus` in any content file, now `retired-key` (step 2), and a
|
|
89
|
+
course's `scripts/content.ts` that prints the draft counts it fed (step 3);
|
|
90
|
+
- a course test that still passes rule S5's `conventions` (step 4);
|
|
91
|
+
- `lessonExports.standaloneHtml` without `canonicalBaseUrl` (step 5);
|
|
92
|
+
- faults that used to pass in silence and are now `validate:content`
|
|
93
|
+
errors, rule S6 among them (step 7);
|
|
94
|
+
- rule N23, an index is part of the symbol, and rule N4, an indexed entry
|
|
95
|
+
lends its card to nothing (steps 8–14);
|
|
96
|
+
- code a course owns that reads what was removed (step 15).
|
|
97
|
+
|
|
98
|
+
The manifest schema is now v31, by way of v26, v27, v28, v29 and v30 (step
|
|
99
|
+
15). Fix every finding in the same change as the upgrade. The steps are one
|
|
100
|
+
pass, ordered so that no fix has to be redone. `rules.N23.enabled: false`
|
|
101
|
+
exists, but a course that ships with it off shows its readers the cards this
|
|
102
|
+
rule exists to fix, and the N4 failures of step 8 cannot be switched off.
|
|
103
|
+
|
|
104
|
+
### 1. Update the dependencies together
|
|
105
|
+
|
|
106
|
+
explico 0.13.0 pins a newer Astro stack in its `peerDependencies`. Set these
|
|
107
|
+
five in the course's `package.json`, each in the block that declares it now,
|
|
108
|
+
then run `pnpm install`:
|
|
109
|
+
|
|
110
|
+
| Package | from | to |
|
|
111
|
+
| --- | --- | --- |
|
|
112
|
+
| `explico` | 0.12.0 | 0.13.0 |
|
|
113
|
+
| `astro` | 7.2.7 | 7.3.5 |
|
|
114
|
+
| `@astrojs/starlight` | 0.41.9 | 0.42.4 |
|
|
115
|
+
| `@astrojs/react` | 6.0.4 | 7.0.0 |
|
|
116
|
+
| `@astrojs/markdown-remark` | 7.2.4 | 7.3.1 |
|
|
117
|
+
|
|
118
|
+
Move the four Astro packages together: Starlight 0.42 requires `astro`
|
|
119
|
+
7.2.10 and `@astrojs/markdown-remark` 7.3.0 or later. `astro.config.mjs`
|
|
120
|
+
needs no change unless it uses one of these:
|
|
121
|
+
|
|
122
|
+
- `react({ babel: … })`. `@astrojs/react` 7 removes the option: move those
|
|
123
|
+
plugins to `@rolldown/plugin-babel` in `vite.plugins`.
|
|
124
|
+
- Starlight's top-level `tagline`. It is removed, so delete it. A splash
|
|
125
|
+
page's `hero.tagline` is unaffected.
|
|
126
|
+
|
|
127
|
+
Starlight's mobile menu is now a `#starlight__sidebar` popover, opened by a
|
|
128
|
+
plain `button.sl-menu-button`. The `<starlight-menu-button>` element, its
|
|
129
|
+
`aria-expanded` and `body[data-mobile-menu-expanded]` are gone. Course CSS,
|
|
130
|
+
scripts or browser tests that target them match nothing; use
|
|
131
|
+
`.sl-menu-button` and `body:has(#starlight__sidebar:popover-open)`:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
rg -n 'starlight-menu-button|data-mobile-menu-expanded' src content tests
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Starlight 0.42 supports Chrome 116, Safari 17 and Firefox 125 or later.
|
|
138
|
+
`astro build` now prints `[WARN] [content] The collection "i18n" does not
|
|
139
|
+
exist or is empty` twice. The warning is harmless.
|
|
140
|
+
|
|
141
|
+
### 2. Delete `editorialStatus` from every content file
|
|
142
|
+
|
|
143
|
+
The draft / in-review / reviewed flag is retired, and nothing reads or shows
|
|
144
|
+
it. A page, notation entry, abbreviation, competency, assessment, source or
|
|
145
|
+
track that still sets it fails `validate:content` with `retired-key`, once
|
|
146
|
+
per file. Run this from the course root. It deletes the key from Markdown
|
|
147
|
+
frontmatter and from JSON records, along with the comma left behind where
|
|
148
|
+
the key was a record's last:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
node --input-type=module <<'EOF'
|
|
152
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
153
|
+
import { execFileSync } from 'node:child_process';
|
|
154
|
+
const files = execFileSync('grep', ['-rl', 'editorialStatus', 'content'], { encoding: 'utf8' })
|
|
155
|
+
.split('\n').filter(Boolean);
|
|
156
|
+
for (const file of files) {
|
|
157
|
+
const out = [];
|
|
158
|
+
let fence = file.endsWith('.json') ? null : 0; // Markdown: only inside the frontmatter
|
|
159
|
+
for (const line of readFileSync(file, 'utf8').split('\n')) {
|
|
160
|
+
if (fence !== null && line.trim() === '---') fence += 1;
|
|
161
|
+
const json = fence === null && /^\s*"editorialStatus"\s*:\s*"[^"]*"\s*,?\s*$/.test(line);
|
|
162
|
+
const yaml = fence === 1 && /^\s*editorialStatus\s*:/.test(line);
|
|
163
|
+
if (!json && !yaml) { out.push(line); continue; }
|
|
164
|
+
if (json && !line.trimEnd().endsWith(',')) {
|
|
165
|
+
// The key was the record's last: drop the comma the key before it left.
|
|
166
|
+
const i = out.findLastIndex((l) => l.trim() !== '');
|
|
167
|
+
out[i] = out[i].replace(/,(\s*)$/, '$1');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
writeFileSync(file, out.join('\n'));
|
|
171
|
+
if (file.endsWith('.json')) JSON.parse(out.join('\n'));
|
|
172
|
+
}
|
|
173
|
+
console.log(`editorialStatus removed from ${files.length} files`);
|
|
174
|
+
EOF
|
|
175
|
+
grep -rn editorialStatus content
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The final `grep` must print nothing. In `git diff`, each file loses one line,
|
|
179
|
+
and a JSON record whose last key it was also loses one comma. A course test
|
|
180
|
+
that builds notation, lesson or source inputs drops their `status` /
|
|
181
|
+
`editorialStatus` too (step 15).
|
|
182
|
+
|
|
183
|
+
### 3. The course's `scripts/content.ts`
|
|
184
|
+
|
|
185
|
+
`tsx` does not type-check, so a field the engine no longer returns throws at
|
|
186
|
+
run time. In the course's own `content` wrapper:
|
|
187
|
+
|
|
188
|
+
- `content status`: drop the draft counts. `report.draftDebt` is gone, so
|
|
189
|
+
`report.draftDebt.lessons.length` and `report.draftDebt.notation.length`
|
|
190
|
+
throw.
|
|
191
|
+
- `content context`: drop `report.lesson.status`.
|
|
192
|
+
- `content check`: pass every id, `contentCheck(manifest, { lessons:
|
|
193
|
+
args.positionals, changed: args.changed })`. `lesson` still works, but it
|
|
194
|
+
checks only the first id: `content check a b` exits 0 having never
|
|
195
|
+
looked at `b`.
|
|
196
|
+
|
|
197
|
+
Optionally, as explico's playground now does, fail on an argument a command
|
|
198
|
+
does not take (`status`, `rules` and `warnings` take none; `context` and
|
|
199
|
+
`new` take one).
|
|
200
|
+
|
|
201
|
+
### 4. Rule S5 is retired: delete `conventions`
|
|
202
|
+
|
|
203
|
+
Rule S5 (`convention-single-definition`) is gone, and so is the
|
|
204
|
+
`conventions` setting it read (`signConventionKey`,
|
|
205
|
+
`cashFlowPerspectiveCompetency`). Its check knew one finance course's wording
|
|
206
|
+
and never fired in any course. A convention is a definition, so rule N4 now
|
|
207
|
+
covers it: the convention's notation entry names the other choice in its
|
|
208
|
+
`meaning` and says how to convert in its body (notation.md, rule N4, "A
|
|
209
|
+
definition that is a convention").
|
|
210
|
+
|
|
211
|
+
- Delete the `conventions` block from `content/course.config.ts`, or from
|
|
212
|
+
`course.settings.json` and its schema where the course keeps its settings
|
|
213
|
+
there. Until then it does nothing, and `validate:content` warns
|
|
214
|
+
`config-deprecated-key`. The type keeps it, as a deprecated `unknown`,
|
|
215
|
+
only until the next MINOR.
|
|
216
|
+
- Delete a `rules.S5` block (it warns `config-retired-rule`) and any
|
|
217
|
+
`lint-ignore.yml` line for `convention-single-definition`, which now
|
|
218
|
+
silences nothing.
|
|
219
|
+
- A course test that calls `runConsistencyChecks` drops `catalog` and
|
|
220
|
+
`conventions` from its input. The check that read them is gone, and an
|
|
221
|
+
object literal that still passes them is a type error.
|
|
222
|
+
- Optional: on the entry that was the course's `signConventionKey`, and on
|
|
223
|
+
any other entry that is a convention, add the other choice to `meaning`
|
|
224
|
+
and the conversion to the body. That is a notation edit, so it gets a
|
|
225
|
+
`content/CHANGELOG.md` bullet like any other (rule C1).
|
|
226
|
+
|
|
227
|
+
### 5. `lessonExports.canonicalBaseUrl` with standalone HTML
|
|
228
|
+
|
|
229
|
+
With `lessonExports.standaloneHtml` on, each part and the whole course now
|
|
230
|
+
also download as one offline HTML file: `downloads/part/<dir>.html` (the
|
|
231
|
+
part's page, then its chapters) and `downloads/course.html` (the landing
|
|
232
|
+
page, the curriculum map, the figures and tables, every part, the glossary).
|
|
233
|
+
An exported page that links elsewhere in the course fails the build without
|
|
234
|
+
a base URL, as a chapter always did, and a splash hero's actions always
|
|
235
|
+
link. Such a course sets its deployed root:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
"lessonExports": {
|
|
239
|
+
"standaloneHtml": true,
|
|
240
|
+
"print": true,
|
|
241
|
+
"canonicalBaseUrl": "https://example.org/my-course/"
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
A page that is not a chapter has no download of its own. Its content is in
|
|
246
|
+
its part's file and the course's. A course link into `downloads/` points at
|
|
247
|
+
`<slug>.html` for a chapter, `part/<dir>.html` or `course.html`.
|
|
248
|
+
|
|
249
|
+
### 6. List the work
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pnpm validate:content; pnpm validate:content
|
|
253
|
+
pnpm content diagnostics error
|
|
254
|
+
pnpm content warnings
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Read the second `validate:content`; the first regenerates
|
|
258
|
+
`build/resolution/`. Step 7 covers the new errors that are not about
|
|
259
|
+
indices. Every N23 finding names its rule, the form, and the fix:
|
|
260
|
+
`index-explained`, `index-swallowed`, `index-range`, `derived-key-taken`
|
|
261
|
+
(errors), `accent-swallowed` (a rule N22 warning), and `unresolved-glyph`
|
|
262
|
+
lines whose message names "an indexed entry". Lab and diagram math only
|
|
263
|
+
exists as the page renders, so `astro build` reports it (step 13). Run that
|
|
264
|
+
once the content checks pass. To see the list before upgrading, run the
|
|
265
|
+
engine repository's dry run from its `playground/` directory in a checkout:
|
|
266
|
+
`node_modules/.bin/tsx ../scripts/agent/index-dry-run.ts <course-dir>`. It
|
|
267
|
+
leaves the course untouched (its report goes under the engine's
|
|
268
|
+
`.agent/index-dry-run/`). It covers lesson bodies, notation formulas,
|
|
269
|
+
assessments and `unresolved-glyph`, but not `accent-swallowed`, labs or
|
|
270
|
+
diagrams.
|
|
271
|
+
|
|
272
|
+
### 7. Faults that now fail `validate:content`
|
|
273
|
+
|
|
274
|
+
Each of these used to pass and then show readers something wrong, or fail
|
|
275
|
+
`astro build` with no file or line. Each error names its file and line. Most
|
|
276
|
+
courses have few of them, or none:
|
|
277
|
+
|
|
278
|
+
| Code | What fails | Fix |
|
|
279
|
+
| --- | --- | --- |
|
|
280
|
+
| `markup-in-prop` | `$…$`, `[[…]]` or `[@…]` in a quoted prop (`short="Speed $v$"`) | write the symbol in Unicode or words; reference or cite from the prose beside the component |
|
|
281
|
+
| `mdx-expression` | `{a}` in prose, which MDX runs as JavaScript | `\{a\}`, or `$\{a\}$` for a set |
|
|
282
|
+
| `eq-label-repeated` | a second `\label{eq:…}` in one `$$…$$` block | give each equation you refer to its own block |
|
|
283
|
+
| `eq-latex-ref` | `\begin{align}`, `\begin{equation}`, `\tag`, an unprefixed `\label`, `\eqref` or `\ref` | `aligned` / `gathered` / `alignedat` inside the block, `\label{eq:key}`, `[[eq-key]]` |
|
|
284
|
+
| `invalid-key` | a notation key starting `eq-`, `tab-`, `fig-`, `dia-`, `ex-`, `check-`, `sec-` or `memo-` | rename it: a MAJOR bump under rule C2 |
|
|
285
|
+
| `heading-nested` | a worked-example set or a knowledge check inside a `<Memo>` or `<ShortNote>` (rule S6) | move it out, after the memo |
|
|
286
|
+
| `tab-several-tables` | one `<Table>` holding two tables | one `<Table>` each |
|
|
287
|
+
| `citation-in-link` | `[as measured in [@id]](https://…)` | cite after the link |
|
|
288
|
+
| `heading-anchor-collision` | a heading whose anchor something else holds: `## References` on a page that cites, `## Tab totals` beside `<Table id="totals">` | reword the heading |
|
|
289
|
+
| `currency-dollar` | `pay $5 ~ $6`, which remark-math reads as math | `\$5 to \$6` |
|
|
290
|
+
| `malformed-reference` | an unclosed `[[` | close it |
|
|
291
|
+
| `invalid-assessment` | a `[[…]]` or `[@…]` in a knowledge check's prompt, explanation or option, which reached students as typed | say it in words: a check renders text and math, not references or citations |
|
|
292
|
+
| `unsupported-key` | `draft: true` on a lesson | keep an unfinished lesson outside `content/docs/` |
|
|
293
|
+
|
|
294
|
+
Two more fail `astro build`: a `<Table>` or `<Figure>` inside a `:::`
|
|
295
|
+
aside (the message names the aside; move the float out), and a `<Diagram>`
|
|
296
|
+
edge from a node to itself (the message says how to draw the repetition).
|
|
297
|
+
|
|
298
|
+
A knowledge check's option label now renders its math, so rule N4 checks
|
|
299
|
+
it: a symbol in `"$30^{\circ}$"` needs a card, as in the prompt. Rule N9
|
|
300
|
+
still does not apply to a label ("30 degrees" stays valid). A declared
|
|
301
|
+
operator now binds only its own card (rule N8). A `\operatorname{Cov}` that
|
|
302
|
+
silently opened the page's `\operatorname{Var}` card has no card now: give
|
|
303
|
+
it one, or add it to `rules.N8.allow`. A name a course put on
|
|
304
|
+
`rules.N8.allow` only because its card was refused can come off the list,
|
|
305
|
+
with the card restored.
|
|
306
|
+
|
|
307
|
+
New warnings, worth clearing in the same pass:
|
|
308
|
+
|
|
309
|
+
- `local-shadows-shared`: a `notation.local` key equal to a shared one.
|
|
310
|
+
Rename the local key.
|
|
311
|
+
- `fig-unread-prop` (and the `tab-`, `dia-` and `ex-` variants): a caption
|
|
312
|
+
prop written as an expression, `short={"…"}`. Quote it, `short="…"`.
|
|
313
|
+
- `ignored-key`: a chapter's `sidebar.order`, which does nothing. Delete it.
|
|
314
|
+
- `part-empty`: a part listed in `parts` before its directory exists. Fine
|
|
315
|
+
while the part is planned.
|
|
316
|
+
- `lab-picture-undrawn` and `dia-too-wide` (step 13), and
|
|
317
|
+
`accent-swallowed` (step 14).
|
|
318
|
+
|
|
319
|
+
### 8. A bare symbol that borrowed an indexed entry's card (rule N4)
|
|
320
|
+
|
|
321
|
+
An entry with a subscript lends its card to no bare symbol now. A family
|
|
322
|
+
(`\alpha_i`, "ARCH coefficient") gives it to its own instances only
|
|
323
|
+
(`\alpha_1`, `\alpha_q`); a fixed label (`H_0`, `v_0`, `T_{\mathrm{opt}}`)
|
|
324
|
+
to nothing. The bare symbol fails `unresolved-glyph`, and the message names
|
|
325
|
+
the entry it shared its base with. For each (page, symbol):
|
|
326
|
+
|
|
327
|
+
- **A different object** — the usual case: a learning rate `\alpha` beside
|
|
328
|
+
ARCH coefficients `\alpha_i`, an AR(1) coefficient `\beta` beside `\beta_i`,
|
|
329
|
+
a response `Y` beside observations `Y_i`. Give it its own entry, page-local
|
|
330
|
+
when only that page uses it:
|
|
331
|
+
|
|
332
|
+
```yaml
|
|
333
|
+
notation:
|
|
334
|
+
local:
|
|
335
|
+
- key: learning-rate
|
|
336
|
+
latex: \alpha
|
|
337
|
+
label: Learning rate
|
|
338
|
+
meaning: The weight the newest observation gets in the exponentially weighted average.
|
|
339
|
+
dimensionless: true
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
- **Shorthand for the family**, the indexed symbol with the index left off:
|
|
343
|
+
wrap it, `\explain{arch-coefficient}{\alpha}`.
|
|
344
|
+
|
|
345
|
+
- **Another member of a fixed-label set**: `H_1` borrowed the `H_0` card
|
|
346
|
+
("Null hypothesis"). Give it its own entry, or introduce the one the course
|
|
347
|
+
has (`[[alternative-hypothesis]]`).
|
|
348
|
+
|
|
349
|
+
A function form still lends by its head: `D(0,t)` explains a bare `D`, and
|
|
350
|
+
`V_0(1_t)` explains `V_0(1_2)`, but no longer a bare `V`.
|
|
351
|
+
|
|
352
|
+
### 9. `index-swallowed`: an `\explain` around an indexed symbol
|
|
353
|
+
|
|
354
|
+
`\explain{motion.velocity}{v_x}` made the whole `v_x` one target with the
|
|
355
|
+
velocity's card, which says nothing about `x`. Find them all:
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
rg -n '\\explain\{[^}]+\}\{\\?[A-Za-z]+(\{[^}]*\})?_' content
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
For each reported wrap, either drop it and explain the subscript the way
|
|
362
|
+
step 10 does (an index entry `{}_x` turns `v_x` into one derived card,
|
|
363
|
+
"Horizontal component of velocity"), or point the wrap at an entry for the
|
|
364
|
+
indexed symbol itself. A wrap whose key's `latex` has an index
|
|
365
|
+
(`\explain{launch-speed}{v_0}`) is fine.
|
|
366
|
+
|
|
367
|
+
### 10. `index-explained`: whole form, family or index entry
|
|
368
|
+
|
|
369
|
+
A subscript only the base's card covered — a digit, a `\mathrm{}` label, a
|
|
370
|
+
base-library `i`, `e` or `d` used as an index — needs one of three, in this
|
|
371
|
+
order of precedence:
|
|
372
|
+
|
|
373
|
+
1. **Whole form**, for a named quantity: an entry with `latex:
|
|
374
|
+
\mathbf{v}_0`, "Initial velocity". It also wins under a power
|
|
375
|
+
(`\mathbf{v}_0^{2}`), so an `\explain{key}{v_0}^{2}` workaround can go.
|
|
376
|
+
2. **Family**, for an index that runs: `latex: x_k`, "k-th component". It
|
|
377
|
+
explains every instance with the same number of comma-separated slots
|
|
378
|
+
(`x_1`, `x_{k+1}`, `x_N`), ahead of a plain `x` entry, but not a fixed
|
|
379
|
+
label (`x_{\mathrm{e}}`). Two families on one base that both fit an
|
|
380
|
+
instance fail `ambiguous-base-fallback`: keep one per page, or
|
|
381
|
+
`\explain` the instance. An entry like `v_x` whose index is a label is no
|
|
382
|
+
family: mark it `fixedIndex: true`.
|
|
383
|
+
3. **Index entry**, for a subscript with one meaning on the page — usually
|
|
384
|
+
page-local, since `x_0` may be a starting point on one page and a centre
|
|
385
|
+
on another:
|
|
386
|
+
|
|
387
|
+
```yaml
|
|
388
|
+
notation:
|
|
389
|
+
local:
|
|
390
|
+
- key: initial
|
|
391
|
+
latex: "{}_0" # quoted: a bare {} starts a YAML mapping
|
|
392
|
+
label: Initial value
|
|
393
|
+
meaning: The value of a quantity at the start, when time is zero.
|
|
394
|
+
reads: "{base} evaluated at t = 0" # optional
|
|
395
|
+
formula: "{base}_0 = {base}\\,(\\explain{time}{t} = 0)" # optional
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Every symbol of the page that has a card of its own then shows `x_0` as
|
|
399
|
+
one derived card, titled from `reads` ("Velocity vector evaluated at
|
|
400
|
+
t = 0"; the default is "Initial value of velocity vector"), with the
|
|
401
|
+
index entry's meaning and the base's units. An index entry takes no
|
|
402
|
+
`units`, `dimensionless`, `range` or `fixedIndex` (the loader fails on
|
|
403
|
+
them), and rule N19 skips it. `reads` belongs to an index entry only; it
|
|
404
|
+
names the symbol with `{base}` and is plain prose, with no `$`, `\` or
|
|
405
|
+
backtick.
|
|
406
|
+
|
|
407
|
+
An index letter with its own card explains its slot, arithmetic included
|
|
408
|
+
(`X_{t-1}`); a base-library letter does not, so `x_i` needs an `i` card (an
|
|
409
|
+
index letter, with `range`, step 11) or a family. A digit beside a carded
|
|
410
|
+
letter in another slot (`F_{0,T}`) needs a family (`F_{t,T}`) or an index
|
|
411
|
+
entry. When the message says the base has no card either (an indicator
|
|
412
|
+
`\mathbf{1}_{\{k=n\}}`), give the base an entry.
|
|
413
|
+
|
|
414
|
+
### 11. `index-range`: the set a running index runs over
|
|
415
|
+
|
|
416
|
+
A running index is a lowercase letter in a subscript (`i`, `k`, `t`) that
|
|
417
|
+
the page does not declare fixed. State its set once, in one of three ways:
|
|
418
|
+
|
|
419
|
+
- `range` on the letter's card, or on the family entry over it — one edit
|
|
420
|
+
for every page that card is on:
|
|
421
|
+
|
|
422
|
+
```yaml
|
|
423
|
+
key: time.index
|
|
424
|
+
latex: t
|
|
425
|
+
range: "1, \\dots, T"
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
- after a `\quad` on the first display line where the letter is an index,
|
|
429
|
+
for a set that belongs to the page: `x_i \sim \mathcal{N}(\mu, \sigma^2),
|
|
430
|
+
\quad i = 1, \dots, n` (not `\qquad`, which is rule N18's reason slot);
|
|
431
|
+
- `fixedIndex: true` on the letter's card when the letter is a label there
|
|
432
|
+
(a component `x`, a group `g`), not a position in a range.
|
|
433
|
+
|
|
434
|
+
Uppercase and Greek letters in a subscript (`X_N`, `p_\theta`) are sizes and
|
|
435
|
+
parameters: they need a card, never a range.
|
|
436
|
+
|
|
437
|
+
### 12. Notation formulas and assessments
|
|
438
|
+
|
|
439
|
+
`validate:content` reports the same `index-explained` and `index-swallowed`
|
|
440
|
+
in a `formula:` of `content/notation/*.md` or `notation.local`, and in an
|
|
441
|
+
assessment's prompt, explanation or option. In an assessment, fix it as in
|
|
442
|
+
a lesson: the assessment renders with its lesson's notation, derived cards
|
|
443
|
+
included. A formula resolves against its own card's table, where an index
|
|
444
|
+
entry does not compose; explain the indexed symbol there with a whole form —
|
|
445
|
+
`\explain{launch-speed}{v_0}`, or a gloss on the entry:
|
|
446
|
+
|
|
447
|
+
```yaml
|
|
448
|
+
glosses:
|
|
449
|
+
- latex: y_{\mathrm{new}}
|
|
450
|
+
name: yield after the shift
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
— or wrap the subscript in the index entry's key,
|
|
454
|
+
`\mathbf{v}_{\explain{initial}{0}}`, which gives the `0` that card.
|
|
455
|
+
|
|
456
|
+
### 13. Labs and diagrams: index math, a drawn picture, a width
|
|
457
|
+
|
|
458
|
+
**Rule N23 at render.** `astro build` fails with "Lab math has an index no
|
|
459
|
+
card explains (rule N23, <context>)" or "Diagram … has an index no card
|
|
460
|
+
explains (rule N23)", naming the form and the template. Fix the page's
|
|
461
|
+
notation as in steps 8–11. An index entry on the page gives the lab's and
|
|
462
|
+
the diagram's symbols their derived cards too, with no code change, as long
|
|
463
|
+
as the lab passes the table `labMathScope` returned straight to
|
|
464
|
+
`renderLabMath`. A wrapper that copies it (`[...scope]`) gets neither the
|
|
465
|
+
cards nor the check, so pass it unchanged.
|
|
466
|
+
|
|
467
|
+
**A lab's picture is in the built page (rule V3).** `astro build` warns
|
|
468
|
+
`lab-picture-undrawn` for a figure whose picture is an island that draws
|
|
469
|
+
nothing until the browser runs it. A card from another page, print without
|
|
470
|
+
JavaScript, and the HTML, LaTeX and Markdown exports all show an empty box
|
|
471
|
+
there. Draw the lab's default picture at build time in its `.astro` wrapper
|
|
472
|
+
and pass it to the island as children. The island shows them until it has
|
|
473
|
+
drawn into `.lab-chart-live`, and explico's stylesheet hides them from then
|
|
474
|
+
on. With Observable Plot, add `linkedom` as a course devDependency and draw
|
|
475
|
+
with the island's own options at its defaults:
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
// content/labs/still-plot.ts — import it only from .astro frontmatter,
|
|
479
|
+
// so linkedom stays out of the island's bundle
|
|
480
|
+
import * as Plot from '@observablehq/plot';
|
|
481
|
+
import { parseHTML } from 'linkedom';
|
|
482
|
+
|
|
483
|
+
export function stillPlot(options: Plot.PlotOptions): string {
|
|
484
|
+
const { document } = parseHTML('<!doctype html><html><head></head><body></body></html>');
|
|
485
|
+
return (Plot.plot({ ...options, document }) as unknown as Element).outerHTML;
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```astro
|
|
490
|
+
---
|
|
491
|
+
const still = stillPlot(rangePlotOptions(DEFAULTS.speed, DEFAULTS.angle));
|
|
492
|
+
---
|
|
493
|
+
<RangePlot client:visible><Fragment set:html={still} /></RangePlot>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
```tsx
|
|
497
|
+
// the island: show the build's copy until the live plot is in
|
|
498
|
+
<div className="lab-chart">
|
|
499
|
+
{drawn ? null : children}
|
|
500
|
+
<div className="lab-chart-live" ref={chartRef} />
|
|
501
|
+
</div>
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Set `drawn` in the effect that puts the plot into `chartRef`.
|
|
505
|
+
|
|
506
|
+
**A diagram's width (rule V8).** Diagram boxes are now sized from their
|
|
507
|
+
label and formula, so a diagram can change size; re-shoot any screenshot of
|
|
508
|
+
one. A diagram wider than the lesson column, 707px unless the course sets
|
|
509
|
+
`rules.V8.columnWidth`, warns `dia-too-wide`. It used to be an untagged
|
|
510
|
+
console line, above 800px. Shorten its labels, split it, or lay it out
|
|
511
|
+
vertically. `warnAboveWidth={false}` still opts one diagram out, and a
|
|
512
|
+
number there sets that diagram's own limit. A node's `width` alone now takes
|
|
513
|
+
effect, with the height following, so a `height` that was there only to
|
|
514
|
+
make `width` work can go.
|
|
515
|
+
|
|
516
|
+
### 14. `accent-swallowed` and `derived-key-taken`
|
|
517
|
+
|
|
518
|
+
`accent-swallowed` (rule N22, a warning) is the hat's twin of step 9:
|
|
519
|
+
`\explain{beta}{\hat{\beta}}` names a card that says nothing about the hat.
|
|
520
|
+
Wrap only the letter, `\hat{\explain{beta}{\beta}}`, and explain the hat
|
|
521
|
+
(an operator entry `\hat{}`, or `rules.N22.allow`), or name an entry for
|
|
522
|
+
`\hat{\beta}`. `derived-key-taken` means an authored key has the form
|
|
523
|
+
`<entry>.sub.<index entry>`, which the build uses for derived cards: rename
|
|
524
|
+
it (a MAJOR bump under rule C2, step 20).
|
|
525
|
+
|
|
526
|
+
### 15. Code a course owns
|
|
527
|
+
|
|
528
|
+
- **Manifest v31.** `MANIFEST_SCHEMA_VERSION` goes from 25 to 31, so a
|
|
529
|
+
course test that pins it by number moves to 31. Along the way:
|
|
530
|
+
- v26 adds `cards`, the course's card settings with defaults applied;
|
|
531
|
+
- v27 adds `lessonExports.latex` and `lessonExports.latexPaper`, and gives
|
|
532
|
+
every `assessmentContent` item its `type`, a choice item its `options`
|
|
533
|
+
and `correctOptionId`, and a numeric item its `answer`;
|
|
534
|
+
- v28 adds `lessonExports.markdown`;
|
|
535
|
+
- v29 removes `lessons[].status`, the `editorialStatus` of the notation
|
|
536
|
+
definitions under `lessons[]` and `pages[]`, and the `status` of
|
|
537
|
+
`notation.definitions[]` and `notation.bundles[]`;
|
|
538
|
+
- v30 makes `lessons[].headings[].text` the text a reader sees (a formula
|
|
539
|
+
as it reads, a `[[key]]` term as its label), marks a heading with math
|
|
540
|
+
`math: true`, and gives each choice option `labelSegments`;
|
|
541
|
+
- v31 adds `derived`, the page's derived cards, to `lessons[].notation`
|
|
542
|
+
and `pages[].notation`. A notation definition carries `reads`, `range`,
|
|
543
|
+
`fixedIndex` and `formulaTemplate` when set, and a bundle definition
|
|
544
|
+
carries `range`.
|
|
545
|
+
- **Removed exports.** `EditorialStatus` and the `status` field of
|
|
546
|
+
`SharedNotationDefinitionInput`, `NotationLessonInput`, the notation
|
|
547
|
+
definition records and `NotationPageBundle` (`explico/reference/types`);
|
|
548
|
+
`LessonDefinition.status` and `SourceDefinition.editorialStatus`
|
|
549
|
+
(`explico/curriculum/validation`); `NotationLayer`'s per-definition
|
|
550
|
+
`editorialStatus`; `CourseConventions`. A course test that builds these
|
|
551
|
+
inputs drops `status`. `estimateBoxSize` is gone from
|
|
552
|
+
`explico/reference/diagram-layout`; size a node with
|
|
553
|
+
`nodeBoxSize({ text, formula: measureFormula(latex, fontPx) })`
|
|
554
|
+
(`measureFormula` from `explico/reference/katex-measure`).
|
|
555
|
+
- **`runConsistencyChecks`** no longer takes `catalog` or `conventions`
|
|
556
|
+
(step 4).
|
|
557
|
+
- **Diagnostic codes.** `review-state` and `alignment-review-state` are gone.
|
|
558
|
+
A lesson that `teaches` but declares no `assumptions` now reports
|
|
559
|
+
`missing-assumptions`. Rename either code where a course test or
|
|
560
|
+
`lint-ignore.yml` names it.
|
|
561
|
+
- **`resolveMathGlyphs`** returns `indices` and `derived` and takes a
|
|
562
|
+
`derive` option. A course test that compares its whole result with
|
|
563
|
+
`toEqual` sees an unresolved item carry `lenders` and a decoration carry
|
|
564
|
+
`wholeFormExplicit`.
|
|
565
|
+
- **The `content` CLI's JSON** loses `draftDebt` and `lesson.status` (step
|
|
566
|
+
3). Its lists now include the last build's render findings (from
|
|
567
|
+
`build/render-diagnostics.json`) under a `render:` source, such as
|
|
568
|
+
`render:dia-too-wide`.
|
|
569
|
+
- **A card layer of the course's own** (rare) implements the new
|
|
570
|
+
`CardSource.build(item, page)` and `CardSource.awayItem(item, page)` from
|
|
571
|
+
`card-manager.ts`, which carried cards need.
|
|
572
|
+
|
|
573
|
+
### 16. Course CSS and browser tests
|
|
574
|
+
|
|
575
|
+
Selectors and accessible names that moved:
|
|
576
|
+
|
|
577
|
+
```bash
|
|
578
|
+
rg -n 'float-caption__anchor|keyed-equation__(controls|copy)|float-ref-panel-jump|explico-keep-left|(notation|glossary|citation|citation-panel)-status|Keep the article left|this lesson|Lesson exports|Go to (figure|equation|table|diagram) |data-card-key="notation:' src tests
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
- **A float's chain icon is gone**: `a.float-caption__anchor` no longer
|
|
582
|
+
exists on figures, diagrams or tables. Hover or focus the float's number,
|
|
583
|
+
then use `a.float-toolbar__link`, which carries the same
|
|
584
|
+
`data-copy-link`. An equation's `button.keyed-equation__copy` is now a
|
|
585
|
+
child of `.keyed-equation`, not of `.keyed-equation__controls`.
|
|
586
|
+
- **A page-local symbol's card key is scoped to its page**:
|
|
587
|
+
`[data-card-key="notation:theta-star@projectiles/optimal-launch-angle"]`,
|
|
588
|
+
not `notation:theta-star`. A shared symbol's key is unchanged.
|
|
589
|
+
- **A reference card names its float in the title**: "Equation (1.1.3)",
|
|
590
|
+
"Figure 2.2.1 · …". `[data-panel-number]` moved into the title; an
|
|
591
|
+
equation's now reads "Equation (1.1.3)" rather than "(1.1.3)". The
|
|
592
|
+
"Go to …" link drops the number ("Go to the equation in Position and
|
|
593
|
+
Coordinate Systems", "Go to the table") and sits in its own row,
|
|
594
|
+
`p.float-ref-panel-links`. CSS that placed `.float-ref-panel-jump` as a
|
|
595
|
+
grid item of `.float-ref-panel-body` targets the row instead.
|
|
596
|
+
- **The side column's switches** share `.explico-side-switch` (knob
|
|
597
|
+
`.explico-side-switch-knob`) in place of `.explico-keep-left` and
|
|
598
|
+
`.explico-keep-left-switch`, inside a new row, `.explico-side-controls`,
|
|
599
|
+
which now holds the fixed position. "Keep the article left" reads
|
|
600
|
+
"Article left" (its tooltip is unchanged). `[data-keep-article-left]` is
|
|
601
|
+
unchanged, and "Carry cards" is `[data-carry-cards]`.
|
|
602
|
+
- **Page exports.** The group "Lesson exports" is "Page exports", and the
|
|
603
|
+
print button is "Print or save this page as PDF". The download link
|
|
604
|
+
"Download this lesson as standalone HTML" is now a "Download this page"
|
|
605
|
+
button that opens a menu. Its links are named by scope and format,
|
|
606
|
+
"Download this chapter as standalone HTML" ("… this part …", "… the whole
|
|
607
|
+
course …"), with the file's size appended in parentheses.
|
|
608
|
+
- **Status hooks are gone**: `.notation-status`, `.glossary-status`,
|
|
609
|
+
`.citation-status` and `.citation-panel-status`. A glossary entry's header
|
|
610
|
+
has two columns, not three.
|
|
611
|
+
- **Starlight's mobile menu**: see step 1.
|
|
612
|
+
|
|
613
|
+
Visual baselines move too: card text is 14px, a figure card's picture is 80%
|
|
614
|
+
of its width in the article, and diagram boxes are measured (step 13).
|
|
615
|
+
|
|
616
|
+
### 17. Rule V7: a test that each figure fits on one screen
|
|
617
|
+
|
|
618
|
+
Rule V7 holds a `<Figure>`'s picture (plot, key and tables) to 80% of the
|
|
619
|
+
viewport height, or `rules.V7.maxPercent`, so the reader sees it with its
|
|
620
|
+
caption line. Only a laid-out page knows the height, so the check runs in
|
|
621
|
+
the course's Playwright suite. Add it there, at each viewport the course
|
|
622
|
+
supports:
|
|
623
|
+
|
|
624
|
+
```ts
|
|
625
|
+
import { readFileSync } from 'node:fs';
|
|
626
|
+
import { expect, test } from '@playwright/test';
|
|
627
|
+
import { checkFigureFit, lessonsWithFigures } from 'explico/reference/figure-fit';
|
|
628
|
+
|
|
629
|
+
const manifest = JSON.parse(readFileSync('build/manifest.json', 'utf8'));
|
|
630
|
+
|
|
631
|
+
for (const path of lessonsWithFigures(manifest)) {
|
|
632
|
+
test(`${path} figures fit on one screen (rule V7)`, async ({ page }) => {
|
|
633
|
+
await page.setViewportSize({ width: 1280, height: 800 });
|
|
634
|
+
await page.goto(path);
|
|
635
|
+
const findings = await checkFigureFit(page);
|
|
636
|
+
expect(findings.map((finding) => finding.message)).toEqual([]);
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Pass `{ maxPercent }` when the course sets `rules.V7.maxPercent`, and
|
|
642
|
+
`{ allow: { 'fig-…': '<reason>' } }` for a picture meant to be scrolled.
|
|
643
|
+
Shorten a figure that fails, or give a square or tall plot a fixed width
|
|
644
|
+
(visualizations.md, rule V7).
|
|
645
|
+
|
|
646
|
+
### 18. Optional: what a course can turn on
|
|
647
|
+
|
|
648
|
+
- **LaTeX source and PDF** of every chapter, each part and the course:
|
|
649
|
+
`lessonExports.latex: true`, and `lessonExports.latexPaper: "a4"` for A4
|
|
650
|
+
(the default is `letter`). This needs TeX Live 2025 or later with
|
|
651
|
+
`latexmk` (LuaLaTeX by default; `EXPLICO_LATEX_ENGINE=pdflatex` switches
|
|
652
|
+
engines) and Playwright's Chromium for the figures a browser draws
|
|
653
|
+
(`pnpm exec playwright install chromium`). The TeX Live package list,
|
|
654
|
+
which includes `float` and an optional `cm-unicode`, ships at
|
|
655
|
+
`node_modules/explico/src/compiler/exports/latex/texlive-packages.txt`.
|
|
656
|
+
When `CI` is set, or with `EXPLICO_LATEX_STRICT=1`, a missing engine or
|
|
657
|
+
browser fails the build. Elsewhere the build warns, still writes the
|
|
658
|
+
source zips, and leaves placeholders for uncaptured figures.
|
|
659
|
+
- **Markdown** of every chapter, each part and the course:
|
|
660
|
+
`lessonExports.markdown: true`.
|
|
661
|
+
- **Carry cards from the start**: `cards.carry: true` starts every reader
|
|
662
|
+
with the switch on. A reader's own choice still wins.
|
|
663
|
+
|
|
664
|
+
A course that keeps its settings in `course.settings.json` against a schema
|
|
665
|
+
of its own with `additionalProperties: false` adds `cards`,
|
|
666
|
+
`lessonExports.latex`, `lessonExports.latexPaper` and
|
|
667
|
+
`lessonExports.markdown` to that schema first, each with a `title` and a
|
|
668
|
+
`description`. `rules.V7.maxPercent` and `rules.V8.columnWidth` are in the
|
|
669
|
+
engine's generated rules schema already.
|
|
670
|
+
|
|
671
|
+
### 19. What readers see without a content edit
|
|
672
|
+
|
|
673
|
+
None of this needs a course change, but the course's changelog says what
|
|
674
|
+
readers now see (step 20):
|
|
675
|
+
|
|
676
|
+
- **Cards.** Each float's number has a toolbar: Pin, Dock, Copy link. A
|
|
677
|
+
docked card can be widened, and a width menu sizes them all. "Carry cards"
|
|
678
|
+
keeps kept cards on screen and brings them to every page, each with an
|
|
679
|
+
"Opened at" link back. A symbol in a card from another lesson opens that
|
|
680
|
+
lesson's card. A reference card is titled by its number, a figure card's
|
|
681
|
+
picture is 80% of its width in the article, every card's text is 14px, and
|
|
682
|
+
footer links are outline buttons.
|
|
683
|
+
- **Touch screens** get a text size control (100% to 70%), rendered by
|
|
684
|
+
`LayoutSocialIcons.astro`, which the course already wires as its
|
|
685
|
+
`SocialIcons`.
|
|
686
|
+
- **Every page** has the print button and the Download menu, and Ctrl+P
|
|
687
|
+
loads the labs first.
|
|
688
|
+
- **Heading anchors with math read as the heading**:
|
|
689
|
+
`#the-range-explainmotionranger-in-a-heading` is now
|
|
690
|
+
`#the-range-r-in-a-heading`. A heading whose math has no markup keeps its
|
|
691
|
+
anchor. `validate:content` names a `[[sec-…]]` that used the old one; a
|
|
692
|
+
link from outside the course needs updating by hand.
|
|
693
|
+
- **Numbering.** An equation or a float in a list item or a `>` quote now
|
|
694
|
+
counts on the page as in the manifest, and one in a `:::` aside never
|
|
695
|
+
counts, so a later number can shift. `[@a; @b]` cites both sources, so a
|
|
696
|
+
reference list can gain an entry and renumber. A table one row over
|
|
697
|
+
`truncateAfter` shows whole.
|
|
698
|
+
- **The rules read what a reader sees.** Rule S1 measures a heading's
|
|
699
|
+
readable text, so `\explain{…}{…}` no longer counts against the limit and
|
|
700
|
+
an `explico-allow S1` waiver kept for that reason can go. Rule N9 and rule
|
|
701
|
+
N14 no longer read a link's address, and rule N9 quotes a hand-typed
|
|
702
|
+
sub/superscript whole. A course's own rule (`courseRules`) now matches a
|
|
703
|
+
link's text rather than its address, and matches the text of a
|
|
704
|
+
`caption`, `short`, `title` or `label` prop as a paragraph of its own: a
|
|
705
|
+
`forbid` pattern can newly fail on a caption. A section reference to a
|
|
706
|
+
part's page says why it cannot resolve (rule S10).
|
|
707
|
+
- **Notation.** Two notation formulas may name each other, local or shared;
|
|
708
|
+
a workaround for a local `reference-cycle` can go. A whole form survives a
|
|
709
|
+
power (`v_0^{2}`, step 10).
|
|
710
|
+
- **The LaTeX book and PDF** grow nested `\left … \right` brackets outward
|
|
711
|
+
as the website does (rule N17), link a formula's notation markers to the
|
|
712
|
+
notation appendix, number citations as the page does, and set Greek,
|
|
713
|
+
Cyrillic, CJK and emoji prose from fallback fonts.
|
|
714
|
+
- **Smaller fixes**: Copy LaTeX keeps a space after a control word, search
|
|
715
|
+
indexes a formula once, a wide equation fades at its cut edge, the splash
|
|
716
|
+
hero prints its light image, and a pinned card waits while its section is
|
|
717
|
+
folded.
|
|
718
|
+
|
|
719
|
+
### 20. Record and check
|
|
720
|
+
|
|
721
|
+
Cards changed without a content edit (an instance now opens its family's
|
|
722
|
+
card, a power no longer breaks a whole form, a bare symbol lost a borrowed
|
|
723
|
+
card), and so did what step 19 lists. Add a `content/CHANGELOG.md` bullet
|
|
724
|
+
(rule C1) that says what readers now see, and bump `about.version` (rule C2:
|
|
725
|
+
MINOR for new entries, MAJOR if a notation key was renamed, as in steps 7
|
|
726
|
+
and 14). Then:
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
pnpm validate:content; pnpm validate:content
|
|
730
|
+
pnpm content check --changed
|
|
731
|
+
pnpm exec astro check
|
|
732
|
+
pnpm exec astro build
|
|
733
|
+
pnpm test # unit tests (step 15)
|
|
734
|
+
pnpm test:e2e # browser tests, if the course has them (steps 16–17)
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
`validate:content` must report no `retired-key`, `index-*`,
|
|
738
|
+
`derived-key-taken` or `unresolved-glyph` error, and no
|
|
739
|
+
`config-deprecated-key` warning. `astro build` must report no lab or diagram
|
|
740
|
+
N23 finding. Each `lab-picture-undrawn` and `dia-too-wide` it prints is
|
|
741
|
+
either fixed or deliberate.
|
|
742
|
+
|
|
36
743
|
## 0.11.1 → 0.12.0
|
|
37
744
|
|
|
38
745
|
**Course changes may be required.** Four changes can fail a build that
|