explico 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +350 -1
- package/README.md +16 -2
- package/dist/compiler/astro.d.ts +13 -2
- package/dist/compiler/astro.js +39 -0
- package/dist/compiler/cli.d.ts +30 -4
- package/dist/compiler/cli.js +79 -10
- package/dist/compiler/collections.js +16 -3
- package/dist/compiler/exports/standalone-html.js +13 -0
- package/dist/compiler/logging.d.ts +119 -0
- package/dist/compiler/logging.js +108 -0
- package/dist/compiler/manifest.d.ts +7 -3
- package/dist/compiler/manifest.js +1 -1
- package/dist/reference/base-abbreviations.mjs +8 -2
- package/dist/reference/consistency.d.ts +8 -10
- package/dist/reference/consistency.js +3 -47
- package/dist/reference/delimiter-size.d.ts +48 -0
- package/dist/reference/delimiter-size.js +153 -0
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +2 -2
- package/dist/reference/equations-validate.js +1 -1
- package/dist/reference/equations.d.mts +9 -3
- package/dist/reference/equations.mjs +7 -1
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +2 -2
- package/dist/reference/gate-heading-length.js +2 -2
- package/dist/reference/gate-math.d.ts +25 -1
- package/dist/reference/gate-math.js +50 -9
- package/dist/reference/gate-prose-notation.d.ts +12 -1
- package/dist/reference/gate-prose-notation.js +5 -1
- package/dist/reference/katex-delimiters.d.mts +15 -0
- package/dist/reference/katex-delimiters.mjs +125 -0
- package/dist/reference/katex-options.mjs +4 -0
- package/dist/reference/keyed-float-validate.d.ts +2 -2
- package/dist/reference/keyed-float-validate.js +1 -1
- package/dist/reference/math-glyphs.mjs +16 -2
- package/dist/reference/references.js +2 -1
- package/dist/reference/registry.js +1 -1
- package/dist/reference/rehype-base-links.d.mts +23 -0
- package/dist/reference/rehype-base-links.mjs +40 -0
- package/dist/reference/remark-abbreviations.mjs +10 -12
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/render-lab-math.d.ts +18 -1
- package/dist/reference/render-lab-math.js +11 -4
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/types.d.ts +8 -1
- package/docs/VERSIONING.md +2 -2
- package/docs/authoring/README.md +12 -2
- package/docs/authoring/agents.md +7 -3
- package/docs/authoring/migrating.md +514 -0
- package/docs/authoring/notation.md +157 -7
- package/docs/authoring/prose.md +64 -0
- package/docs/katex-bracket-scaling.md +191 -0
- package/package.json +2 -1
- package/src/compiler/astro.ts +89 -0
- package/src/compiler/cli.ts +167 -12
- package/src/compiler/collections.ts +33 -3
- package/src/compiler/exports/standalone-html.ts +15 -0
- package/src/compiler/logging.ts +259 -0
- package/src/compiler/manifest.ts +7 -3
- package/src/components/memo/Memo.astro +2 -5
- package/src/components/memo/ShortNote.astro +2 -5
- package/src/components/notation/NotationFormula.astro +199 -10
- package/src/components/notation/NotationGlossary.astro +100 -58
- package/src/components/notation/NotationLayer.astro +83 -81
- package/src/components/notation/render-notation-math.ts +111 -10
- package/src/components/scroll-animation.ts +160 -0
- package/src/components/starlight/AboutPanel.astro +17 -2
- package/src/components/starlight/AnchorScrollEnhancer.astro +102 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +2 -4
- package/src/components/starlight/KeyedFloatEnhancer.astro +17 -16
- package/src/components/starlight/LessonFooter.astro +2 -0
- package/src/reference/base-abbreviations.mjs +8 -2
- package/src/reference/consistency.ts +10 -66
- package/src/reference/delimiter-size.ts +279 -0
- package/src/reference/diagrams-validate.ts +1 -1
- package/src/reference/equations-validate.ts +3 -3
- package/src/reference/equations.mjs +7 -1
- package/src/reference/figures-validate.ts +1 -1
- package/src/reference/gate-abbreviations.ts +2 -2
- package/src/reference/gate-heading-length.ts +2 -2
- package/src/reference/gate-math.ts +91 -8
- package/src/reference/gate-prose-notation.ts +15 -1
- package/src/reference/katex-delimiters.mjs +125 -0
- package/src/reference/katex-options.mjs +4 -0
- package/src/reference/keyed-float-validate.ts +3 -3
- package/src/reference/math-glyphs.mjs +16 -2
- package/src/reference/references.ts +2 -1
- package/src/reference/registry.ts +1 -1
- package/src/reference/rehype-base-links.mjs +40 -0
- package/src/reference/remark-abbreviations.mjs +10 -12
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/render-lab-math.ts +25 -2
- package/src/reference/tables-validate.ts +1 -1
- package/src/reference/types.ts +8 -1
- package/src/styles/global.css +119 -14
|
@@ -33,6 +33,510 @@ required config block throws with the section of this file to read.
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
+
## 0.7.0 → 0.8.0
|
|
37
|
+
|
|
38
|
+
### 1. Rule N17 is inverted: delimiters are sized by the engine (`\left`/`\right` everywhere)
|
|
39
|
+
|
|
40
|
+
The engine now installs its own KaTeX delimiter sizing, so a `\left … \right`
|
|
41
|
+
pair is always strictly taller than its content and a nest shows its depth
|
|
42
|
+
without help. Hand-picking `\bigl` → `\Bigl` → `\biggl` → `\Biggl` outward —
|
|
43
|
+
which rule N17 previously *required* — is now the thing the linter warns about.
|
|
44
|
+
|
|
45
|
+
**There is no install step.** `astro.config.mjs` already imports
|
|
46
|
+
`explico/reference/katex-options.mjs`, and that module now imports
|
|
47
|
+
`explico/reference/katex-delimiters.mjs` for its side effect. Confirm the import
|
|
48
|
+
is still there; a course that inlined its own KaTeX options object instead must
|
|
49
|
+
add, as the **first** import in `astro.config.mjs`:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import 'explico/reference/katex-delimiters.mjs';
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Order matters: the installer moves KaTeX's render entry points onto the shared
|
|
56
|
+
`katex` object, so anything that renders math before the import would keep stock
|
|
57
|
+
spacing. It refuses to fail quietly — it renders a known nest at install time and
|
|
58
|
+
throws if the sizes did not grow.
|
|
59
|
+
|
|
60
|
+
Two course-side conditions make the build throw, both with an explicit message:
|
|
61
|
+
|
|
62
|
+
- **A `patches/katex@*.patch` file that already applies a negative
|
|
63
|
+
`\delimitershortfall`.** Delete the patch and its `pnpm.patchedDependencies`
|
|
64
|
+
entry; the engine does this in code now, and a patch is project-local anyway
|
|
65
|
+
so it never reached a consumer.
|
|
66
|
+
- **A `katex` whose bundle no longer holds the constant where the engine looks
|
|
67
|
+
for it.** The rewrite targets one line in KaTeX's ESM bundle, so keep `katex`
|
|
68
|
+
on the declared peer version (`0.16.47`). An upgrade that moves or reformats
|
|
69
|
+
that line fails the build asking you to re-derive the change against
|
|
70
|
+
[`../katex-bracket-scaling.md`](../katex-bracket-scaling.md), which is
|
|
71
|
+
shipped in the package. The failure is loud and immediate, not a silent
|
|
72
|
+
return to stock spacing.
|
|
73
|
+
|
|
74
|
+
### 2. Diagnostic renamed: `delimiter-size-hierarchy` → `delimiter-manual-size`
|
|
75
|
+
|
|
76
|
+
The old code string no longer exists. Update every place that names it:
|
|
77
|
+
|
|
78
|
+
- `lint-ignore.yml` — a stale line is inert and silently stops suppressing.
|
|
79
|
+
- Course scripts, tests, and type narrowings over the diagnostic union;
|
|
80
|
+
`astro check` flags a comparison against a non-member.
|
|
81
|
+
|
|
82
|
+
Its payload changed shape too. A consumer reading the fields, rather than just
|
|
83
|
+
the `code` and `message`, needs this edit:
|
|
84
|
+
|
|
85
|
+
```diff
|
|
86
|
+
-// outerSize / nestedSize described the mismatch between two levels
|
|
87
|
+
-const found = diagnostic.outerSize;
|
|
88
|
+
-const suggested = diagnostic.suggestion?.size;
|
|
89
|
+
+// `size` is the hand-picked size found; `suggestion` is always present and is
|
|
90
|
+
+// always a \left/\right pair, so it no longer carries a `size` of its own.
|
|
91
|
+
+const found = diagnostic.size;
|
|
92
|
+
+const suggested = diagnostic.suggestion.latex;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`DelimiterSizeSuggestion` keeps `open`, `close`, and `latex`, and drops `size`.
|
|
96
|
+
`DelimiterSizeDiagnostic` drops `outerSize` and `nestedSize`, gains a required
|
|
97
|
+
`size`, and `suggestion` is no longer optional.
|
|
98
|
+
|
|
99
|
+
### 3. Content: hand-sized nests now warn
|
|
100
|
+
|
|
101
|
+
Math that was N17-compliant under 0.7.0 reports one `delimiter-manual-size`
|
|
102
|
+
finding per hand-sized level. This is a Tier-3 warning — it does not fail a
|
|
103
|
+
build — so it can be worked through at your own pace, but the findings are real
|
|
104
|
+
and the repair improves the rendering.
|
|
105
|
+
|
|
106
|
+
Find them with:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
pnpm content warnings --json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The repair is mechanical: replace the hand-picked pair with `\left`/`\right`,
|
|
113
|
+
keeping the delimiter shapes.
|
|
114
|
+
|
|
115
|
+
```diff
|
|
116
|
+
-\Biggl[a+\biggl(b+\Bigl[c+\left(d+e\right)\Bigr]\biggr)\Biggr]
|
|
117
|
+
+\left[a+\left(b+\left[c+\left(d+e\right)\right]\right)\right]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A **lone** hand-sized pair that is not part of a nest — `\bigl(x,\ y\bigr)`
|
|
121
|
+
around a tuple, for instance — is a single-level typographic choice with no
|
|
122
|
+
hierarchy to get wrong, and is deliberately left alone. Do not convert those.
|
|
123
|
+
|
|
124
|
+
Expect a small visual change everywhere a nest is rendered: each level is now
|
|
125
|
+
strictly larger than the one inside it, so outer delimiters grow by roughly one
|
|
126
|
+
size step. A course holding screenshot or bounding-box baselines over math
|
|
127
|
+
should re-record them.
|
|
128
|
+
|
|
129
|
+
### 4. Manifest schema is now v16: a math diagnostic can name its equation
|
|
130
|
+
|
|
131
|
+
`MANIFEST_SCHEMA_VERSION` is 16 (v15 → v16). The bump is **additive** — nothing
|
|
132
|
+
existing changed shape — so the only required edit is to a client that asserts
|
|
133
|
+
the number by exact equality, which now expects 16.
|
|
134
|
+
|
|
135
|
+
What was added: a finding the math gate reports from a `$$…$$` block carrying a
|
|
136
|
+
`\label{eq:…}` gains an optional `equation` field, `{ key, href }`. `href` is
|
|
137
|
+
the rendered page's anchor for that equation
|
|
138
|
+
(`/l1-ar/ar1-basics/#eq-ar1-variance`). `CliDiagnostic` carries the same
|
|
139
|
+
optional field, so a course's own `scripts/content.ts` picks it up with no
|
|
140
|
+
change.
|
|
141
|
+
|
|
142
|
+
`diagnosticLine()` now appends it, so console output, the run log, and
|
|
143
|
+
`pnpm content diagnostics` read:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
[code] file:line:column: message (eq:<key> -> <href>)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
A course script that parses that line with an anchored regex must tolerate the
|
|
150
|
+
optional trailing ` (eq:… -> …)`. One that just prints the string needs nothing.
|
|
151
|
+
|
|
152
|
+
### 5. Diagnostic line numbers are corrected — re-record anything that stored them
|
|
153
|
+
|
|
154
|
+
Every gate scans the lesson body, which Astro hands over with the frontmatter
|
|
155
|
+
already stripped, but findings are reported against the lesson *file* — so every
|
|
156
|
+
`file:line:column` the engine has emitted for a lesson was short by the height
|
|
157
|
+
of that lesson's frontmatter. `gate-math` (every `delimiter-manual-size`
|
|
158
|
+
column), `gate-prose-notation` (rule N9), `gate-abbreviations` (rule N14), and
|
|
159
|
+
`gate-heading-length` (S1) are all corrected at once.
|
|
160
|
+
|
|
161
|
+
Nothing to edit in content, but line numbers move, so:
|
|
162
|
+
|
|
163
|
+
- Re-check any suppression, snapshot, or problem matcher keyed to a line number.
|
|
164
|
+
Line numbers were wrong before; they now point at the real line.
|
|
165
|
+
- `pnpm validate:content` (twice) regenerates `build/resolution/*` with the
|
|
166
|
+
corrected positions. Commit the result.
|
|
167
|
+
|
|
168
|
+
### 6. Malformed `\explain` / `\slot` keys now fail the build
|
|
169
|
+
|
|
170
|
+
Previously a key that did not match the notation key pattern —
|
|
171
|
+
`\explain{Not A Key}{\Omega}` — was not a KaTeX parse error: KaTeX rendered the
|
|
172
|
+
command name in its error color and carried on, so the page shipped red
|
|
173
|
+
`\htmlData` text with a green build. `renderNotationMath` now checks both marker
|
|
174
|
+
macros before KaTeX runs and throws, naming the offending key.
|
|
175
|
+
|
|
176
|
+
**This can newly fail a build that passed on 0.7.0.** If it does, the page was
|
|
177
|
+
already broken for readers. Fix the key to match the notation key pattern
|
|
178
|
+
(lower-case, hyphen-separated) and make sure it resolves to a real entry.
|
|
179
|
+
`renderNotationFormula` still degrades to inert-but-correct math rather than
|
|
180
|
+
costing a reader the equation.
|
|
181
|
+
|
|
182
|
+
### 7. Glossary entry heading markup: the anchor is now a sibling of the `<h2>`
|
|
183
|
+
|
|
184
|
+
The per-entry anchor link moved out of the `<h2>` and into a new
|
|
185
|
+
`.glossary-heading` flex row wrapping both — the same shape
|
|
186
|
+
`rehype-heading-anchors` gives a lesson heading. This restores the heading's
|
|
187
|
+
accessible name (a screen reader was announcing "Velocity Link to Velocity").
|
|
188
|
+
|
|
189
|
+
Nothing visual changed, but update course-owned CSS and end-to-end tests that
|
|
190
|
+
assumed the nesting:
|
|
191
|
+
|
|
192
|
+
```diff
|
|
193
|
+
-h2:hover .glossary-anchor,
|
|
194
|
+
-h2:focus-within .glossary-anchor {
|
|
195
|
+
+.glossary-heading:hover .glossary-anchor,
|
|
196
|
+
+.glossary-heading:focus-within .glossary-anchor {
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
A test locating the anchor as a descendant of the heading must target
|
|
200
|
+
`.glossary-heading .glossary-anchor` instead. A check for the heading *by
|
|
201
|
+
accessible name* now matches the term alone, which is the point of the fix — if
|
|
202
|
+
such a test was written against the broken name ("Velocity Link to Velocity"),
|
|
203
|
+
it needs the term.
|
|
204
|
+
|
|
205
|
+
### 8. The About panel publishes its versions as data attributes
|
|
206
|
+
|
|
207
|
+
Additive; no course edit is required. `details[data-about-panel]` now carries
|
|
208
|
+
`data-knowledge-version`, `data-knowledge-date` (omitted when the content
|
|
209
|
+
changelog has no date), and `data-engine-version`, and the rendered version line
|
|
210
|
+
is marked `data-knowledge-line`.
|
|
211
|
+
|
|
212
|
+
This exists so a build check does not have to match prose. A course asserting
|
|
213
|
+
the panel's contents by text is pinned to one version string and turns every
|
|
214
|
+
routine bump into a test edit — this repo's own `about.spec.ts` was asserting
|
|
215
|
+
`0.4.0` against a playground long since past it. Prefer:
|
|
216
|
+
|
|
217
|
+
```diff
|
|
218
|
+
-await expect(panel).toContainText('0.6.0');
|
|
219
|
+
+await expect(panel).toHaveAttribute('data-knowledge-version', knowledgeVersion);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
reading the expected value from `content/course.config.ts` rather than hard-coding
|
|
223
|
+
it. A bare version substring is not scoped to the panel either — the engine
|
|
224
|
+
version printed one row below can satisfy it.
|
|
225
|
+
|
|
226
|
+
### 9. Fixes that need no action
|
|
227
|
+
|
|
228
|
+
These remove build failures; they never require a content edit. Formulas you
|
|
229
|
+
previously worked around may now be written directly.
|
|
230
|
+
|
|
231
|
+
- **A notation `formula` can use a manual delimiter size, an accent, a box, or
|
|
232
|
+
a color.** `render-notation-math.ts`'s attribute allowlist is now KaTeX's
|
|
233
|
+
whole inert presentation surface, so `\Bigl`/`\biggl`/`\Biggl`,
|
|
234
|
+
`\xrightarrow`, `\boxed`, and `\colorbox` no longer throw
|
|
235
|
+
`Unexpected KaTeX property`. `alt`, `href`, `src`, and `title` are explicitly
|
|
236
|
+
denied; no attribute that can carry a URL is allowed through.
|
|
237
|
+
- **`\vec` and every other accent renders.** The style sanitizer no longer
|
|
238
|
+
requires a trailing `;` on the last CSS declaration. `\mathbf` remains the
|
|
239
|
+
house style for a vector; `\vec` simply works now.
|
|
240
|
+
- **A macro in a formula no longer invents a source span.** `\vdots`,
|
|
241
|
+
`\varSigma`, `\argmax`, `\bmod`, `\R`/`\N`/`\Z` and 79 of KaTeX's 282 macros
|
|
242
|
+
produce nodes whose `loc` indexes the macro body, which the glyph resolver
|
|
243
|
+
read as a span over unrelated text — failing with `Unresolved notation ""`,
|
|
244
|
+
or worse, silently splitting a formula mid-command. Fixed. An existing
|
|
245
|
+
explicit `\explain{key}{\varSigma}` annotation still works and is still the
|
|
246
|
+
way to bind a macro-expanded glyph, since it has no authored span for
|
|
247
|
+
canonical matching to see.
|
|
248
|
+
- **`equationAnchorId({ key })` type-checks without a `number`.** Its JSDoc
|
|
249
|
+
required a property the function ignores when a `key` is given.
|
|
250
|
+
|
|
251
|
+
### 10. Verify
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
pnpm add -D explico@0.8.0
|
|
255
|
+
pnpm validate:content # twice — the first run regenerates build/resolution/*
|
|
256
|
+
pnpm content check --changed
|
|
257
|
+
pnpm content warnings # expect new delimiter-manual-size findings (item 3)
|
|
258
|
+
astro check
|
|
259
|
+
astro build
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Commit the regenerated `build/resolution/*` (items 4 and 5 both change it).
|
|
263
|
+
|
|
264
|
+
## 0.6.0 → 0.7.0
|
|
265
|
+
|
|
266
|
+
### 1. Manifest schema is now v15: diagnostic severity has three levels
|
|
267
|
+
|
|
268
|
+
`MANIFEST_SCHEMA_VERSION` is 15 (v14 → v15). Public diagnostic severity unions
|
|
269
|
+
now include `info`, so a client that treated "not an error" as "a warning"
|
|
270
|
+
needs three edits:
|
|
271
|
+
|
|
272
|
+
1. A client asserting `MANIFEST_SCHEMA_VERSION` by exact equality expects 15.
|
|
273
|
+
2. Widen any hand-written `'error' | 'warning'` type over manifest diagnostics
|
|
274
|
+
to `'error' | 'warning' | 'info'`. `ConsistencyDiagnostic.severity` is now
|
|
275
|
+
`'warning' | 'info'`.
|
|
276
|
+
3. In `scripts/compile-manifest.ts` (and any other consumer), filter on
|
|
277
|
+
`severity === 'warning'` before printing or counting warnings. A script that
|
|
278
|
+
counts all of `manifest.diagnostics.consistency` as "Tier-3 findings" now
|
|
279
|
+
over-reports:
|
|
280
|
+
|
|
281
|
+
```diff
|
|
282
|
+
-const consistencyByCode = consistencyCounts(consistency);
|
|
283
|
+
-const consistencyTotal = consistency.length;
|
|
284
|
+
+const consistencyWarnings = consistency.filter(
|
|
285
|
+
+ (diagnostic) => diagnostic.severity === 'warning',
|
|
286
|
+
+);
|
|
287
|
+
+const consistencyByCode = consistencyCounts(consistencyWarnings);
|
|
288
|
+
+const consistencyTotal = consistencyWarnings.length;
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
These codes moved from `warning` to `info`: `eq-key-unused`, every keyed-float
|
|
292
|
+
`*-key-unused`, `unused-definition`, `weak-local`, `gloss-wants-promoting`, and
|
|
293
|
+
`card-wants-demoting`. Their code strings and container fields did not change,
|
|
294
|
+
the `lint-ignore.yml` lines that already worked for `weak-local`,
|
|
295
|
+
`gloss-wants-promoting`, and `card-wants-demoting` still match, and nothing
|
|
296
|
+
blocks the build. They no longer appear in `pnpm content warnings`; read them
|
|
297
|
+
with `pnpm content diagnostics info`.
|
|
298
|
+
|
|
299
|
+
Run `pnpm validate:content` twice. The committed `build/resolution/*` files
|
|
300
|
+
(including `consistency-report.json`) change because those findings now carry
|
|
301
|
+
`info` severity and `numerals-tagged` findings are gone (item 2); commit them.
|
|
302
|
+
|
|
303
|
+
### 2. Retired diagnostic: `numerals-tagged`
|
|
304
|
+
|
|
305
|
+
`ConsistencyCode` no longer contains `numerals-tagged`, and the engine never
|
|
306
|
+
emits it. Delete every `numerals-tagged` line from `lint-ignore.yml` (a stale
|
|
307
|
+
line is inert but misleads the next reader) and every course script, test, or
|
|
308
|
+
type narrowing that names the code — `tsc`/`astro check` flags the latter as a
|
|
309
|
+
comparison against a non-member of the union.
|
|
310
|
+
|
|
311
|
+
### 3. `explicoContentRefresh()` fails the build on a missing remark plugin (rule N14 and its siblings)
|
|
312
|
+
|
|
313
|
+
This is the enforcement half of rule N14's Astro wiring (see item 4 of the
|
|
314
|
+
0.4.x → 0.5.0 section). Its `astro:config:setup` hook now compares the manifest
|
|
315
|
+
against the configured remark plugins and throws, naming each gap, when a
|
|
316
|
+
non-empty table has no matching plugin registered:
|
|
317
|
+
|
|
318
|
+
| Manifest table is non-empty | Plugin that must be registered |
|
|
319
|
+
| --- | --- |
|
|
320
|
+
| `manifest.abbreviations` | `[remarkAbbreviations, { abbreviations: manifest.abbreviations }]` from `explico/reference/remark-abbreviations.mjs` |
|
|
321
|
+
| `manifest.sources` | `[remarkCitation, { sources: manifest.sources }]` from `explico/reference/remark-citation.mjs` |
|
|
322
|
+
| `manifest.notation.raw` | `[remarkNotation, createRemarkNotationOptions(manifest)]` from `explico/reference/remark-notation.mjs` |
|
|
323
|
+
|
|
324
|
+
Check `astro.config.mjs` against that table. The check reads both wiring
|
|
325
|
+
surfaces Astro offers — the flat `markdown.remarkPlugins` array and a
|
|
326
|
+
`markdown.processor` such as `unified({ remarkPlugins: [...] })` — and accepts
|
|
327
|
+
either the bare plugin or a `[plugin, options]` tuple. It compares by identity
|
|
328
|
+
with the module the `explico/reference/*.mjs` specifier resolves to, so register
|
|
329
|
+
the imported function itself rather than a local wrapper around it. A course
|
|
330
|
+
that was already fully wired needs no edit; one that skipped a plugin was
|
|
331
|
+
silently rendering triggers as plain text and now fails `astro build` /
|
|
332
|
+
`astro dev` until it adds the missing registration.
|
|
333
|
+
|
|
334
|
+
### 4. Removed markup: popup "Copy LaTeX", glossary `#` copy-link, formula scroll region
|
|
335
|
+
|
|
336
|
+
None of these has a replacement selector; update course-owned CSS and
|
|
337
|
+
end-to-end tests that target them:
|
|
338
|
+
|
|
339
|
+
- `.notation-popup-copy` / `[data-popup-copy]` — the button in a notation
|
|
340
|
+
popup. Copying is now a click on the equation itself (item 8).
|
|
341
|
+
- `[data-glossary-anchor]` and its "Link copied" flash — a glossary entry's `#`
|
|
342
|
+
button that wrote its URL to the clipboard. The entry title is now a link to
|
|
343
|
+
`#notation-<key>` (`.glossary-term-link`), and a hover-revealed link-icon
|
|
344
|
+
anchor (`.glossary-anchor`) simply navigates; nothing is copied.
|
|
345
|
+
- `NotationFormula`'s `tabindex="0"` scroll region moved from
|
|
346
|
+
`.notation-formula-math` to a nested `.notation-formula-scroll`. A test that
|
|
347
|
+
focuses or scrolls `.notation-formula-math` must target the inner element.
|
|
348
|
+
|
|
349
|
+
No source or config change is needed beyond selectors.
|
|
350
|
+
|
|
351
|
+
### 5. Rule N14: every occurrence of a catalogued abbreviation is now wrapped
|
|
352
|
+
|
|
353
|
+
Two changes ride under rule N14, neither of which needs a config edit:
|
|
354
|
+
|
|
355
|
+
- **Rendered output changed.** `remarkAbbreviations` used to wrap only the first
|
|
356
|
+
occurrence of each catalogued abbreviation per page; it now wraps every
|
|
357
|
+
occurrence (`a.abbreviation-term[data-abbr-key]`). A course-owned e2e test or
|
|
358
|
+
snapshot that expected exactly one such link per term per page, or CSS that
|
|
359
|
+
assumed a page's later occurrences were plain text, must be updated.
|
|
360
|
+
`AbbreviationLayer.astro` already resolved markers independently by
|
|
361
|
+
`data-abbr-key`, so no island change is needed.
|
|
362
|
+
- **The shipped baseline grew** (`base-abbreviations.mjs`): `AM`, `PM`, `A.M.`,
|
|
363
|
+
`P.M.`, and `e.t.c.` join `a.m.`, `p.m.`, `e.g.`, `i.e.`, and `etc.`. This only
|
|
364
|
+
loosens the gate. A now-redundant `abbreviations.allow` line or
|
|
365
|
+
`content/abbreviations/*.md` entry for one of them is harmless and can stay; a
|
|
366
|
+
course that wants one explained anyway lists it in `abbreviations.deny`.
|
|
367
|
+
|
|
368
|
+
### 6. Rule N16 and rule N17: delimiter conventions and sizes
|
|
369
|
+
|
|
370
|
+
Rule N16 (alternate `()`, `[]`, `\{\}` for purely stylistic nested grouping,
|
|
371
|
+
never for conventional delimiters such as `f(x)`, `\mathbb{E}[X]`, or
|
|
372
|
+
intervals) is **review-only**: nothing checks it and nothing needs to change to
|
|
373
|
+
keep building. Rule N17 (every outer scalable pair in a nest grows strictly
|
|
374
|
+
larger than the pairs inside it: `\left…\right` → `\Bigl…\Bigr` → `\biggl…\biggr`
|
|
375
|
+
→ `\Biggl…\Biggr`) is a **Tier-3 warning**, `delimiter-size-hierarchy`, reported
|
|
376
|
+
at the outer pair's line and column by the normal math gate for lesson math,
|
|
377
|
+
notation formulas, and assessment math. It never fails a build, so no course
|
|
378
|
+
needs to change to keep building. To clear the warnings, run
|
|
379
|
+
`pnpm content diagnostics warning`, and enlarge each named outer pair to the
|
|
380
|
+
next manual size without changing its delimiter shape. Rule N15's build-enforced
|
|
381
|
+
behavior is unchanged — its documentation now also accepts an N17 manual pair as
|
|
382
|
+
"sized". See [`notation.md#n16`](notation.md#n16) and
|
|
383
|
+
[`notation.md#n17`](notation.md#n17).
|
|
384
|
+
|
|
385
|
+
### 7. Rule P1: "or" never introduces a second name for the same thing
|
|
386
|
+
|
|
387
|
+
Rule P1 opens the new `P` (prose) rule area and is **review-only**: nothing is
|
|
388
|
+
checked at build time and no course change is required. When editing lessons,
|
|
389
|
+
replace "the residual or error term" with "the residual (i.e., the error
|
|
390
|
+
term)"-style wording. See [`prose.md#p1`](prose.md#p1).
|
|
391
|
+
|
|
392
|
+
### 8. Optional: click-to-copy equations, glossary equation numbers, and live lab LaTeX
|
|
393
|
+
|
|
394
|
+
Nothing to do for a course that wires `Footer` to `LessonFooter.astro`: a
|
|
395
|
+
click on any `[data-notation-formula]` box now copies its `data-latex`, and every
|
|
396
|
+
glossary formula gets a `G.<n>` number and copy button, automatically.
|
|
397
|
+
|
|
398
|
+
Only a course with an interactive lab island that renders math through
|
|
399
|
+
`renderLabMath()` can opt that equation into the gesture, and keep the copied
|
|
400
|
+
LaTeX in step with the sliders, with `plainLatexTemplate` and the new
|
|
401
|
+
`slotPlaceholder` export:
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
import {
|
|
405
|
+
slotPlaceholder,
|
|
406
|
+
type RenderedLabMath,
|
|
407
|
+
} from 'explico/reference/render-lab-math';
|
|
408
|
+
|
|
409
|
+
// On the math root element:
|
|
410
|
+
<div
|
|
411
|
+
className="lab-math"
|
|
412
|
+
data-notation-formula
|
|
413
|
+
data-latex={rendered.plainLatexTemplate}
|
|
414
|
+
/* … */
|
|
415
|
+
/>
|
|
416
|
+
|
|
417
|
+
// Where the island writes each slot's live value (`values`: slot name → text):
|
|
418
|
+
let latex = rendered.plainLatexTemplate;
|
|
419
|
+
for (const [name, value] of Object.entries(values)) {
|
|
420
|
+
latex = latex.split(slotPlaceholder(name)).join(value);
|
|
421
|
+
}
|
|
422
|
+
root.dataset.latex = latex;
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Rebuild `latex` from the template on every update, not from the previous result.
|
|
426
|
+
A lab that does not set these attributes is unchanged. `RenderedLabMath` gained
|
|
427
|
+
the required `plainLatexTemplate` field; a course that constructs one by hand
|
|
428
|
+
(a test double, for instance) must add it.
|
|
429
|
+
|
|
430
|
+
### 9. Only if you override `Footer` yourself: mount `AnchorScrollEnhancer`
|
|
431
|
+
|
|
432
|
+
The new smooth-scroll behavior for in-page anchor links ships in
|
|
433
|
+
`AnchorScrollEnhancer.astro`, which `LessonFooter.astro` mounts. A course whose
|
|
434
|
+
Starlight `components.Footer` is `explico/components/starlight/LessonFooter.astro`
|
|
435
|
+
gets it with no change. A course that swapped in its own footer component must
|
|
436
|
+
render it (`import AnchorScrollEnhancer from
|
|
437
|
+
'explico/components/starlight/AnchorScrollEnhancer.astro'`, then
|
|
438
|
+
`<AnchorScrollEnhancer />`) or its anchor links keep the browser's native jump.
|
|
439
|
+
|
|
440
|
+
### 10. Optional: wire `rehypeBaseLinks` for a course deployed under a subpath
|
|
441
|
+
|
|
442
|
+
Skip this for a course served from a domain root (`base` omitted or `'/'`); the
|
|
443
|
+
plugin is a no-op there. For a course under a subpath (a GitHub Pages *project*
|
|
444
|
+
site, `base: '/my-course'`), Starlight prefixes only its own navigation, so
|
|
445
|
+
every root-relative link the Markdown pipeline produces — prose links,
|
|
446
|
+
equation cross-references, citation links — 404s without this:
|
|
447
|
+
|
|
448
|
+
```diff
|
|
449
|
+
+ import rehypeBaseLinks from 'explico/reference/rehype-base-links.mjs';
|
|
450
|
+
…
|
|
451
|
+
rehypePlugins: [
|
|
452
|
+
[rehypeKatex, createNotationKatexOptions()],
|
|
453
|
+
rehypeFailKatexErrors,
|
|
454
|
+
+ [rehypeBaseLinks, base],
|
|
455
|
+
]
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
`base` is the same value passed to `defineConfig({ base })`. **Undo any manual
|
|
459
|
+
workaround first:** the plugin prefixes every `href` beginning with a single
|
|
460
|
+
`/`, so a lesson link already hand-written as `/my-course/other/` would become
|
|
461
|
+
`/my-course/my-course/other/`. Write lesson links without the base. A lesson's
|
|
462
|
+
Starlight frontmatter (`hero.actions[].link`) never passes through this
|
|
463
|
+
pipeline; write those as paths relative to the current page.
|
|
464
|
+
|
|
465
|
+
### 11. Optional: run logs for `pnpm validate:content`
|
|
466
|
+
|
|
467
|
+
Route the course's `scripts/compile-manifest.ts` through `createRunLog()` to
|
|
468
|
+
record every diagnostic to `build/logs/<timestamp>/{error,warning,info}.log`
|
|
469
|
+
(Python `logging` format, `build/logs/latest` symlinks the newest run):
|
|
470
|
+
|
|
471
|
+
```diff
|
|
472
|
+
+ import { createRunLog } from 'explico/compiler/logging';
|
|
473
|
+
…
|
|
474
|
+
+ const log = createRunLog();
|
|
475
|
+
const manifest = await compileManifest(courseConfig);
|
|
476
|
+
…
|
|
477
|
+
- console.warn(`[${warning.code}] ${warning.message}`);
|
|
478
|
+
+ console.warn(log.warning('notation', `[${warning.code}] ${warning.message}`));
|
|
479
|
+
…
|
|
480
|
+
+ const summary = log.close();
|
|
481
|
+
+ console.log(
|
|
482
|
+
+ `Run log: ${summary.relativeDirectory} ` +
|
|
483
|
+
+ `(${summary.counts.ERROR} error(s), ${summary.counts.WARNING} warning(s), ${summary.counts.INFO} info).`,
|
|
484
|
+
+ );
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Each `log.error/warning/info(source, message)` call returns its message, so
|
|
488
|
+
printing and recording share one expression; `log.infoDiagnostics(manifest.diagnostics)`
|
|
489
|
+
records the severity-`info` findings the console never showed. Call
|
|
490
|
+
`log.close()` before any `throw` so a failing run's log is complete
|
|
491
|
+
(`playground/scripts/compile-manifest.ts` is a full worked example). Add
|
|
492
|
+
`build/logs/` to the course's `.gitignore` — a course commits
|
|
493
|
+
`build/resolution/*`, and nothing prunes old runs.
|
|
494
|
+
|
|
495
|
+
### 12. Optional: the `content diagnostics` / `content warnings` commands and VS Code tasks
|
|
496
|
+
|
|
497
|
+
`content diagnostics [info|warning|error] [--json]` and `content warnings
|
|
498
|
+
[--json]` are new, and `content status` now reports an `info` count
|
|
499
|
+
(`report.diagnostics.infos`). The engine implements them in
|
|
500
|
+
`explico/compiler/cli`, but a course's own `scripts/content.ts` dispatches
|
|
501
|
+
commands, so it must route them:
|
|
502
|
+
|
|
503
|
+
```diff
|
|
504
|
+
import {
|
|
505
|
+
ContentCliError,
|
|
506
|
+
contentCheck,
|
|
507
|
+
contentContext,
|
|
508
|
+
+ contentDiagnostics,
|
|
509
|
+
contentStatus,
|
|
510
|
+
+ contentWarnings,
|
|
511
|
+
…
|
|
512
|
+
} from 'explico/compiler/cli';
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Add a `case 'warnings'` (`contentWarnings(manifest)`) and a `case 'diagnostics'`
|
|
516
|
+
(validate the one positional as `info`/`warning`/`error`, default `info`, then
|
|
517
|
+
`contentDiagnostics(manifest, severity)`) beside `case 'status'`, printing
|
|
518
|
+
`file:line:column: severity code: message` lines — copy
|
|
519
|
+
`playground/scripts/content.ts`. To surface findings in VS Code's Problems
|
|
520
|
+
panel, copy the three **Explico: Show content diagnostics** tasks from the
|
|
521
|
+
engine repository's `.vscode/tasks.json`, replacing the `--filter` package name
|
|
522
|
+
and the problem matcher's `fileLocation` root with the course's own.
|
|
523
|
+
|
|
524
|
+
### 13. No action: other changes in this release
|
|
525
|
+
|
|
526
|
+
- Every `<a>` back-link (`↩`) in a page's References section now also carries a
|
|
527
|
+
`title` tooltip; `remark-citation.mjs` does this itself.
|
|
528
|
+
- Standalone HTML export now inlines a `<link>` only when its `rel` is
|
|
529
|
+
`stylesheet` or an icon type, and leaves other `<link>`s (`canonical`,
|
|
530
|
+
`alternate`, `preload`, …) as authored.
|
|
531
|
+
|
|
532
|
+
### Verification
|
|
533
|
+
|
|
534
|
+
`pnpm validate:content` (run it **twice** — the first run regenerates
|
|
535
|
+
`build/resolution/*`, item 1), then `pnpm content check --changed`, then
|
|
536
|
+
`astro check`, then `astro build`. `astro build` is the step that reports item 3.
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
36
540
|
## 0.5.0 → 0.6.0
|
|
37
541
|
|
|
38
542
|
### 1. Rule S1: no heading or float title runs past 65 characters
|
|
@@ -215,6 +719,16 @@ abbreviation needs its remark plugin wired in too:
|
|
|
215
719
|
]
|
|
216
720
|
```
|
|
217
721
|
|
|
722
|
+
Skipping this second half is now **build-enforced**, not just documented:
|
|
723
|
+
`explicoContentRefresh()`'s `astro:config:setup` hook checks
|
|
724
|
+
`markdown.remarkPlugins` against the manifest and throws if a catalogued
|
|
725
|
+
manifest table (`manifest.abbreviations`, `manifest.sources`, or
|
|
726
|
+
`manifest.notation.raw`) has no matching plugin (`remarkAbbreviations`,
|
|
727
|
+
`remarkCitation`, `remarkNotation` respectively) registered — so a
|
|
728
|
+
half-completed migration like this one fails `astro build`/`astro dev`
|
|
729
|
+
instead of silently rendering plain text with `pnpm validate:content` still
|
|
730
|
+
green.
|
|
731
|
+
|
|
218
732
|
### 5. Optional: rule N10 warns on an unexplained `\mathrm{…}` label
|
|
219
733
|
|
|
220
734
|
A `\mathrm{…}` multi-letter label (`\mathrm{KE}`, `\mathrm{PV}`) not on the
|