explico 0.7.0 → 0.11.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.
Files changed (236) hide show
  1. package/CHANGELOG.md +1409 -1
  2. package/README.md +60 -15
  3. package/dist/compiler/astro.d.ts +6 -1
  4. package/dist/compiler/cli.d.ts +54 -3
  5. package/dist/compiler/cli.js +80 -6
  6. package/dist/compiler/collections.d.ts +35 -2
  7. package/dist/compiler/collections.js +84 -8
  8. package/dist/compiler/course-config.d.ts +3 -194
  9. package/dist/compiler/course-config.js +78 -5
  10. package/dist/compiler/exports/standalone-html.d.ts +6 -1
  11. package/dist/compiler/knowledge-version.js +1 -1
  12. package/dist/compiler/lesson-derivation.d.ts +27 -10
  13. package/dist/compiler/lesson-derivation.js +23 -8
  14. package/dist/compiler/logging.d.ts +14 -1
  15. package/dist/compiler/logging.js +6 -2
  16. package/dist/compiler/manifest.d.ts +204 -31
  17. package/dist/compiler/manifest.js +270 -55
  18. package/dist/compiler/resolution-report.d.ts +6 -1
  19. package/dist/course-config-Dsnri9Tk.d.ts +464 -0
  20. package/dist/reference/base-accents.d.mts +26 -0
  21. package/dist/reference/base-accents.mjs +31 -0
  22. package/dist/reference/base-roman-labels.d.mts +2 -2
  23. package/dist/reference/base-roman-labels.mjs +2 -2
  24. package/dist/reference/consistency.d.ts +14 -2
  25. package/dist/reference/consistency.js +108 -4
  26. package/dist/reference/delimiter-size.d.ts +21 -11
  27. package/dist/reference/delimiter-size.js +15 -39
  28. package/dist/reference/diagrams-validate.d.ts +7 -2
  29. package/dist/reference/diagrams-validate.js +9 -1
  30. package/dist/reference/equations-validate.d.ts +8 -5
  31. package/dist/reference/equations-validate.js +1 -0
  32. package/dist/reference/equations.d.mts +69 -34
  33. package/dist/reference/equations.mjs +90 -44
  34. package/dist/reference/examples-validate.d.ts +31 -0
  35. package/dist/reference/examples-validate.js +48 -0
  36. package/dist/reference/figures-validate.d.ts +1 -1
  37. package/dist/reference/figures-validate.js +4 -1
  38. package/dist/reference/folds-validate.d.ts +33 -0
  39. package/dist/reference/folds-validate.js +32 -0
  40. package/dist/reference/gate-abbreviations.d.ts +3 -1
  41. package/dist/reference/gate-abbreviations.js +3 -2
  42. package/dist/reference/gate-course-rules.d.ts +32 -0
  43. package/dist/reference/gate-course-rules.js +85 -0
  44. package/dist/reference/gate-heading-length.d.ts +5 -2
  45. package/dist/reference/gate-heading-length.js +47 -23
  46. package/dist/reference/gate-heading-structure.d.ts +41 -0
  47. package/dist/reference/gate-heading-structure.js +113 -0
  48. package/dist/reference/gate-math-punctuation.d.ts +71 -0
  49. package/dist/reference/gate-math-punctuation.js +251 -0
  50. package/dist/reference/gate-math.d.ts +44 -6
  51. package/dist/reference/gate-math.js +63 -10
  52. package/dist/reference/gate-part-pages.d.ts +50 -0
  53. package/dist/reference/gate-part-pages.js +118 -0
  54. package/dist/reference/gate-prose-notation.d.ts +32 -11
  55. package/dist/reference/gate-prose-notation.js +30 -8
  56. package/dist/reference/katex-delimiters.d.mts +15 -0
  57. package/dist/reference/katex-delimiters.mjs +138 -0
  58. package/dist/reference/katex-options.mjs +4 -0
  59. package/dist/reference/keyed-float-validate.d.ts +27 -10
  60. package/dist/reference/keyed-float-validate.js +15 -1
  61. package/dist/reference/keyed-jsx-floats.d.mts +11 -5
  62. package/dist/reference/keyed-jsx-floats.mjs +73 -20
  63. package/dist/reference/knowledge-checks-validate.d.ts +1 -1
  64. package/dist/reference/knowledge-checks.d.mts +3 -1
  65. package/dist/reference/knowledge-checks.mjs +9 -4
  66. package/dist/reference/lab-math-scope.d.ts +1 -0
  67. package/dist/reference/lab-math-slot.d.ts +34 -0
  68. package/dist/reference/lab-math-slot.js +6 -0
  69. package/dist/reference/math-glyphs.d.mts +80 -4
  70. package/dist/reference/math-glyphs.mjs +588 -39
  71. package/dist/reference/page-notation.d.ts +6 -1
  72. package/dist/reference/raw-floats-validate.js +1 -1
  73. package/dist/reference/raw-floats.mjs +1 -1
  74. package/dist/reference/rehype-heading-anchors.d.mts +14 -0
  75. package/dist/reference/rehype-heading-anchors.mjs +116 -17
  76. package/dist/reference/rehype-table-header-labels.d.mts +6 -1
  77. package/dist/reference/rehype-table-header-labels.mjs +21 -3
  78. package/dist/reference/remark-asides.d.mts +3 -0
  79. package/dist/reference/remark-asides.mjs +180 -0
  80. package/dist/reference/remark-memo.d.mts +3 -1
  81. package/dist/reference/remark-memo.mjs +42 -11
  82. package/dist/reference/remark-notation.d.mts +60 -10
  83. package/dist/reference/remark-notation.mjs +387 -36
  84. package/dist/reference/render-lab-math.d.ts +4 -26
  85. package/dist/reference/render-lab-math.js +5 -5
  86. package/dist/reference/sections-validate.d.ts +27 -0
  87. package/dist/reference/sections-validate.js +41 -0
  88. package/dist/reference/sections.d.mts +97 -0
  89. package/dist/reference/sections.mjs +306 -0
  90. package/dist/reference/tables-validate.d.ts +1 -1
  91. package/dist/reference/types.d.ts +24 -1
  92. package/dist/reference/unit-words.d.ts +37 -0
  93. package/dist/reference/unit-words.js +170 -0
  94. package/dist/rules/catalog.d.ts +176 -0
  95. package/dist/rules/catalog.js +983 -0
  96. package/dist/rules/course-rules.d.ts +115 -0
  97. package/dist/rules/course-rules.js +292 -0
  98. package/dist/rules/course-rules.schema.json +138 -0
  99. package/dist/rules/in-effect.d.ts +53 -0
  100. package/dist/rules/in-effect.js +142 -0
  101. package/dist/rules/rules.schema.json +1072 -0
  102. package/dist/rules/settings.d.ts +3 -0
  103. package/dist/rules/settings.js +290 -0
  104. package/dist/rules/waivers.d.ts +53 -0
  105. package/dist/rules/waivers.js +132 -0
  106. package/dist/session/PreferenceStore.d.ts +5 -0
  107. package/dist/session/PreferenceStore.js +9 -0
  108. package/docs/VERSIONING.md +2 -2
  109. package/docs/authoring/README.md +232 -40
  110. package/docs/authoring/agents.md +55 -9
  111. package/docs/authoring/components.md +178 -22
  112. package/docs/authoring/migrating.md +1324 -2
  113. package/docs/authoring/notation.md +616 -344
  114. package/docs/authoring/prose.md +551 -0
  115. package/docs/authoring/retired.md +35 -0
  116. package/docs/authoring/structure-rules.md +422 -40
  117. package/docs/authoring/structure.md +445 -62
  118. package/docs/authoring/versioning.md +20 -28
  119. package/docs/authoring/visualizations.md +142 -20
  120. package/docs/katex-bracket-scaling.md +191 -0
  121. package/package.json +3 -2
  122. package/src/compiler/cli.ts +139 -6
  123. package/src/compiler/collections.ts +144 -10
  124. package/src/compiler/course-config.ts +273 -34
  125. package/src/compiler/knowledge-version.ts +1 -1
  126. package/src/compiler/lesson-derivation.ts +54 -15
  127. package/src/compiler/logging.ts +21 -4
  128. package/src/compiler/manifest.ts +573 -104
  129. package/src/components/BlockHeading.astro +113 -0
  130. package/src/components/CourseContents.astro +221 -0
  131. package/src/components/CurriculumMap.astro +5 -6
  132. package/src/components/FloatIndex.astro +200 -0
  133. package/src/components/HoverPanel.astro +431 -79
  134. package/src/components/PartBridge.astro +27 -0
  135. package/src/components/PartOverview.astro +401 -0
  136. package/src/components/PartScope.astro +27 -0
  137. package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
  138. package/src/components/assessments/AssessmentRunner.tsx +8 -5
  139. package/src/components/assessments/AssessmentSet.astro +23 -26
  140. package/src/components/block-heading.ts +146 -0
  141. package/src/components/card-arrow.ts +243 -0
  142. package/src/components/card-drag.ts +631 -0
  143. package/src/components/card-jump.ts +45 -0
  144. package/src/components/card-manager.ts +1589 -0
  145. package/src/components/card-memory.ts +177 -0
  146. package/src/components/card-placement.ts +504 -0
  147. package/src/components/card-side.ts +336 -0
  148. package/src/components/card-travel.ts +197 -0
  149. package/src/components/citation/CitationLayer.astro +77 -76
  150. package/src/components/diagram/Diagram.astro +161 -316
  151. package/src/components/disclosure/course-disclosure.ts +24 -0
  152. package/src/components/disclosure/hover-preview.ts +122 -42
  153. package/src/components/disclosure/persisted-disclosure.ts +3 -3
  154. package/src/components/disclosure/print-as-shown.ts +252 -0
  155. package/src/components/examples/CompactExample.astro +3 -1
  156. package/src/components/examples/CompactExamples.astro +101 -94
  157. package/src/components/figure/Figure.astro +174 -274
  158. package/src/components/figure/FloatCaption.astro +87 -0
  159. package/src/components/figure/figure-state.ts +58 -0
  160. package/src/components/figure/figure-tools.ts +87 -0
  161. package/src/components/float-name.ts +101 -0
  162. package/src/components/fold/Fold.astro +125 -0
  163. package/src/components/fold/fold-id.ts +40 -0
  164. package/src/components/memo/Memo.astro +162 -231
  165. package/src/components/memo/ShortNote.astro +6 -6
  166. package/src/components/notation/NotationFormula.astro +5 -1
  167. package/src/components/notation/NotationGlossary.astro +24 -14
  168. package/src/components/notation/NotationLayer.astro +169 -162
  169. package/src/components/notation/NotationMath.astro +10 -1
  170. package/src/components/notation/render-notation-math.ts +111 -10
  171. package/src/components/reference/FloatRefLayer.astro +485 -423
  172. package/src/components/starlight/AboutPanel.astro +22 -6
  173. package/src/components/starlight/CollapsibleSections.astro +207 -93
  174. package/src/components/starlight/DiagramEnhancer.astro +15 -138
  175. package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
  176. package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
  177. package/src/components/starlight/LayoutHeader.astro +298 -19
  178. package/src/components/starlight/LayoutPageSidebar.astro +99 -12
  179. package/src/components/starlight/LayoutPageTitle.astro +120 -0
  180. package/src/components/starlight/LayoutSidebar.astro +229 -11
  181. package/src/components/starlight/LessonExportActions.astro +53 -72
  182. package/src/components/starlight/LessonFooter.astro +26 -4
  183. package/src/components/starlight/section-parts.ts +15 -2
  184. package/src/components/starlight/section-summary.ts +181 -0
  185. package/src/components/table/Table.astro +95 -76
  186. package/src/components/table/TableOverflowExpander.astro +65 -28
  187. package/src/content-config.ts +40 -4
  188. package/src/reference/base-accents.mjs +31 -0
  189. package/src/reference/base-roman-labels.mjs +2 -2
  190. package/src/reference/consistency.ts +176 -5
  191. package/src/reference/delimiter-size.ts +40 -61
  192. package/src/reference/diagrams-validate.ts +17 -1
  193. package/src/reference/equations-validate.ts +10 -5
  194. package/src/reference/equations.mjs +90 -44
  195. package/src/reference/examples-validate.ts +97 -0
  196. package/src/reference/figures-validate.ts +6 -1
  197. package/src/reference/folds-validate.ts +65 -0
  198. package/src/reference/gate-abbreviations.ts +3 -2
  199. package/src/reference/gate-course-rules.ts +134 -0
  200. package/src/reference/gate-heading-length.ts +68 -37
  201. package/src/reference/gate-heading-structure.ts +193 -0
  202. package/src/reference/gate-math-punctuation.ts +381 -0
  203. package/src/reference/gate-math.ts +119 -12
  204. package/src/reference/gate-part-pages.ts +217 -0
  205. package/src/reference/gate-prose-notation.ts +74 -13
  206. package/src/reference/katex-delimiters.mjs +138 -0
  207. package/src/reference/katex-options.mjs +4 -0
  208. package/src/reference/keyed-float-validate.ts +45 -11
  209. package/src/reference/keyed-jsx-floats.mjs +73 -20
  210. package/src/reference/knowledge-checks-validate.ts +1 -1
  211. package/src/reference/knowledge-checks.mjs +9 -4
  212. package/src/reference/lab-math-slot.ts +36 -0
  213. package/src/reference/math-glyphs.mjs +588 -39
  214. package/src/reference/raw-floats-validate.ts +1 -1
  215. package/src/reference/raw-floats.mjs +1 -1
  216. package/src/reference/rehype-heading-anchors.mjs +116 -17
  217. package/src/reference/rehype-table-header-labels.mjs +21 -3
  218. package/src/reference/remark-asides.mjs +180 -0
  219. package/src/reference/remark-memo.mjs +42 -11
  220. package/src/reference/remark-notation.mjs +387 -36
  221. package/src/reference/render-lab-math.ts +17 -32
  222. package/src/reference/sections-validate.ts +81 -0
  223. package/src/reference/sections.mjs +306 -0
  224. package/src/reference/tables-validate.ts +2 -1
  225. package/src/reference/types.ts +24 -0
  226. package/src/reference/unit-words.ts +233 -0
  227. package/src/rules/catalog.ts +1298 -0
  228. package/src/rules/course-rules.ts +456 -0
  229. package/src/rules/in-effect.ts +235 -0
  230. package/src/rules/settings.ts +448 -0
  231. package/src/rules/waivers.ts +249 -0
  232. package/src/session/PreferenceStore.ts +15 -0
  233. package/src/styles/global.css +1471 -163
  234. package/src/styles/surfaces.css +182 -0
  235. package/src/components/hover-panel.ts +0 -339
  236. package/src/components/popup-stack.ts +0 -345
@@ -1,5 +1,8 @@
1
1
  import rehypeKatex from 'rehype-katex';
2
- import { createNotationKatexOptions } from '../../reference/katex-options.mjs';
2
+ import {
3
+ createNotationKatexOptions,
4
+ trustNotationMarker,
5
+ } from '../../reference/katex-options.mjs';
3
6
  import { NOTATION_KEY_PATTERN } from '../../reference/remark-notation.mjs';
4
7
  import {
5
8
  GlyphResolutionError,
@@ -81,32 +84,96 @@ const allowedTags = new Set([
81
84
  'line',
82
85
  ]);
83
86
 
87
+ /**
88
+ * Every inert presentation attribute KaTeX's MathML builder can set, sorted.
89
+ *
90
+ * This list is deliberately KaTeX's whole surface rather than the attributes
91
+ * the corpus happens to have hit: anything missing here is a hard build error
92
+ * on valid, ordinary math, and the author has no way to work around it. `\Bigl`
93
+ * (`minsize`/`maxsize`), `\boxed` (`notation`), and `\colorbox`
94
+ * (`voffset`/`mathbackground`) each used to fail that way.
95
+ * `tests/notation/render-notation-math.test.ts` scans KaTeX's own
96
+ * `setAttribute` calls and fails when a release adds a name that is in neither
97
+ * this set nor {@link deniedAttributeNames}, so a KaTeX upgrade cannot quietly
98
+ * reintroduce the gap.
99
+ */
84
100
  const simpleAttributeNames = new Set([
85
101
  'accent',
86
102
  'accentunder',
87
103
  'columnalign',
104
+ 'columnlines',
88
105
  'columnspacing',
106
+ 'depth',
107
+ 'display',
89
108
  'displaystyle',
90
109
  'fence',
91
110
  'height',
111
+ 'largeop',
112
+ 'linebreak',
113
+ 'linethickness',
92
114
  'lspace',
115
+ 'mathbackground',
116
+ 'mathcolor',
117
+ 'mathsize',
93
118
  'mathvariant',
119
+ 'maxsize',
120
+ 'minsize',
121
+ 'notation',
94
122
  'preserveaspectratio',
123
+ 'rowlines',
95
124
  'rowspacing',
96
125
  'rspace',
97
126
  'scriptlevel',
98
127
  'separator',
99
128
  'stretchy',
129
+ 'valign',
100
130
  'viewbox',
131
+ 'voffset',
101
132
  'width',
102
133
  ]);
103
134
 
104
- const safeAttributeValue = /^[ A-Za-z0-9+.,()\-/%]*$/;
135
+ /**
136
+ * The attributes KaTeX can set that must never reach the page, each one a
137
+ * navigation or external-resource target: `href` (`\href`), `src`/`alt`
138
+ * (`\includegraphics`), and `title` (`\htmlTitle`). Every command that
139
+ * produces one already needs KaTeX's `trust` callback and is refused earlier by
140
+ * {@link unsafeExtensionCommand}, so this set is the second line — and the
141
+ * reason the completeness scan above can tell "KaTeX added an attribute nobody
142
+ * classified" apart from "we decided against this one".
143
+ */
144
+ const deniedAttributeNames = new Set(['alt', 'href', 'src', 'title']);
145
+
146
+ // `#` is here for `mathcolor` / `mathbackground` / a `background-color:` style,
147
+ // which KaTeX writes as a hex literal. No attribute reaching this point can
148
+ // carry a URL — `href` and `src` are denied above — so it opens no target.
149
+ const safeAttributeValue = /^[ A-Za-z0-9+.,()\-/%#]*$/;
105
150
  const safeClassName = /^[A-Za-z0-9_-]+$/;
106
- const safeStyle = /^(?:[a-z-]+:[ A-Za-z0-9+.,()\-/%]*;)*$/;
151
+ const safeDeclaration = /^\s*[a-z-]+:[ A-Za-z0-9+.,()\-/%#]*$/;
107
152
  const safePathData = /^[\sA-Za-z0-9+.,\-]*$/;
108
153
  const unsafeExtensionCommand =
109
154
  /\\(?:href|url|includegraphics|htmlClass|htmlData|htmlId|htmlStyle)\b/;
155
+ // `\explain{key}{latex}` and `\slot{name}{latex}`, the two macros that expand
156
+ // to a trusted `\htmlData` marker. Only the first argument is captured.
157
+ const MARKER_MACRO = /\\(explain|slot)\{([^{}]*)\}/g;
158
+
159
+ /**
160
+ * A declaration list KaTeX generated: inert properties only, and no
161
+ * `url(...)`/`expression(...)` to fetch or evaluate anything.
162
+ *
163
+ * Validated per declaration rather than with one regex over the whole string,
164
+ * because KaTeX does not always terminate the last one — `\vec` emits
165
+ * `style="width:0.471em"` with no trailing `;`, which a
166
+ * `(?:declaration;)*`-shaped pattern rejects outright.
167
+ */
168
+ function isSafeStyle(value: string): boolean {
169
+ if (/(?:expression|url)\s*\(/i.test(value)) return false;
170
+ return value
171
+ .split(';')
172
+ .every(
173
+ (declaration) =>
174
+ declaration.trim().length === 0 || safeDeclaration.test(declaration),
175
+ );
176
+ }
110
177
 
111
178
  function attributeValue(value: unknown, propertyName: string): string {
112
179
  if (typeof value === 'boolean') return String(value);
@@ -170,22 +237,27 @@ function safeProperties(
170
237
  continue;
171
238
  }
172
239
 
173
- if (
174
- name === 'style' &&
175
- typeof value === 'string' &&
176
- safeStyle.test(value) &&
177
- !/(?:expression|url)\s*\(/i.test(value)
178
- ) {
240
+ if (name === 'style') {
241
+ if (typeof value !== 'string' || !isSafeStyle(value)) {
242
+ throw new Error('Unsafe KaTeX style value.');
243
+ }
179
244
  properties.style = value;
180
245
  continue;
181
246
  }
182
247
 
183
- if (name === 'd' && typeof value === 'string' && safePathData.test(value)) {
248
+ if (name === 'd') {
249
+ if (typeof value !== 'string' || !safePathData.test(value)) {
250
+ throw new Error('Unsafe KaTeX path data.');
251
+ }
184
252
  properties.d = value;
185
253
  continue;
186
254
  }
187
255
 
188
256
  const normalizedName = name.toLowerCase();
257
+ if (deniedAttributeNames.has(normalizedName)) {
258
+ throw new Error(`Disallowed KaTeX property: ${name}.`);
259
+ }
260
+
189
261
  if (simpleAttributeNames.has(normalizedName)) {
190
262
  const outputName =
191
263
  normalizedName === 'viewbox'
@@ -228,6 +300,34 @@ function sanitizeNode(node: HastNode): SafeMathNode {
228
300
  // this module already imports from `remark-notation.mjs`.
229
301
  export { stripNotationMarkers };
230
302
 
303
+ /**
304
+ * Refuse a marker argument the trust callback would reject, before KaTeX sees
305
+ * it.
306
+ *
307
+ * KaTeX does not treat a denied `trust` as a parse error: it renders the
308
+ * command name in `errorColor` and carries on, so `\explain{Not A Key}{\Omega}`
309
+ * would otherwise reach a reader as red `\htmlData` text with the build still
310
+ * green. `\htmlData` itself is already refused by {@link
311
+ * unsafeExtensionCommand}, so the two marker macros are the only way into that
312
+ * callback and this check covers all of them. It asks
313
+ * {@link trustNotationMarker} rather than re-deriving the key patterns, so the
314
+ * answer here cannot drift from the answer KaTeX gets.
315
+ */
316
+ function assertTrustedMarkers(latex: string): void {
317
+ for (const [, macro, argument] of latex.matchAll(MARKER_MACRO)) {
318
+ const attribute =
319
+ macro === 'explain' ? 'data-notation-key' : 'data-lab-slot';
320
+ if (
321
+ !trustNotationMarker({
322
+ command: '\\htmlData',
323
+ attributes: { [attribute]: argument },
324
+ })
325
+ ) {
326
+ throw new Error(`Notation LaTeX has an invalid \\${macro} key: ${argument}`);
327
+ }
328
+ }
329
+ }
330
+
231
331
  /**
232
332
  * Render repository-authored LaTeX through the same build-time KaTeX adapter
233
333
  * as lesson math, then expose a constrained structured tree to Astro. No HTML
@@ -240,6 +340,7 @@ export function renderNotationMath(latex: string): readonly SafeMathNode[] {
240
340
  if (unsafeExtensionCommand.test(latex)) {
241
341
  throw new Error('Notation LaTeX cannot use a trust-requiring extension.');
242
342
  }
343
+ assertTrustedMarkers(latex);
243
344
 
244
345
  const root: HastRoot = {
245
346
  type: 'root',