explico 0.8.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 (230) hide show
  1. package/CHANGELOG.md +1239 -1
  2. package/README.md +60 -15
  3. package/dist/compiler/astro.d.ts +6 -1
  4. package/dist/compiler/cli.d.ts +46 -2
  5. package/dist/compiler/cli.js +70 -4
  6. package/dist/compiler/collections.d.ts +35 -2
  7. package/dist/compiler/collections.js +68 -5
  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 +4 -1
  15. package/dist/compiler/logging.js +4 -1
  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 +3 -2
  27. package/dist/reference/diagrams-validate.d.ts +7 -2
  28. package/dist/reference/diagrams-validate.js +9 -1
  29. package/dist/reference/equations-validate.d.ts +8 -5
  30. package/dist/reference/equations-validate.js +1 -0
  31. package/dist/reference/equations.d.mts +60 -31
  32. package/dist/reference/equations.mjs +83 -43
  33. package/dist/reference/examples-validate.d.ts +31 -0
  34. package/dist/reference/examples-validate.js +48 -0
  35. package/dist/reference/figures-validate.d.ts +1 -1
  36. package/dist/reference/figures-validate.js +4 -1
  37. package/dist/reference/folds-validate.d.ts +33 -0
  38. package/dist/reference/folds-validate.js +32 -0
  39. package/dist/reference/gate-abbreviations.d.ts +3 -1
  40. package/dist/reference/gate-abbreviations.js +1 -0
  41. package/dist/reference/gate-course-rules.d.ts +32 -0
  42. package/dist/reference/gate-course-rules.js +85 -0
  43. package/dist/reference/gate-heading-length.d.ts +5 -2
  44. package/dist/reference/gate-heading-length.js +45 -21
  45. package/dist/reference/gate-heading-structure.d.ts +41 -0
  46. package/dist/reference/gate-heading-structure.js +113 -0
  47. package/dist/reference/gate-math-punctuation.d.ts +71 -0
  48. package/dist/reference/gate-math-punctuation.js +251 -0
  49. package/dist/reference/gate-math.d.ts +22 -6
  50. package/dist/reference/gate-math.js +42 -8
  51. package/dist/reference/gate-part-pages.d.ts +50 -0
  52. package/dist/reference/gate-part-pages.js +118 -0
  53. package/dist/reference/gate-prose-notation.d.ts +21 -11
  54. package/dist/reference/gate-prose-notation.js +25 -7
  55. package/dist/reference/katex-delimiters.mjs +20 -7
  56. package/dist/reference/keyed-float-validate.d.ts +27 -10
  57. package/dist/reference/keyed-float-validate.js +15 -1
  58. package/dist/reference/keyed-jsx-floats.d.mts +11 -5
  59. package/dist/reference/keyed-jsx-floats.mjs +73 -20
  60. package/dist/reference/knowledge-checks-validate.d.ts +1 -1
  61. package/dist/reference/knowledge-checks.d.mts +3 -1
  62. package/dist/reference/knowledge-checks.mjs +9 -4
  63. package/dist/reference/lab-math-scope.d.ts +1 -0
  64. package/dist/reference/lab-math-slot.d.ts +34 -0
  65. package/dist/reference/lab-math-slot.js +6 -0
  66. package/dist/reference/math-glyphs.d.mts +80 -4
  67. package/dist/reference/math-glyphs.mjs +572 -37
  68. package/dist/reference/page-notation.d.ts +6 -1
  69. package/dist/reference/raw-floats-validate.js +1 -1
  70. package/dist/reference/raw-floats.mjs +1 -1
  71. package/dist/reference/rehype-heading-anchors.d.mts +14 -0
  72. package/dist/reference/rehype-heading-anchors.mjs +116 -17
  73. package/dist/reference/rehype-table-header-labels.d.mts +6 -1
  74. package/dist/reference/rehype-table-header-labels.mjs +21 -3
  75. package/dist/reference/remark-asides.d.mts +3 -0
  76. package/dist/reference/remark-asides.mjs +180 -0
  77. package/dist/reference/remark-memo.d.mts +3 -1
  78. package/dist/reference/remark-memo.mjs +42 -11
  79. package/dist/reference/remark-notation.d.mts +60 -10
  80. package/dist/reference/remark-notation.mjs +387 -36
  81. package/dist/reference/render-lab-math.d.ts +4 -26
  82. package/dist/reference/render-lab-math.js +4 -4
  83. package/dist/reference/sections-validate.d.ts +27 -0
  84. package/dist/reference/sections-validate.js +41 -0
  85. package/dist/reference/sections.d.mts +97 -0
  86. package/dist/reference/sections.mjs +306 -0
  87. package/dist/reference/tables-validate.d.ts +1 -1
  88. package/dist/reference/types.d.ts +17 -1
  89. package/dist/reference/unit-words.d.ts +37 -0
  90. package/dist/reference/unit-words.js +170 -0
  91. package/dist/rules/catalog.d.ts +176 -0
  92. package/dist/rules/catalog.js +983 -0
  93. package/dist/rules/course-rules.d.ts +115 -0
  94. package/dist/rules/course-rules.js +292 -0
  95. package/dist/rules/course-rules.schema.json +138 -0
  96. package/dist/rules/in-effect.d.ts +53 -0
  97. package/dist/rules/in-effect.js +142 -0
  98. package/dist/rules/rules.schema.json +1072 -0
  99. package/dist/rules/settings.d.ts +3 -0
  100. package/dist/rules/settings.js +290 -0
  101. package/dist/rules/waivers.d.ts +53 -0
  102. package/dist/rules/waivers.js +132 -0
  103. package/dist/session/PreferenceStore.d.ts +5 -0
  104. package/dist/session/PreferenceStore.js +9 -0
  105. package/docs/VERSIONING.md +2 -2
  106. package/docs/authoring/README.md +232 -40
  107. package/docs/authoring/agents.md +55 -9
  108. package/docs/authoring/components.md +178 -22
  109. package/docs/authoring/migrating.md +1096 -2
  110. package/docs/authoring/notation.md +576 -322
  111. package/docs/authoring/prose.md +551 -0
  112. package/docs/authoring/retired.md +35 -0
  113. package/docs/authoring/structure-rules.md +422 -40
  114. package/docs/authoring/structure.md +445 -62
  115. package/docs/authoring/versioning.md +20 -28
  116. package/docs/authoring/visualizations.md +142 -20
  117. package/package.json +2 -2
  118. package/src/compiler/cli.ts +116 -6
  119. package/src/compiler/collections.ts +111 -7
  120. package/src/compiler/course-config.ts +273 -34
  121. package/src/compiler/knowledge-version.ts +1 -1
  122. package/src/compiler/lesson-derivation.ts +54 -15
  123. package/src/compiler/logging.ts +8 -2
  124. package/src/compiler/manifest.ts +573 -104
  125. package/src/components/BlockHeading.astro +113 -0
  126. package/src/components/CourseContents.astro +221 -0
  127. package/src/components/CurriculumMap.astro +5 -6
  128. package/src/components/FloatIndex.astro +200 -0
  129. package/src/components/HoverPanel.astro +431 -79
  130. package/src/components/PartBridge.astro +27 -0
  131. package/src/components/PartOverview.astro +401 -0
  132. package/src/components/PartScope.astro +27 -0
  133. package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
  134. package/src/components/assessments/AssessmentRunner.tsx +8 -5
  135. package/src/components/assessments/AssessmentSet.astro +23 -26
  136. package/src/components/block-heading.ts +146 -0
  137. package/src/components/card-arrow.ts +243 -0
  138. package/src/components/card-drag.ts +631 -0
  139. package/src/components/card-jump.ts +45 -0
  140. package/src/components/card-manager.ts +1589 -0
  141. package/src/components/card-memory.ts +177 -0
  142. package/src/components/card-placement.ts +504 -0
  143. package/src/components/card-side.ts +336 -0
  144. package/src/components/card-travel.ts +197 -0
  145. package/src/components/citation/CitationLayer.astro +77 -76
  146. package/src/components/diagram/Diagram.astro +161 -316
  147. package/src/components/disclosure/course-disclosure.ts +24 -0
  148. package/src/components/disclosure/hover-preview.ts +122 -42
  149. package/src/components/disclosure/persisted-disclosure.ts +3 -3
  150. package/src/components/disclosure/print-as-shown.ts +252 -0
  151. package/src/components/examples/CompactExample.astro +3 -1
  152. package/src/components/examples/CompactExamples.astro +101 -94
  153. package/src/components/figure/Figure.astro +174 -274
  154. package/src/components/figure/FloatCaption.astro +87 -0
  155. package/src/components/figure/figure-state.ts +58 -0
  156. package/src/components/figure/figure-tools.ts +87 -0
  157. package/src/components/float-name.ts +101 -0
  158. package/src/components/fold/Fold.astro +125 -0
  159. package/src/components/fold/fold-id.ts +40 -0
  160. package/src/components/memo/Memo.astro +162 -231
  161. package/src/components/memo/ShortNote.astro +6 -6
  162. package/src/components/notation/NotationFormula.astro +5 -1
  163. package/src/components/notation/NotationGlossary.astro +3 -4
  164. package/src/components/notation/NotationLayer.astro +169 -162
  165. package/src/components/notation/NotationMath.astro +10 -1
  166. package/src/components/reference/FloatRefLayer.astro +485 -423
  167. package/src/components/starlight/AboutPanel.astro +5 -4
  168. package/src/components/starlight/CollapsibleSections.astro +207 -93
  169. package/src/components/starlight/DiagramEnhancer.astro +15 -138
  170. package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
  171. package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
  172. package/src/components/starlight/LayoutHeader.astro +298 -19
  173. package/src/components/starlight/LayoutPageSidebar.astro +99 -12
  174. package/src/components/starlight/LayoutPageTitle.astro +120 -0
  175. package/src/components/starlight/LayoutSidebar.astro +229 -11
  176. package/src/components/starlight/LessonExportActions.astro +53 -72
  177. package/src/components/starlight/LessonFooter.astro +26 -4
  178. package/src/components/starlight/section-parts.ts +15 -2
  179. package/src/components/starlight/section-summary.ts +181 -0
  180. package/src/components/table/Table.astro +95 -76
  181. package/src/components/table/TableOverflowExpander.astro +65 -28
  182. package/src/content-config.ts +40 -4
  183. package/src/reference/base-accents.mjs +31 -0
  184. package/src/reference/base-roman-labels.mjs +2 -2
  185. package/src/reference/consistency.ts +176 -5
  186. package/src/reference/delimiter-size.ts +3 -2
  187. package/src/reference/diagrams-validate.ts +17 -1
  188. package/src/reference/equations-validate.ts +10 -5
  189. package/src/reference/equations.mjs +83 -43
  190. package/src/reference/examples-validate.ts +97 -0
  191. package/src/reference/figures-validate.ts +6 -1
  192. package/src/reference/folds-validate.ts +65 -0
  193. package/src/reference/gate-abbreviations.ts +1 -0
  194. package/src/reference/gate-course-rules.ts +134 -0
  195. package/src/reference/gate-heading-length.ts +66 -35
  196. package/src/reference/gate-heading-structure.ts +193 -0
  197. package/src/reference/gate-math-punctuation.ts +381 -0
  198. package/src/reference/gate-math.ts +69 -10
  199. package/src/reference/gate-part-pages.ts +217 -0
  200. package/src/reference/gate-prose-notation.ts +59 -12
  201. package/src/reference/katex-delimiters.mjs +20 -7
  202. package/src/reference/keyed-float-validate.ts +45 -11
  203. package/src/reference/keyed-jsx-floats.mjs +73 -20
  204. package/src/reference/knowledge-checks-validate.ts +1 -1
  205. package/src/reference/knowledge-checks.mjs +9 -4
  206. package/src/reference/lab-math-slot.ts +36 -0
  207. package/src/reference/math-glyphs.mjs +572 -37
  208. package/src/reference/raw-floats-validate.ts +1 -1
  209. package/src/reference/raw-floats.mjs +1 -1
  210. package/src/reference/rehype-heading-anchors.mjs +116 -17
  211. package/src/reference/rehype-table-header-labels.mjs +21 -3
  212. package/src/reference/remark-asides.mjs +180 -0
  213. package/src/reference/remark-memo.mjs +42 -11
  214. package/src/reference/remark-notation.mjs +387 -36
  215. package/src/reference/render-lab-math.ts +16 -31
  216. package/src/reference/sections-validate.ts +81 -0
  217. package/src/reference/sections.mjs +306 -0
  218. package/src/reference/tables-validate.ts +2 -1
  219. package/src/reference/types.ts +17 -0
  220. package/src/reference/unit-words.ts +233 -0
  221. package/src/rules/catalog.ts +1298 -0
  222. package/src/rules/course-rules.ts +456 -0
  223. package/src/rules/in-effect.ts +235 -0
  224. package/src/rules/settings.ts +448 -0
  225. package/src/rules/waivers.ts +249 -0
  226. package/src/session/PreferenceStore.ts +15 -0
  227. package/src/styles/global.css +1471 -163
  228. package/src/styles/surfaces.css +182 -0
  229. package/src/components/hover-panel.ts +0 -339
  230. package/src/components/popup-stack.ts +0 -345
@@ -30,6 +30,10 @@ import {
30
30
  import {
31
31
  validateDiagrams
32
32
  } from "../reference/diagrams-validate.js";
33
+ import {
34
+ validateExamples
35
+ } from "../reference/examples-validate.js";
36
+ import { validateFolds } from "../reference/folds-validate.js";
33
37
  import {
34
38
  validateKnowledgeChecks
35
39
  } from "../reference/knowledge-checks-validate.js";
@@ -44,8 +48,21 @@ import {
44
48
  gateProseNotation,
45
49
  gateProseNotationInAssessments
46
50
  } from "../reference/gate-prose-notation.js";
51
+ import {
52
+ gateMathPunctuation,
53
+ gateMathPunctuationInAssessments
54
+ } from "../reference/gate-math-punctuation.js";
47
55
  import { gateAbbreviations } from "../reference/gate-abbreviations.js";
56
+ import { gateCourseRules } from "../reference/gate-course-rules.js";
48
57
  import { gateHeadingLength } from "../reference/gate-heading-length.js";
58
+ import { gateHeadingStructure } from "../reference/gate-heading-structure.js";
59
+ import { gatePartPages } from "../reference/gate-part-pages.js";
60
+ import {
61
+ scanSectionHeadings,
62
+ scanTitledBlocks
63
+ } from "../reference/sections.mjs";
64
+ import { knowledgeCheckAnchorId } from "../reference/knowledge-checks.mjs";
65
+ import { validateSectionRefs } from "../reference/sections-validate.js";
49
66
  import {
50
67
  splitMixedContent
51
68
  } from "../reference/mixed-content.js";
@@ -55,9 +72,22 @@ import { formulaGlyphScope } from "../reference/gloss.js";
55
72
  import { resolveReferenceId } from "../reference/references.js";
56
73
  import {
57
74
  coursePartsOf,
75
+ normalizeBlockLabels,
58
76
  normalizeLessonExports,
59
- normalizeDisclosureDefaults
77
+ normalizeDisclosure,
78
+ normalizeNumbering
60
79
  } from "./course-config.js";
80
+ import {
81
+ disabledCodes,
82
+ dropDisabled,
83
+ partPageLimits,
84
+ resolveRules,
85
+ rulesSnapshot
86
+ } from "../rules/settings.js";
87
+ import {
88
+ applyWaivers,
89
+ collectWaivers
90
+ } from "../rules/waivers.js";
61
91
  import {
62
92
  resolveKnowledgeVersion
63
93
  } from "./knowledge-version.js";
@@ -67,6 +97,7 @@ import {
67
97
  loadNotationDefinitions,
68
98
  loadNotationRegistryInput,
69
99
  loadNotationSpecs,
100
+ loadPartOverviews,
70
101
  loadSourceRecords
71
102
  } from "./collections.js";
72
103
  import {
@@ -75,7 +106,7 @@ import {
75
106
  isLessonSlug,
76
107
  lessonIdFromSlug
77
108
  } from "./lesson-derivation.js";
78
- const MANIFEST_SCHEMA_VERSION = 16;
109
+ const MANIFEST_SCHEMA_VERSION = 24;
79
110
  const REPOSITORY_ROOT = process.cwd();
80
111
  const CONTENT_ROOT = join(REPOSITORY_ROOT, "content");
81
112
  const MANIFEST_PATH = join(REPOSITORY_ROOT, "build", "manifest.json");
@@ -178,6 +209,16 @@ function lessonNotationBundle(bundle, definitionsById, resolution, cardsByKey) {
178
209
  resolution: [...resolution]
179
210
  };
180
211
  }
212
+ function studyMinutesRange(value) {
213
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
214
+ return { min: value, max: value };
215
+ }
216
+ if (Array.isArray(value) && value.length === 2 && value.every((entry) => typeof entry === "number" && entry > 0)) {
217
+ const [min, max] = value;
218
+ return min <= max ? { min, max } : { min: max, max: min };
219
+ }
220
+ return void 0;
221
+ }
181
222
  function lessonFrontmatterById() {
182
223
  const base = join(CONTENT_ROOT, "docs");
183
224
  const result = /* @__PURE__ */ new Map();
@@ -193,9 +234,11 @@ function lessonFrontmatterById() {
193
234
  if (!isLessonSlug(slug)) continue;
194
235
  const id = slug.replace(/\.(md|mdx)$/, "").replace(/\//g, ".");
195
236
  const data = parseFrontmatter(readFileSync(path, "utf8")).frontmatter ?? {};
237
+ const studyMinutes = studyMinutesRange(data.studyMinutes);
196
238
  result.set(id, {
197
239
  title: typeof data.title === "string" ? data.title : id,
198
- description: typeof data.description === "string" ? data.description : ""
240
+ description: typeof data.description === "string" ? data.description : "",
241
+ ...studyMinutes === void 0 ? {} : { studyMinutes }
199
242
  });
200
243
  }
201
244
  };
@@ -208,6 +251,10 @@ async function compileManifest(courseConfig) {
208
251
  "course.config.ts is missing a complete `about` block (required since explico 0.3.0): `about: { version, authors: [{ name }], disclaimer, materialName?, summary?, changelogHref? }`. See docs/authoring/migrating.md (\xA7 0.2.x \u2192 0.3.0) in the installed package."
209
252
  );
210
253
  }
254
+ const rules = resolveRules(courseConfig);
255
+ const off = disabledCodes(rules);
256
+ const numberingSettings = normalizeNumbering(courseConfig);
257
+ const blockLabels = normalizeBlockLabels(courseConfig);
211
258
  const [catalog, notationInput, abbreviationsInput] = await Promise.all([
212
259
  loadCurriculumCatalog(),
213
260
  loadNotationRegistryInput(),
@@ -230,6 +277,10 @@ async function compileManifest(courseConfig) {
230
277
  const assessmentsInput = catalog.assessments;
231
278
  const curriculumIssues = validateCurriculum(catalog);
232
279
  const alignmentIssues = validateNotationAlignment(registry, catalog);
280
+ const mathEndAbbreviations = {
281
+ allow: rules.strings("N12", "allow"),
282
+ deny: rules.strings("N12", "deny")
283
+ };
233
284
  const mathIssues = [
234
285
  ...gateContentMath({
235
286
  notationInput,
@@ -239,14 +290,34 @@ async function compileManifest(courseConfig) {
239
290
  assessmentIds: lesson.assessments
240
291
  }))
241
292
  }),
242
- ...gateProseNotation(notationInput.lessons),
243
- ...gateProseNotationInAssessments(assessmentsInput),
244
- ...gateAbbreviations({
293
+ ...rules.isEnabled("N9") ? [
294
+ ...gateProseNotation(notationInput.lessons, {
295
+ allowSpelledUnits: rules.strings("N9", "allow")
296
+ }),
297
+ ...gateProseNotationInAssessments(assessmentsInput, {
298
+ allowSpelledUnits: rules.strings("N9", "allow")
299
+ })
300
+ ] : [],
301
+ ...rules.isEnabled("N12") ? [
302
+ ...gateMathPunctuation(notationInput.lessons, mathEndAbbreviations),
303
+ ...gateMathPunctuationInAssessments(assessmentsInput, mathEndAbbreviations)
304
+ ] : [],
305
+ ...rules.isEnabled("N14") ? gateAbbreviations({
245
306
  notationInput,
246
307
  abbreviations: abbreviationsInput,
247
- courseAbbreviations: courseConfig.abbreviations
308
+ courseAbbreviations: rules.settings("N14")
309
+ }) : [],
310
+ ...rules.isEnabled("S1") ? gateHeadingLength(notationInput.lessons, {
311
+ maxLength: rules.number("S1", "maxLength")
312
+ }) : [],
313
+ ...gateHeadingStructure(notationInput.lessons, {
314
+ levels: rules.isEnabled("S6"),
315
+ adjacency: rules.isEnabled("S7")
248
316
  }),
249
- ...gateHeadingLength(notationInput.lessons)
317
+ // The course's own rules (`courseRules`): one pass for every enabled `X`
318
+ // rule that carries a `forbid` pattern. A disabled one, and a guide rule
319
+ // with no pattern, do no work here.
320
+ ...gateCourseRules(notationInput.lessons, rules.course)
250
321
  ];
251
322
  const notationLessonById = new Map(
252
323
  notationInput.lessons.map((lesson) => [lesson.lessonId, lesson])
@@ -294,15 +365,48 @@ async function compileManifest(courseConfig) {
294
365
  );
295
366
  const frontmatterById = lessonFrontmatterById();
296
367
  const lessonSlugs = [...notationInput.lessons].map((lesson) => lesson.lessonId.replace(/\./g, "/")).sort();
368
+ const configuredParts = coursePartsOf(courseConfig);
369
+ const overviewPages = loadPartOverviews(configuredParts);
370
+ const overviewByDir = new Map(overviewPages.map((page) => [page.dir, page]));
371
+ if (rules.isEnabled("S2")) {
372
+ mathIssues.push(
373
+ ...gatePartPages(
374
+ overviewPages.map((page) => ({
375
+ ...page,
376
+ ordinal: configuredParts.findIndex((part) => part.dir === page.dir) + 1
377
+ })),
378
+ partPageLimits(rules)
379
+ )
380
+ );
381
+ }
382
+ const waiverDiagnostics = [];
383
+ const waiverRules = { courseRules: rules.course };
384
+ const waivers = notationInput.lessons.flatMap((lesson) => {
385
+ const collected = collectWaivers(lesson, waiverRules);
386
+ waiverDiagnostics.push(...collected.diagnostics);
387
+ return collected.waivers;
388
+ });
389
+ const waived = applyWaivers(mathIssues, waivers, waiverRules);
390
+ mathIssues.splice(0, mathIssues.length, ...waived.kept);
391
+ waiverDiagnostics.push(...waived.unused);
297
392
  const sidebar = buildSidebar(
298
393
  catalog.tracks.map((track) => ({ id: track.id, lessons: track.lessons })),
299
394
  lessonSlugs,
300
- coursePartsOf(courseConfig)
395
+ configuredParts.map((part) => ({
396
+ ...part,
397
+ ...overviewByDir.has(part.dir) ? { overviewLink: `/${part.dir}/` } : {}
398
+ })),
399
+ {
400
+ floatIndex: [".mdx", ".md"].some(
401
+ (extension) => existsSync(join(CONTENT_ROOT, "docs", `figures-and-tables${extension}`))
402
+ )
403
+ }
301
404
  );
302
405
  const bodyByLessonId = new Map(
303
406
  notationInput.lessons.map((lesson) => [lesson.lessonId, lesson.body])
304
407
  );
305
408
  const placementByLessonId = /* @__PURE__ */ new Map();
409
+ const chapterScoped = numberingSettings.floats === "chapter";
306
410
  let partCursor = 0;
307
411
  for (const group of sidebar) {
308
412
  const lessonIds = group.items.filter((item) => typeof item === "string").map(lessonIdFromSlug);
@@ -313,23 +417,88 @@ async function compileManifest(courseConfig) {
313
417
  tables: 0,
314
418
  figures: 0,
315
419
  diagrams: 0,
316
- checks: 0
420
+ checks: 0,
421
+ examples: 0
317
422
  };
318
423
  let chapterCursor = 0;
319
424
  for (const lessonId of lessonIds) {
320
425
  const body = bodyByLessonId.get(lessonId) ?? "";
426
+ const chapter = ++chapterCursor;
321
427
  placementByLessonId.set(lessonId, {
322
428
  part: partCursor,
323
- chapter: ++chapterCursor,
324
- numbering: { ...used }
429
+ chapter,
430
+ numbering: chapterScoped ? {
431
+ prefix: `${partCursor}.${chapter}`,
432
+ equations: 0,
433
+ tables: 0,
434
+ figures: 0,
435
+ diagrams: 0,
436
+ checks: 0,
437
+ examples: 0
438
+ } : { prefix: String(partCursor), ...used }
325
439
  });
326
440
  used.equations += countDisplayEquations(body);
327
441
  used.tables += countKeyedJsxFloats(body, { tagName: "Table" });
328
442
  used.figures += countKeyedJsxFloats(body, { tagName: "Figure" });
329
443
  used.diagrams += countKeyedJsxFloats(body, { tagName: "Diagram" });
330
444
  used.checks += lessonMetaById.get(lessonId)?.assessments.length ?? 0;
445
+ used.examples += countKeyedJsxFloats(body, { tagName: "CompactExamples" });
331
446
  }
332
447
  }
448
+ const headingsByLessonId = new Map(
449
+ notationInput.lessons.map((lesson) => {
450
+ const placement = placementByLessonId.get(lesson.lessonId);
451
+ return [
452
+ lesson.lessonId,
453
+ scanSectionHeadings(lesson.body, {
454
+ ...placement ? { prefix: `${placement.part}.${placement.chapter}` } : {},
455
+ depth: numberingSettings.sections.depth
456
+ })
457
+ ];
458
+ })
459
+ );
460
+ mathIssues.push(
461
+ ...validateSectionRefs(
462
+ notationInput.lessons.map((lesson) => ({
463
+ slug: lesson.lessonId.replace(/\./g, "/"),
464
+ file: lesson.source.file,
465
+ body: lesson.body,
466
+ ...lesson.bodyLine === void 0 ? {} : { bodyLine: lesson.bodyLine },
467
+ headingSlugs: (headingsByLessonId.get(lesson.lessonId) ?? []).map(
468
+ (heading) => heading.slug
469
+ )
470
+ }))
471
+ )
472
+ );
473
+ const manifestParts = configuredParts.map((part, index) => {
474
+ const overview = overviewByDir.get(part.dir);
475
+ const lessonIds = [...placementByLessonId].filter(([lessonId]) => lessonId.startsWith(`${part.dir}.`)).sort(([, a], [, b]) => a.chapter - b.chapter).map(([lessonId]) => lessonId);
476
+ const chapterMinutes = lessonIds.map(
477
+ (lessonId) => frontmatterById.get(lessonId)?.studyMinutes
478
+ );
479
+ const studyMinutes = chapterMinutes.length > 0 && chapterMinutes.every((range) => range !== void 0) ? chapterMinutes.reduce(
480
+ (total, range) => ({
481
+ min: total.min + range.min,
482
+ max: total.max + range.max
483
+ }),
484
+ { min: 0, max: 0 }
485
+ ) : void 0;
486
+ return {
487
+ dir: part.dir,
488
+ label: part.label,
489
+ ordinal: index + 1,
490
+ link: `/${part.dir}/`,
491
+ lessons: lessonIds,
492
+ ...studyMinutes === void 0 ? {} : { studyMinutes },
493
+ ...overview ? {
494
+ overview: {
495
+ title: overview.title,
496
+ file: overview.file,
497
+ ...overview.description === void 0 ? {} : { description: overview.description }
498
+ }
499
+ } : {}
500
+ };
501
+ });
333
502
  const floatInputs = (kind) => notationInput.lessons.map((lesson) => {
334
503
  const placement = placementByLessonId.get(lesson.lessonId);
335
504
  return {
@@ -339,40 +508,37 @@ async function compileManifest(courseConfig) {
339
508
  body: lesson.body,
340
509
  ...placement ? {
341
510
  numbering: {
342
- prefix: placement.part,
511
+ prefix: placement.numbering.prefix,
343
512
  offset: placement.numbering[kind]
344
513
  }
345
514
  } : {}
346
515
  };
347
516
  });
517
+ const floatsBySlug = (labels) => {
518
+ const bySlug = /* @__PURE__ */ new Map();
519
+ for (const { slug, key, number, short, caption } of labels) {
520
+ const list = bySlug.get(slug) ?? [];
521
+ list.push({
522
+ key,
523
+ number,
524
+ ...short === void 0 ? {} : { short },
525
+ ...caption === void 0 ? {} : { caption }
526
+ });
527
+ bySlug.set(slug, list);
528
+ }
529
+ return bySlug;
530
+ };
348
531
  const equationValidation = validateEquations(floatInputs("equations"));
349
- const equationsBySlug = new Map(
350
- Object.entries(equationValidation.numbersBySlug).map(([slug, table]) => [
351
- slug,
352
- Object.entries(table).map(([key, number]) => ({ key, number }))
353
- ])
354
- );
532
+ const equationsBySlug = floatsBySlug(equationValidation.labels);
355
533
  const tableValidation = validateTables(floatInputs("tables"));
356
- const tablesBySlug = new Map(
357
- Object.entries(tableValidation.numbersBySlug).map(([slug, table]) => [
358
- slug,
359
- Object.entries(table).map(([key, number]) => ({ key, number }))
360
- ])
361
- );
534
+ const tablesBySlug = floatsBySlug(tableValidation.labels);
362
535
  const figureValidation = validateFigures(floatInputs("figures"));
363
- const figuresBySlug = new Map(
364
- Object.entries(figureValidation.numbersBySlug).map(([slug, table]) => [
365
- slug,
366
- Object.entries(table).map(([key, number]) => ({ key, number }))
367
- ])
368
- );
536
+ const figuresBySlug = floatsBySlug(figureValidation.labels);
369
537
  const diagramValidation = validateDiagrams(floatInputs("diagrams"));
370
- const diagramsBySlug = new Map(
371
- Object.entries(diagramValidation.numbersBySlug).map(([slug, table]) => [
372
- slug,
373
- Object.entries(table).map(([key, number]) => ({ key, number }))
374
- ])
375
- );
538
+ const diagramsBySlug = floatsBySlug(diagramValidation.labels);
539
+ const exampleValidation = validateExamples(floatInputs("examples"));
540
+ const examplesBySlug = floatsBySlug(exampleValidation.labels);
541
+ const foldValidation = validateFolds(floatInputs("figures"));
376
542
  const checkValidation = validateKnowledgeChecks(
377
543
  notationInput.lessons.map((lesson) => {
378
544
  const placement = placementByLessonId.get(lesson.lessonId);
@@ -384,19 +550,49 @@ async function compileManifest(courseConfig) {
384
550
  assessmentIds: lessonMetaById.get(lesson.lessonId)?.assessments ?? [],
385
551
  ...placement ? {
386
552
  numbering: {
387
- prefix: placement.part,
553
+ prefix: placement.numbering.prefix,
388
554
  offset: placement.numbering.checks
389
555
  }
390
556
  } : {}
391
557
  };
392
558
  })
393
559
  );
560
+ const checkTitleById = new Map(
561
+ assessmentsInput.map((assessment) => [assessment.id, assessment.title])
562
+ );
394
563
  const checksBySlug = new Map(
395
564
  Object.entries(checkValidation.numbersBySlug).map(([slug, table]) => [
396
565
  slug,
397
- Object.entries(table).map(([key, number]) => ({ key, number }))
566
+ Object.entries(table).map(([key, number]) => {
567
+ const title = checkTitleById.get(key);
568
+ return { key, number, ...title === void 0 ? {} : { title } };
569
+ })
398
570
  ])
399
571
  );
572
+ const titledBlocksFor = (lessonId) => {
573
+ const slug = lessonId.replace(/\./g, "/");
574
+ const body = bodyByLessonId.get(lessonId) ?? "";
575
+ const headings = headingsByLessonId.get(lessonId) ?? [];
576
+ const checks = checksBySlug.get(slug) ?? [];
577
+ const examples = examplesBySlug.get(slug) ?? [];
578
+ return scanTitledBlocks(body, ["AssessmentSet", "CompactExamples"]).flatMap(
579
+ (block) => {
580
+ const after = headings[block.heading]?.slug;
581
+ const place = after === void 0 ? {} : { after };
582
+ if (block.name === "CompactExamples") {
583
+ const set = examples.find((example) => example.key === block.id);
584
+ return set?.short ? [{ kind: "example", key: set.key, anchor: `ex-${set.key}`, title: set.short, ...place }] : [];
585
+ }
586
+ return checks.filter((check) => block.id === void 0 || check.key === block.id).map((check) => ({
587
+ kind: "check",
588
+ key: check.key,
589
+ anchor: knowledgeCheckAnchorId(check.key),
590
+ title: check.title ?? check.key,
591
+ ...place
592
+ }));
593
+ }
594
+ );
595
+ };
400
596
  const rawFloatDiagnostics = validateRawFloats(
401
597
  notationInput.lessons.map((lesson) => ({
402
598
  lessonId: lesson.lessonId,
@@ -424,27 +620,33 @@ async function compileManifest(courseConfig) {
424
620
  part: placementByLessonId.get(id)?.part ?? 0,
425
621
  chapter: placementByLessonId.get(id)?.chapter ?? 0,
426
622
  numbering: placementByLessonId.get(id)?.numbering ?? {
623
+ prefix: "",
427
624
  equations: 0,
428
625
  tables: 0,
429
626
  figures: 0,
430
627
  diagrams: 0,
431
- checks: 0
628
+ checks: 0,
629
+ examples: 0
432
630
  },
631
+ headings: headingsByLessonId.get(id) ?? [],
433
632
  file: notationLesson.source.file,
434
633
  title: frontmatter.title,
435
634
  description: frontmatter.description,
635
+ ...frontmatter.studyMinutes === void 0 ? {} : { studyMinutes: frontmatter.studyMinutes },
436
636
  status: meta.status,
437
637
  teaches: [...teaches],
438
638
  requires: [...meta.requires],
439
639
  assumptions: [...meta.assumptions],
440
640
  assessments: [...meta.assessments],
441
641
  knowledgeChecks: checksBySlug.get(id.replace(/\./g, "/")) ?? [],
642
+ titledBlocks: titledBlocksFor(id),
442
643
  sources: deriveSources(notationLesson.body),
443
644
  citations: lessonCitations(notationLesson.body),
444
645
  equations: equationsBySlug.get(id.replace(/\./g, "/")) ?? [],
445
646
  tables: tablesBySlug.get(id.replace(/\./g, "/")) ?? [],
446
647
  figures: figuresBySlug.get(id.replace(/\./g, "/")) ?? [],
447
648
  diagrams: diagramsBySlug.get(id.replace(/\./g, "/")) ?? [],
649
+ examples: examplesBySlug.get(id.replace(/\./g, "/")) ?? [],
448
650
  prereqEdges: sortEdges(
449
651
  teaches.flatMap(
450
652
  (to) => (prerequisitesById.get(to) ?? []).filter((from) => !teaches.includes(from)).map((from) => ({ from, to }))
@@ -470,8 +672,9 @@ async function compileManifest(courseConfig) {
470
672
  catalog,
471
673
  lintIgnore: loadLintIgnore(),
472
674
  conventions: courseConfig.conventions,
473
- ...courseConfig.operators === void 0 ? {} : { operators: courseConfig.operators },
474
- ...courseConfig.romanLabels === void 0 ? {} : { romanLabels: courseConfig.romanLabels }
675
+ operators: rules.settings("N8"),
676
+ romanLabels: rules.settings("N10"),
677
+ accents: rules.settings("N22")
475
678
  });
476
679
  const rawNotation = [...loadNotationDefinitions()].sort(
477
680
  (a, b) => String(a.key).localeCompare(String(b.key))
@@ -520,7 +723,9 @@ async function compileManifest(courseConfig) {
520
723
  return {
521
724
  schemaVersion: MANIFEST_SCHEMA_VERSION,
522
725
  lessonExports: normalizeLessonExports(courseConfig),
523
- disclosureDefaults: normalizeDisclosureDefaults(courseConfig),
726
+ disclosure: normalizeDisclosure(courseConfig),
727
+ numbering: numberingSettings,
728
+ blockLabels,
524
729
  about,
525
730
  notation: {
526
731
  definitions: registry.definitions,
@@ -534,6 +739,7 @@ async function compileManifest(courseConfig) {
534
739
  tracks,
535
740
  abbreviations,
536
741
  sidebar,
742
+ parts: manifestParts,
537
743
  lessons,
538
744
  prereqEdges,
539
745
  equations: {
@@ -556,20 +762,29 @@ async function compileManifest(courseConfig) {
556
762
  labels: checkValidation.labels,
557
763
  numbersBySlug: checkValidation.numbersBySlug
558
764
  },
765
+ examples: {
766
+ labels: exampleValidation.labels,
767
+ numbersBySlug: exampleValidation.numbersBySlug
768
+ },
559
769
  assessmentContent,
770
+ rules: rulesSnapshot(rules),
560
771
  diagnostics: {
561
- curriculum: curriculumIssues,
562
- notation: registry.diagnostics,
563
- alignment: alignmentIssues,
564
- math: mathIssues,
565
- consistency: consistencyIssues,
566
- equations: equationValidation.diagnostics,
567
- tables: tableValidation.diagnostics,
568
- figures: figureValidation.diagnostics,
569
- diagrams: diagramValidation.diagnostics,
570
- checks: checkValidation.diagnostics,
571
- knowledge: knowledge.diagnostics,
572
- rawFloats: rawFloatDiagnostics
772
+ curriculum: dropDisabled(curriculumIssues, off),
773
+ notation: dropDisabled(registry.diagnostics, off),
774
+ alignment: dropDisabled(alignmentIssues, off),
775
+ math: dropDisabled(mathIssues, off),
776
+ consistency: dropDisabled(consistencyIssues, off),
777
+ equations: dropDisabled(equationValidation.diagnostics, off),
778
+ tables: dropDisabled(tableValidation.diagnostics, off),
779
+ figures: dropDisabled(figureValidation.diagnostics, off),
780
+ diagrams: dropDisabled(diagramValidation.diagnostics, off),
781
+ checks: dropDisabled(checkValidation.diagnostics, off),
782
+ examples: dropDisabled(exampleValidation.diagnostics, off),
783
+ folds: dropDisabled(foldValidation.diagnostics, off),
784
+ knowledge: dropDisabled(knowledge.diagnostics, off),
785
+ rawFloats: dropDisabled(rawFloatDiagnostics, off),
786
+ config: rules.diagnostics,
787
+ waivers: waiverDiagnostics
573
788
  },
574
789
  hashes
575
790
  };
@@ -1,7 +1,9 @@
1
1
  import { Manifest } from './manifest.js';
2
2
  import '../curriculum/validation.js';
3
3
  import '../reference/consistency.js';
4
- import './course-config.js';
4
+ import '../course-config-Dsnri9Tk.js';
5
+ import '../rules/catalog.js';
6
+ import '../rules/course-rules.js';
5
7
  import './collections.js';
6
8
  import '../reference/types.js';
7
9
  import '../reference/lint-ignore.js';
@@ -10,11 +12,14 @@ import '../reference/tables-validate.js';
10
12
  import '../reference/keyed-float-validate.js';
11
13
  import '../reference/figures-validate.js';
12
14
  import '../reference/diagrams-validate.js';
15
+ import '../reference/examples-validate.js';
16
+ import '../reference/folds-validate.js';
13
17
  import '../reference/knowledge-checks-validate.js';
14
18
  import '../reference/raw-floats-validate.js';
15
19
  import '../reference/gate-math.js';
16
20
  import '../reference/mixed-content.js';
17
21
  import '../reference/gloss.js';
22
+ import '../rules/waivers.js';
18
23
  import './knowledge-version.js';
19
24
  import './lesson-derivation.js';
20
25