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.
- package/CHANGELOG.md +1239 -1
- package/README.md +60 -15
- package/dist/compiler/astro.d.ts +6 -1
- package/dist/compiler/cli.d.ts +46 -2
- package/dist/compiler/cli.js +70 -4
- package/dist/compiler/collections.d.ts +35 -2
- package/dist/compiler/collections.js +68 -5
- package/dist/compiler/course-config.d.ts +3 -194
- package/dist/compiler/course-config.js +78 -5
- package/dist/compiler/exports/standalone-html.d.ts +6 -1
- package/dist/compiler/knowledge-version.js +1 -1
- package/dist/compiler/lesson-derivation.d.ts +27 -10
- package/dist/compiler/lesson-derivation.js +23 -8
- package/dist/compiler/logging.d.ts +4 -1
- package/dist/compiler/logging.js +4 -1
- package/dist/compiler/manifest.d.ts +204 -31
- package/dist/compiler/manifest.js +270 -55
- package/dist/compiler/resolution-report.d.ts +6 -1
- package/dist/course-config-Dsnri9Tk.d.ts +464 -0
- package/dist/reference/base-accents.d.mts +26 -0
- package/dist/reference/base-accents.mjs +31 -0
- package/dist/reference/base-roman-labels.d.mts +2 -2
- package/dist/reference/base-roman-labels.mjs +2 -2
- package/dist/reference/consistency.d.ts +14 -2
- package/dist/reference/consistency.js +108 -4
- package/dist/reference/delimiter-size.d.ts +3 -2
- package/dist/reference/diagrams-validate.d.ts +7 -2
- package/dist/reference/diagrams-validate.js +9 -1
- package/dist/reference/equations-validate.d.ts +8 -5
- package/dist/reference/equations-validate.js +1 -0
- package/dist/reference/equations.d.mts +60 -31
- package/dist/reference/equations.mjs +83 -43
- package/dist/reference/examples-validate.d.ts +31 -0
- package/dist/reference/examples-validate.js +48 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/figures-validate.js +4 -1
- package/dist/reference/folds-validate.d.ts +33 -0
- package/dist/reference/folds-validate.js +32 -0
- package/dist/reference/gate-abbreviations.d.ts +3 -1
- package/dist/reference/gate-abbreviations.js +1 -0
- package/dist/reference/gate-course-rules.d.ts +32 -0
- package/dist/reference/gate-course-rules.js +85 -0
- package/dist/reference/gate-heading-length.d.ts +5 -2
- package/dist/reference/gate-heading-length.js +45 -21
- package/dist/reference/gate-heading-structure.d.ts +41 -0
- package/dist/reference/gate-heading-structure.js +113 -0
- package/dist/reference/gate-math-punctuation.d.ts +71 -0
- package/dist/reference/gate-math-punctuation.js +251 -0
- package/dist/reference/gate-math.d.ts +22 -6
- package/dist/reference/gate-math.js +42 -8
- package/dist/reference/gate-part-pages.d.ts +50 -0
- package/dist/reference/gate-part-pages.js +118 -0
- package/dist/reference/gate-prose-notation.d.ts +21 -11
- package/dist/reference/gate-prose-notation.js +25 -7
- package/dist/reference/katex-delimiters.mjs +20 -7
- package/dist/reference/keyed-float-validate.d.ts +27 -10
- package/dist/reference/keyed-float-validate.js +15 -1
- package/dist/reference/keyed-jsx-floats.d.mts +11 -5
- package/dist/reference/keyed-jsx-floats.mjs +73 -20
- package/dist/reference/knowledge-checks-validate.d.ts +1 -1
- package/dist/reference/knowledge-checks.d.mts +3 -1
- package/dist/reference/knowledge-checks.mjs +9 -4
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-slot.d.ts +34 -0
- package/dist/reference/lab-math-slot.js +6 -0
- package/dist/reference/math-glyphs.d.mts +80 -4
- package/dist/reference/math-glyphs.mjs +572 -37
- package/dist/reference/page-notation.d.ts +6 -1
- package/dist/reference/raw-floats-validate.js +1 -1
- package/dist/reference/raw-floats.mjs +1 -1
- package/dist/reference/rehype-heading-anchors.d.mts +14 -0
- package/dist/reference/rehype-heading-anchors.mjs +116 -17
- package/dist/reference/rehype-table-header-labels.d.mts +6 -1
- package/dist/reference/rehype-table-header-labels.mjs +21 -3
- package/dist/reference/remark-asides.d.mts +3 -0
- package/dist/reference/remark-asides.mjs +180 -0
- package/dist/reference/remark-memo.d.mts +3 -1
- package/dist/reference/remark-memo.mjs +42 -11
- package/dist/reference/remark-notation.d.mts +60 -10
- package/dist/reference/remark-notation.mjs +387 -36
- package/dist/reference/render-lab-math.d.ts +4 -26
- package/dist/reference/render-lab-math.js +4 -4
- package/dist/reference/sections-validate.d.ts +27 -0
- package/dist/reference/sections-validate.js +41 -0
- package/dist/reference/sections.d.mts +97 -0
- package/dist/reference/sections.mjs +306 -0
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/types.d.ts +17 -1
- package/dist/reference/unit-words.d.ts +37 -0
- package/dist/reference/unit-words.js +170 -0
- package/dist/rules/catalog.d.ts +176 -0
- package/dist/rules/catalog.js +983 -0
- package/dist/rules/course-rules.d.ts +115 -0
- package/dist/rules/course-rules.js +292 -0
- package/dist/rules/course-rules.schema.json +138 -0
- package/dist/rules/in-effect.d.ts +53 -0
- package/dist/rules/in-effect.js +142 -0
- package/dist/rules/rules.schema.json +1072 -0
- package/dist/rules/settings.d.ts +3 -0
- package/dist/rules/settings.js +290 -0
- package/dist/rules/waivers.d.ts +53 -0
- package/dist/rules/waivers.js +132 -0
- package/dist/session/PreferenceStore.d.ts +5 -0
- package/dist/session/PreferenceStore.js +9 -0
- package/docs/VERSIONING.md +2 -2
- package/docs/authoring/README.md +232 -40
- package/docs/authoring/agents.md +55 -9
- package/docs/authoring/components.md +178 -22
- package/docs/authoring/migrating.md +1096 -2
- package/docs/authoring/notation.md +576 -322
- package/docs/authoring/prose.md +551 -0
- package/docs/authoring/retired.md +35 -0
- package/docs/authoring/structure-rules.md +422 -40
- package/docs/authoring/structure.md +445 -62
- package/docs/authoring/versioning.md +20 -28
- package/docs/authoring/visualizations.md +142 -20
- package/package.json +2 -2
- package/src/compiler/cli.ts +116 -6
- package/src/compiler/collections.ts +111 -7
- package/src/compiler/course-config.ts +273 -34
- package/src/compiler/knowledge-version.ts +1 -1
- package/src/compiler/lesson-derivation.ts +54 -15
- package/src/compiler/logging.ts +8 -2
- package/src/compiler/manifest.ts +573 -104
- package/src/components/BlockHeading.astro +113 -0
- package/src/components/CourseContents.astro +221 -0
- package/src/components/CurriculumMap.astro +5 -6
- package/src/components/FloatIndex.astro +200 -0
- package/src/components/HoverPanel.astro +431 -79
- package/src/components/PartBridge.astro +27 -0
- package/src/components/PartOverview.astro +401 -0
- package/src/components/PartScope.astro +27 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
- package/src/components/assessments/AssessmentRunner.tsx +8 -5
- package/src/components/assessments/AssessmentSet.astro +23 -26
- package/src/components/block-heading.ts +146 -0
- package/src/components/card-arrow.ts +243 -0
- package/src/components/card-drag.ts +631 -0
- package/src/components/card-jump.ts +45 -0
- package/src/components/card-manager.ts +1589 -0
- package/src/components/card-memory.ts +177 -0
- package/src/components/card-placement.ts +504 -0
- package/src/components/card-side.ts +336 -0
- package/src/components/card-travel.ts +197 -0
- package/src/components/citation/CitationLayer.astro +77 -76
- package/src/components/diagram/Diagram.astro +161 -316
- package/src/components/disclosure/course-disclosure.ts +24 -0
- package/src/components/disclosure/hover-preview.ts +122 -42
- package/src/components/disclosure/persisted-disclosure.ts +3 -3
- package/src/components/disclosure/print-as-shown.ts +252 -0
- package/src/components/examples/CompactExample.astro +3 -1
- package/src/components/examples/CompactExamples.astro +101 -94
- package/src/components/figure/Figure.astro +174 -274
- package/src/components/figure/FloatCaption.astro +87 -0
- package/src/components/figure/figure-state.ts +58 -0
- package/src/components/figure/figure-tools.ts +87 -0
- package/src/components/float-name.ts +101 -0
- package/src/components/fold/Fold.astro +125 -0
- package/src/components/fold/fold-id.ts +40 -0
- package/src/components/memo/Memo.astro +162 -231
- package/src/components/memo/ShortNote.astro +6 -6
- package/src/components/notation/NotationFormula.astro +5 -1
- package/src/components/notation/NotationGlossary.astro +3 -4
- package/src/components/notation/NotationLayer.astro +169 -162
- package/src/components/notation/NotationMath.astro +10 -1
- package/src/components/reference/FloatRefLayer.astro +485 -423
- package/src/components/starlight/AboutPanel.astro +5 -4
- package/src/components/starlight/CollapsibleSections.astro +207 -93
- package/src/components/starlight/DiagramEnhancer.astro +15 -138
- package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
- package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
- package/src/components/starlight/LayoutHeader.astro +298 -19
- package/src/components/starlight/LayoutPageSidebar.astro +99 -12
- package/src/components/starlight/LayoutPageTitle.astro +120 -0
- package/src/components/starlight/LayoutSidebar.astro +229 -11
- package/src/components/starlight/LessonExportActions.astro +53 -72
- package/src/components/starlight/LessonFooter.astro +26 -4
- package/src/components/starlight/section-parts.ts +15 -2
- package/src/components/starlight/section-summary.ts +181 -0
- package/src/components/table/Table.astro +95 -76
- package/src/components/table/TableOverflowExpander.astro +65 -28
- package/src/content-config.ts +40 -4
- package/src/reference/base-accents.mjs +31 -0
- package/src/reference/base-roman-labels.mjs +2 -2
- package/src/reference/consistency.ts +176 -5
- package/src/reference/delimiter-size.ts +3 -2
- package/src/reference/diagrams-validate.ts +17 -1
- package/src/reference/equations-validate.ts +10 -5
- package/src/reference/equations.mjs +83 -43
- package/src/reference/examples-validate.ts +97 -0
- package/src/reference/figures-validate.ts +6 -1
- package/src/reference/folds-validate.ts +65 -0
- package/src/reference/gate-abbreviations.ts +1 -0
- package/src/reference/gate-course-rules.ts +134 -0
- package/src/reference/gate-heading-length.ts +66 -35
- package/src/reference/gate-heading-structure.ts +193 -0
- package/src/reference/gate-math-punctuation.ts +381 -0
- package/src/reference/gate-math.ts +69 -10
- package/src/reference/gate-part-pages.ts +217 -0
- package/src/reference/gate-prose-notation.ts +59 -12
- package/src/reference/katex-delimiters.mjs +20 -7
- package/src/reference/keyed-float-validate.ts +45 -11
- package/src/reference/keyed-jsx-floats.mjs +73 -20
- package/src/reference/knowledge-checks-validate.ts +1 -1
- package/src/reference/knowledge-checks.mjs +9 -4
- package/src/reference/lab-math-slot.ts +36 -0
- package/src/reference/math-glyphs.mjs +572 -37
- package/src/reference/raw-floats-validate.ts +1 -1
- package/src/reference/raw-floats.mjs +1 -1
- package/src/reference/rehype-heading-anchors.mjs +116 -17
- package/src/reference/rehype-table-header-labels.mjs +21 -3
- package/src/reference/remark-asides.mjs +180 -0
- package/src/reference/remark-memo.mjs +42 -11
- package/src/reference/remark-notation.mjs +387 -36
- package/src/reference/render-lab-math.ts +16 -31
- package/src/reference/sections-validate.ts +81 -0
- package/src/reference/sections.mjs +306 -0
- package/src/reference/tables-validate.ts +2 -1
- package/src/reference/types.ts +17 -0
- package/src/reference/unit-words.ts +233 -0
- package/src/rules/catalog.ts +1298 -0
- package/src/rules/course-rules.ts +456 -0
- package/src/rules/in-effect.ts +235 -0
- package/src/rules/settings.ts +448 -0
- package/src/rules/waivers.ts +249 -0
- package/src/session/PreferenceStore.ts +15 -0
- package/src/styles/global.css +1471 -163
- package/src/styles/surfaces.css +182 -0
- package/src/components/hover-panel.ts +0 -339
- package/src/components/popup-stack.ts +0 -345
package/README.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="playground/src/assets/explico-mark-dark.svg">
|
|
3
|
+
<img src="playground/src/assets/explico-mark.svg" alt="" width="88" align="right">
|
|
4
|
+
</picture>
|
|
5
|
+
|
|
1
6
|
# explico
|
|
2
7
|
|
|
3
8
|
A build-time engine for **prerequisite-aware, notation-rigorous course
|
|
@@ -23,6 +28,13 @@ What it gives a course:
|
|
|
23
28
|
- **Equation identity** — `\label{eq:key}` gives a display equation a stable
|
|
24
29
|
key, an appearance-order number, an anchor, and cross-lesson `[[eq-key]]`
|
|
25
30
|
references.
|
|
31
|
+
- **Outline numbering** — sections number `part.chapter.section` like a book
|
|
32
|
+
(`§ 1.1.2`), floats `part.chapter.n` (`Figure 2.2.1`); `[[sec-…]]` cites a
|
|
33
|
+
section, a heading's chain icon copies its link, and a typed number form
|
|
34
|
+
(`#sec-1.1.2`) lands on the named anchor. A knowledge check and a set of
|
|
35
|
+
worked examples are numbered sections of their own: the author writes the
|
|
36
|
+
topic, the engine the kind's badge and the number (`[[ex-…]]`,
|
|
37
|
+
`[[check-…]]`).
|
|
26
38
|
- **A KaTeX trust boundary** — build-time HTML + MathML; the trust callback
|
|
27
39
|
accepts exactly one validated `data-notation-key`. No runtime math, no CDN.
|
|
28
40
|
- **A deterministic JSON manifest** — the MCP/LMS contract: lessons, notation,
|
|
@@ -78,8 +90,10 @@ import remarkNotation, {
|
|
|
78
90
|
} from 'explico/reference/remark-notation.mjs';
|
|
79
91
|
import remarkShortNote from 'explico/reference/remark-short-note.mjs';
|
|
80
92
|
import remarkCitation from 'explico/reference/remark-citation.mjs';
|
|
93
|
+
import remarkAsides from 'explico/reference/remark-asides.mjs';
|
|
81
94
|
import { createNotationKatexOptions } from 'explico/reference/katex-options.mjs';
|
|
82
95
|
import rehypeFailKatexErrors from 'explico/reference/rehype-fail-katex-errors.mjs';
|
|
96
|
+
import rehypeHeadingAnchors from 'explico/reference/rehype-heading-anchors.mjs';
|
|
83
97
|
import { courseConfig } from './content/course.config.ts';
|
|
84
98
|
|
|
85
99
|
const manifest = await loadManifest(courseConfig);
|
|
@@ -93,14 +107,26 @@ const manifest = await loadManifest(courseConfig);
|
|
|
93
107
|
// // the build when a catalogued lesson has equations/tables/figures but no
|
|
94
108
|
// // numbering or cross-page entry, instead of silently numbering it by
|
|
95
109
|
// // `##` section while references to it read the part scheme.
|
|
96
|
-
//
|
|
97
|
-
//
|
|
110
|
+
// // `base` is the Astro `base` of a subpath deployment (e.g. a GitHub
|
|
111
|
+
// // Pages project site); the links these plugins write 404 without it.
|
|
112
|
+
// [remarkNotation, createRemarkNotationOptions(manifest, { strict: true, base })],
|
|
113
|
+
// // The generated References section's first state, from the course's
|
|
114
|
+
// // `disclosure` settings block (`CourseConfig.disclosure`).
|
|
115
|
+
// [remarkCitation, {
|
|
116
|
+
// sources: manifest.sources,
|
|
117
|
+
// defaultOpen: courseConfig.disclosure?.references?.defaultOpen === true,
|
|
118
|
+
// }],
|
|
119
|
+
// // Last: renders `:::note` / `:::tip` / `:::caution` / `:::danger` as
|
|
120
|
+
// // Starlight's `<Aside>` (Starlight's own pass skips `content/docs/`).
|
|
121
|
+
// remarkAsides,
|
|
98
122
|
// ]
|
|
99
123
|
// … integrations: [explicoContentRefresh(courseConfig, manifest),
|
|
100
124
|
// starlight({ customCss: ['explico/styles/global.css'],
|
|
101
125
|
// components: { Footer: 'explico/components/starlight/LessonFooter.astro',
|
|
102
126
|
// SocialIcons: 'explico/components/starlight/LayoutSocialIcons.astro', … } })
|
|
103
|
-
// … rehypePlugins: [[rehypeKatex, createNotationKatexOptions()], rehypeFailKatexErrors
|
|
127
|
+
// … rehypePlugins: [[rehypeKatex, createNotationKatexOptions()], rehypeFailKatexErrors,
|
|
128
|
+
// // Heading collapse defaults: the same `disclosure` block.
|
|
129
|
+
// [rehypeHeadingAnchors, { defaultCollapsible: courseConfig.disclosure }]]
|
|
104
130
|
```
|
|
105
131
|
|
|
106
132
|
`loadManifest(courseConfig)` always recompiles current content before Astro
|
|
@@ -109,18 +135,18 @@ and restarts the development server when any file under `content/` is added,
|
|
|
109
135
|
changed, or removed, keeping Markdown transforms and UI components on the same
|
|
110
136
|
model without an editor-specific task.
|
|
111
137
|
|
|
112
|
-
A memo is a substantial optional derivation: it
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
fragment:
|
|
138
|
+
A memo is a substantial optional derivation: it folds like a `######`
|
|
139
|
+
section without adding a heading to the page outline. Cite it from earlier
|
|
140
|
+
prose with `[[memo-id]]` — a superscript letter — then place the block
|
|
141
|
+
wherever it best fits. The citation and the chain icon on its bar link to the
|
|
142
|
+
same URL fragment:
|
|
117
143
|
|
|
118
144
|
```mdx
|
|
119
145
|
The omitted calculation is recorded in [[memo-full-check]].
|
|
120
146
|
|
|
121
147
|
Several paragraphs may intervene.
|
|
122
148
|
|
|
123
|
-
<Memo id="full-check"
|
|
149
|
+
<Memo id="full-check" short="Full check" caption="The omitted algebra and evidence">
|
|
124
150
|
|
|
125
151
|
The longer derivation can contain paragraphs, equations, tables, and figures.
|
|
126
152
|
|
|
@@ -140,9 +166,24 @@ Differentiate the polynomial, set the result to zero, and solve.
|
|
|
140
166
|
</ShortNote>. But symmetry is quicker.
|
|
141
167
|
```
|
|
142
168
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
169
|
+
A memo requires literal `id` and `caption` strings (`short` is optional); a
|
|
170
|
+
short note requires `id`, `title` and `description`. Memos start as the
|
|
171
|
+
course's `disclosure.memos` says (closed by default) and persist reader state
|
|
172
|
+
unless `rememberState={false}`; short notes always start collapsed.
|
|
173
|
+
|
|
174
|
+
A figure or a diagram never folds by itself. To let a reader fold one away
|
|
175
|
+
where it stands — or any stretch of content — import
|
|
176
|
+
`explico/components/fold/Fold.astro` and wrap it in `<Fold>`: no heading,
|
|
177
|
+
number or letter, only a bar with the section chevron. The bar is its `label`
|
|
178
|
+
or, without one, the numbers and short captions of the floats inside
|
|
179
|
+
("Diagram 2.1.1 Steps of the derivation"). Folds start as the course's
|
|
180
|
+
`disclosure.folds` says (closed by default), or as `defaultOpen` says:
|
|
181
|
+
|
|
182
|
+
```mdx
|
|
183
|
+
<Fold>
|
|
184
|
+
<Diagram id="steps" caption="…" short="Steps of the derivation" nodes={…} edges={…} />
|
|
185
|
+
</Fold>
|
|
186
|
+
```
|
|
146
187
|
|
|
147
188
|
### Lesson exports
|
|
148
189
|
|
|
@@ -176,9 +217,13 @@ viewer’s system color scheme.
|
|
|
176
217
|
|
|
177
218
|
The **Print / save as PDF** action calls the browser's native print dialog; it
|
|
178
219
|
does not download or build a `.pdf` file itself. The print layout removes site
|
|
179
|
-
chrome
|
|
180
|
-
|
|
181
|
-
|
|
220
|
+
chrome and prints every disclosure as the reader left it on screen: an open
|
|
221
|
+
section, figure, memo, or question prints in full, and a closed one prints its
|
|
222
|
+
title and a "(content collapsed — full text: …)" note with its permalink.
|
|
223
|
+
Complete data surfaces (every table row, every worked example of an open set)
|
|
224
|
+
still print in full. It does all this without changing saved reader state,
|
|
225
|
+
hides controls that have no paper equivalent while retaining their current
|
|
226
|
+
visual result, and keeps linked text clickable with canonical destinations.
|
|
182
227
|
Paper size, margins, browser-added headers/footers, final filename, and the
|
|
183
228
|
choice to save as PDF remain browser and reader settings.
|
|
184
229
|
|
package/dist/compiler/astro.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AstroConfig, AstroIntegration } from 'astro';
|
|
2
|
-
import { CourseConfig } from '
|
|
2
|
+
import { C as CourseConfig } from '../course-config-Dsnri9Tk.js';
|
|
3
3
|
import { Manifest } from './manifest.js';
|
|
4
|
+
import '../rules/catalog.js';
|
|
5
|
+
import '../rules/course-rules.js';
|
|
4
6
|
import '../curriculum/validation.js';
|
|
5
7
|
import '../reference/consistency.js';
|
|
6
8
|
import './collections.js';
|
|
@@ -11,11 +13,14 @@ import '../reference/tables-validate.js';
|
|
|
11
13
|
import '../reference/keyed-float-validate.js';
|
|
12
14
|
import '../reference/figures-validate.js';
|
|
13
15
|
import '../reference/diagrams-validate.js';
|
|
16
|
+
import '../reference/examples-validate.js';
|
|
17
|
+
import '../reference/folds-validate.js';
|
|
14
18
|
import '../reference/knowledge-checks-validate.js';
|
|
15
19
|
import '../reference/raw-floats-validate.js';
|
|
16
20
|
import '../reference/gate-math.js';
|
|
17
21
|
import '../reference/mixed-content.js';
|
|
18
22
|
import '../reference/gloss.js';
|
|
23
|
+
import '../rules/waivers.js';
|
|
19
24
|
import './knowledge-version.js';
|
|
20
25
|
import './lesson-derivation.js';
|
|
21
26
|
|
package/dist/compiler/cli.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { DiagnosticSeverity } from '../reference/types.js';
|
|
2
2
|
import { EquationLink } from '../reference/gate-math.js';
|
|
3
3
|
import { Manifest, ManifestLesson } from './manifest.js';
|
|
4
|
+
import { RulesFilter, RuleInEffect } from '../rules/in-effect.js';
|
|
4
5
|
import '../curriculum/validation.js';
|
|
5
6
|
import '../reference/consistency.js';
|
|
6
|
-
import '
|
|
7
|
+
import '../course-config-Dsnri9Tk.js';
|
|
8
|
+
import '../rules/catalog.js';
|
|
9
|
+
import '../rules/course-rules.js';
|
|
7
10
|
import './collections.js';
|
|
8
11
|
import '../reference/lint-ignore.js';
|
|
9
12
|
import '../reference/equations-validate.js';
|
|
@@ -11,10 +14,13 @@ import '../reference/tables-validate.js';
|
|
|
11
14
|
import '../reference/keyed-float-validate.js';
|
|
12
15
|
import '../reference/figures-validate.js';
|
|
13
16
|
import '../reference/diagrams-validate.js';
|
|
17
|
+
import '../reference/examples-validate.js';
|
|
18
|
+
import '../reference/folds-validate.js';
|
|
14
19
|
import '../reference/knowledge-checks-validate.js';
|
|
15
20
|
import '../reference/raw-floats-validate.js';
|
|
16
21
|
import '../reference/mixed-content.js';
|
|
17
22
|
import '../reference/gloss.js';
|
|
23
|
+
import '../rules/waivers.js';
|
|
18
24
|
import './knowledge-version.js';
|
|
19
25
|
import './lesson-derivation.js';
|
|
20
26
|
|
|
@@ -56,6 +62,12 @@ declare class ContentCliError extends Error {
|
|
|
56
62
|
/** One normalized diagnostic. `code` is `<source>:<kind>` and always stable. */
|
|
57
63
|
interface CliDiagnostic {
|
|
58
64
|
readonly code: string;
|
|
65
|
+
/**
|
|
66
|
+
* The catalog entry that owns the code — a rule ID (`N9`) or an invariant
|
|
67
|
+
* slug (`keyed-floats`). Absent only for a code the catalog does not know,
|
|
68
|
+
* which `tests/rules/catalog.test.ts` treats as a bug.
|
|
69
|
+
*/
|
|
70
|
+
readonly rule?: string;
|
|
59
71
|
readonly severity: DiagnosticSeverity;
|
|
60
72
|
readonly message: string;
|
|
61
73
|
readonly file?: string;
|
|
@@ -123,6 +135,7 @@ interface StatusReport {
|
|
|
123
135
|
readonly keyedTables: number;
|
|
124
136
|
readonly keyedFigures: number;
|
|
125
137
|
readonly keyedDiagrams: number;
|
|
138
|
+
readonly keyedExamples: number;
|
|
126
139
|
};
|
|
127
140
|
readonly draftDebt: {
|
|
128
141
|
readonly lessons: readonly string[];
|
|
@@ -150,6 +163,23 @@ interface WarningsReport {
|
|
|
150
163
|
declare function contentDiagnostics(manifest: Manifest, minimumSeverity?: DiagnosticThreshold): DiagnosticsReport;
|
|
151
164
|
/** Every warning exactly; errors and informational advice are excluded. */
|
|
152
165
|
declare function contentWarnings(manifest: Manifest): WarningsReport;
|
|
166
|
+
interface RulesReport {
|
|
167
|
+
readonly filter: RulesFilter;
|
|
168
|
+
readonly count: number;
|
|
169
|
+
readonly rules: readonly RuleInEffect[];
|
|
170
|
+
/** The same selection as the page `validate:content` writes. */
|
|
171
|
+
readonly markdown: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Parse `--element a,b` / `--enforcement script` into a filter, throwing a
|
|
175
|
+
* usage error on a value outside the vocabulary.
|
|
176
|
+
*/
|
|
177
|
+
declare function parseRulesFilter(input: {
|
|
178
|
+
readonly element?: string;
|
|
179
|
+
readonly enforcement?: string;
|
|
180
|
+
}): RulesFilter;
|
|
181
|
+
/** The rules this course has in effect, optionally narrowed. */
|
|
182
|
+
declare function contentRules(manifest: Manifest, filter?: RulesFilter): RulesReport;
|
|
153
183
|
interface ContextReport {
|
|
154
184
|
readonly lesson: {
|
|
155
185
|
readonly id: string;
|
|
@@ -196,9 +226,23 @@ interface ContextReport {
|
|
|
196
226
|
key: string;
|
|
197
227
|
number: string;
|
|
198
228
|
}[];
|
|
229
|
+
/** Worked-example sets: `short` is the title `[[ex-key]]` names. */
|
|
230
|
+
readonly examples: readonly {
|
|
231
|
+
key: string;
|
|
232
|
+
number: string;
|
|
233
|
+
short?: string;
|
|
234
|
+
}[];
|
|
199
235
|
readonly knowledgeChecks: readonly {
|
|
200
236
|
key: string;
|
|
201
237
|
number: string;
|
|
238
|
+
title?: string;
|
|
239
|
+
}[];
|
|
240
|
+
/** The top-level headings: `slug` is what `[[sec-slug]]` names. */
|
|
241
|
+
readonly sections: readonly {
|
|
242
|
+
slug: string;
|
|
243
|
+
text: string;
|
|
244
|
+
level: number;
|
|
245
|
+
number?: string;
|
|
202
246
|
}[];
|
|
203
247
|
readonly sources: readonly {
|
|
204
248
|
id: string;
|
|
@@ -242,4 +286,4 @@ interface Scaffold {
|
|
|
242
286
|
declare function scaffoldLesson(rawId: string): Scaffold;
|
|
243
287
|
declare function scaffoldTerm(rawKey: string): Scaffold;
|
|
244
288
|
|
|
245
|
-
export { type CheckLessonResult, type CheckReport, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DomainFileSignatures, type RenderResult, type Scaffold, type StatusReport, type TokenCounts, type WarningsReport, changedLessonIds, contentCheck, contentContext, contentDiagnostics, contentStatus, contentWarnings, estimateTokens, findLesson, lessonDiagnostics, normalizeLessonId, renderLesson, scaffoldLesson, scaffoldTerm };
|
|
289
|
+
export { type CheckLessonResult, type CheckReport, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DomainFileSignatures, type RenderResult, type RulesReport, type Scaffold, type StatusReport, type TokenCounts, type WarningsReport, changedLessonIds, contentCheck, contentContext, contentDiagnostics, contentRules, contentStatus, contentWarnings, estimateTokens, findLesson, lessonDiagnostics, normalizeLessonId, parseRulesFilter, renderLesson, scaffoldLesson, scaffoldTerm };
|
package/dist/compiler/cli.js
CHANGED
|
@@ -18,6 +18,11 @@ import remarkNotation, {
|
|
|
18
18
|
} from "../reference/remark-notation.mjs";
|
|
19
19
|
import remarkShortNote from "../reference/remark-short-note.mjs";
|
|
20
20
|
import { isLessonSlug, lessonIdFromSlug } from "./lesson-derivation.js";
|
|
21
|
+
import { isCourseRuleId, ownerOf, ELEMENTS } from "../rules/catalog.js";
|
|
22
|
+
import {
|
|
23
|
+
renderRulesInEffect,
|
|
24
|
+
rulesInEffect
|
|
25
|
+
} from "../rules/in-effect.js";
|
|
21
26
|
const REPOSITORY_ROOT = process.cwd();
|
|
22
27
|
const CONTENT_ROOT = join(REPOSITORY_ROOT, "content");
|
|
23
28
|
const DOCS_ROOT = join(CONTENT_ROOT, "docs");
|
|
@@ -33,6 +38,15 @@ class ContentCliError extends Error {
|
|
|
33
38
|
function diagnosticSeverity(value) {
|
|
34
39
|
return value === "info" || value === "warning" ? value : "error";
|
|
35
40
|
}
|
|
41
|
+
function ownerFields(code) {
|
|
42
|
+
const bare = code.slice(code.indexOf(":") + 1);
|
|
43
|
+
const owner = ownerOf(bare);
|
|
44
|
+
if (owner !== void 0) return { rule: owner.id };
|
|
45
|
+
return isCourseRuleId(bare) ? { rule: bare } : {};
|
|
46
|
+
}
|
|
47
|
+
function withOwner(diagnostic) {
|
|
48
|
+
return { ...diagnostic, ...ownerFields(diagnostic.code) };
|
|
49
|
+
}
|
|
36
50
|
function mentions(message, lessonId, file) {
|
|
37
51
|
return message.includes(lessonId) || message.includes(file) || message.includes(file.replace(/^content\/docs\//, ""));
|
|
38
52
|
}
|
|
@@ -71,7 +85,7 @@ function lessonDiagnostics(manifest, lesson) {
|
|
|
71
85
|
);
|
|
72
86
|
if (!forLesson) continue;
|
|
73
87
|
out.push({
|
|
74
|
-
code: `math:${diagnostic.code
|
|
88
|
+
code: `math:${diagnostic.code}`,
|
|
75
89
|
severity: diagnostic.severity,
|
|
76
90
|
message: diagnostic.message,
|
|
77
91
|
file: diagnostic.file,
|
|
@@ -96,6 +110,8 @@ function lessonDiagnostics(manifest, lesson) {
|
|
|
96
110
|
...manifest.diagnostics.figures,
|
|
97
111
|
...manifest.diagnostics.diagrams,
|
|
98
112
|
...manifest.diagnostics.checks,
|
|
113
|
+
...manifest.diagnostics.examples,
|
|
114
|
+
...manifest.diagnostics.folds,
|
|
99
115
|
...manifest.diagnostics.rawFloats
|
|
100
116
|
]) {
|
|
101
117
|
if (diagnostic.lessonId !== id && diagnostic.file !== file && !mentions(diagnostic.message, id, file)) {
|
|
@@ -117,7 +133,7 @@ function lessonDiagnostics(manifest, lesson) {
|
|
|
117
133
|
...withFile(diagnostic.file)
|
|
118
134
|
});
|
|
119
135
|
}
|
|
120
|
-
return out.sort(
|
|
136
|
+
return out.map(withOwner).sort(
|
|
121
137
|
(a, b) => a.code.localeCompare(b.code) || a.message.localeCompare(b.message)
|
|
122
138
|
);
|
|
123
139
|
}
|
|
@@ -306,6 +322,7 @@ function contentStatus(manifest) {
|
|
|
306
322
|
const draftNotation = manifest.notation.definitions.filter((definition) => definition.status === "draft").map((definition) => definition.id).sort();
|
|
307
323
|
const orphans = manifest.notation.diagnostics.filter((diagnostic) => diagnostic.code === "unused-definition").map((diagnostic) => ({
|
|
308
324
|
code: `notation:${diagnostic.code}`,
|
|
325
|
+
...ownerFields(diagnostic.code),
|
|
309
326
|
severity: diagnosticSeverity(diagnostic.severity),
|
|
310
327
|
message: diagnostic.message,
|
|
311
328
|
...diagnostic.source?.file === void 0 ? {} : { file: diagnostic.source.file }
|
|
@@ -320,9 +337,13 @@ function contentStatus(manifest) {
|
|
|
320
337
|
...manifest.diagnostics.figures.map((d) => d.severity),
|
|
321
338
|
...manifest.diagnostics.diagrams.map((d) => d.severity),
|
|
322
339
|
...manifest.diagnostics.checks.map((d) => d.severity),
|
|
340
|
+
...manifest.diagnostics.examples.map((d) => d.severity),
|
|
341
|
+
...manifest.diagnostics.folds.map((d) => d.severity),
|
|
323
342
|
...manifest.diagnostics.rawFloats.map((d) => d.severity),
|
|
324
343
|
...manifest.diagnostics.consistency.map((d) => d.severity),
|
|
325
|
-
...manifest.diagnostics.knowledge.map((d) => d.severity)
|
|
344
|
+
...manifest.diagnostics.knowledge.map((d) => d.severity),
|
|
345
|
+
...manifest.diagnostics.config.map((d) => d.severity),
|
|
346
|
+
...manifest.diagnostics.waivers.map((d) => d.severity)
|
|
326
347
|
];
|
|
327
348
|
const keyedEquations = manifest.lessons.reduce(
|
|
328
349
|
(count, lesson) => count + lesson.equations.length,
|
|
@@ -340,6 +361,10 @@ function contentStatus(manifest) {
|
|
|
340
361
|
(count, lesson) => count + lesson.diagrams.length,
|
|
341
362
|
0
|
|
342
363
|
);
|
|
364
|
+
const keyedExamples = manifest.lessons.reduce(
|
|
365
|
+
(count, lesson) => count + lesson.examples.length,
|
|
366
|
+
0
|
|
367
|
+
);
|
|
343
368
|
const assessments = new Set(
|
|
344
369
|
manifest.lessons.flatMap((lesson) => lesson.assessments)
|
|
345
370
|
).size;
|
|
@@ -355,7 +380,8 @@ function contentStatus(manifest) {
|
|
|
355
380
|
keyedEquations,
|
|
356
381
|
keyedTables,
|
|
357
382
|
keyedFigures,
|
|
358
|
-
keyedDiagrams
|
|
383
|
+
keyedDiagrams,
|
|
384
|
+
keyedExamples
|
|
359
385
|
},
|
|
360
386
|
draftDebt: { lessons: draftLessons, notation: draftNotation },
|
|
361
387
|
orphans,
|
|
@@ -403,6 +429,7 @@ function contentDiagnostics(manifest, minimumSeverity = "info") {
|
|
|
403
429
|
const equation = equationLink(diagnostic.equation);
|
|
404
430
|
diagnostics.push({
|
|
405
431
|
code: `${group}:${detail}`,
|
|
432
|
+
...ownerFields(detail),
|
|
406
433
|
severity,
|
|
407
434
|
message: String(diagnostic.message ?? detail),
|
|
408
435
|
...file === void 0 ? {} : { file },
|
|
@@ -427,6 +454,41 @@ function contentWarnings(manifest) {
|
|
|
427
454
|
);
|
|
428
455
|
return { count: warnings.length, warnings };
|
|
429
456
|
}
|
|
457
|
+
function parseRulesFilter(input) {
|
|
458
|
+
const filter = {};
|
|
459
|
+
if (input.element !== void 0) {
|
|
460
|
+
const elements = input.element.split(",").map((e) => e.trim()).filter(Boolean);
|
|
461
|
+
for (const element of elements) {
|
|
462
|
+
if (!ELEMENTS.includes(element)) {
|
|
463
|
+
throw new ContentCliError(
|
|
464
|
+
"usage",
|
|
465
|
+
`--element ${element}: not an element. One of: ${ELEMENTS.join(", ")}.`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
filter.elements = elements;
|
|
470
|
+
}
|
|
471
|
+
if (input.enforcement !== void 0) {
|
|
472
|
+
const kinds = ["script", "partial", "guide", "locked"];
|
|
473
|
+
if (!kinds.includes(input.enforcement)) {
|
|
474
|
+
throw new ContentCliError(
|
|
475
|
+
"usage",
|
|
476
|
+
`--enforcement ${input.enforcement}: one of ${kinds.join(", ")}.`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
filter.enforcement = input.enforcement;
|
|
480
|
+
}
|
|
481
|
+
return filter;
|
|
482
|
+
}
|
|
483
|
+
function contentRules(manifest, filter = {}) {
|
|
484
|
+
const rules = rulesInEffect(manifest, filter);
|
|
485
|
+
return {
|
|
486
|
+
filter,
|
|
487
|
+
count: rules.length,
|
|
488
|
+
rules,
|
|
489
|
+
markdown: renderRulesInEffect(manifest, filter)
|
|
490
|
+
};
|
|
491
|
+
}
|
|
430
492
|
function contentContext(manifest, rawId) {
|
|
431
493
|
const lesson = findLesson(manifest, rawId);
|
|
432
494
|
const { frontmatter, body } = lessonRaw(lesson);
|
|
@@ -474,7 +536,9 @@ function contentContext(manifest, rawId) {
|
|
|
474
536
|
tables: lesson.tables.map((table) => ({ ...table })),
|
|
475
537
|
figures: lesson.figures.map((figure) => ({ ...figure })),
|
|
476
538
|
diagrams: lesson.diagrams.map((diagram) => ({ ...diagram })),
|
|
539
|
+
examples: lesson.examples.map((example) => ({ ...example })),
|
|
477
540
|
knowledgeChecks: lesson.knowledgeChecks.map((check) => ({ ...check })),
|
|
541
|
+
sections: lesson.headings.map((heading) => ({ ...heading })),
|
|
478
542
|
sources: lesson.sources.map((id) => {
|
|
479
543
|
const record = sourceById.get(id);
|
|
480
544
|
return {
|
|
@@ -667,12 +731,14 @@ export {
|
|
|
667
731
|
contentCheck,
|
|
668
732
|
contentContext,
|
|
669
733
|
contentDiagnostics,
|
|
734
|
+
contentRules,
|
|
670
735
|
contentStatus,
|
|
671
736
|
contentWarnings,
|
|
672
737
|
estimateTokens,
|
|
673
738
|
findLesson,
|
|
674
739
|
lessonDiagnostics,
|
|
675
740
|
normalizeLessonId,
|
|
741
|
+
parseRulesFilter,
|
|
676
742
|
renderLesson,
|
|
677
743
|
scaffoldLesson,
|
|
678
744
|
scaffoldTerm
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CurriculumCatalog } from '../curriculum/validation.js';
|
|
2
|
-
import { NotationReferenceInput, AbbreviationDefinitionInput, NotationRegistryInput } from '../reference/types.js';
|
|
2
|
+
import { NotationReferenceInput, AbbreviationDefinitionInput, NotationRegistryInput, LocalNotationDefinitionInput, NotationSuspension } from '../reference/types.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The single path from content files to typed data.
|
|
@@ -19,8 +19,41 @@ import { NotationReferenceInput, AbbreviationDefinitionInput, NotationRegistryIn
|
|
|
19
19
|
* ignoring code fences and inline code, sorted by position.
|
|
20
20
|
*/
|
|
21
21
|
declare function extractNotationReferences(text: string, file: string, kind: NotationReferenceInput['kind'] | undefined): NotationReferenceInput[];
|
|
22
|
+
/**
|
|
23
|
+
* One part's **overview page** — `content/docs/<dir>/index.mdx`, the page the
|
|
24
|
+
* part's own directory URL resolves to. `isLessonSlug` already excludes any
|
|
25
|
+
* `<dir>/index`, so this page is not a chapter: it carries no competencies, no
|
|
26
|
+
* knowledge check, and no float numbers, and nothing in the curriculum graph
|
|
27
|
+
* changes when a course adds one.
|
|
28
|
+
*/
|
|
29
|
+
interface PartOverviewPage {
|
|
30
|
+
readonly dir: string;
|
|
31
|
+
readonly slug: string;
|
|
32
|
+
readonly file: string;
|
|
33
|
+
readonly title: string;
|
|
34
|
+
readonly description?: string;
|
|
35
|
+
/** MDX after the frontmatter — what the S2 gate (`gate-part-pages.ts`) reads. */
|
|
36
|
+
readonly body: string;
|
|
37
|
+
/** 1-based file line `body` starts on, for diagnostic locations. */
|
|
38
|
+
readonly bodyLine: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The overview page of every part that has one, keyed by the part's directory.
|
|
42
|
+
* A part without one is simply absent — overview pages are opt-in, one part at
|
|
43
|
+
* a time.
|
|
44
|
+
*/
|
|
45
|
+
declare function loadPartOverviews(parts: readonly {
|
|
46
|
+
readonly dir: string;
|
|
47
|
+
}[]): PartOverviewPage[];
|
|
22
48
|
declare function loadCurriculumCatalog(): Promise<CurriculumCatalog>;
|
|
23
49
|
declare function loadAbbreviationRegistryInput(): Promise<readonly AbbreviationDefinitionInput[]>;
|
|
50
|
+
/**
|
|
51
|
+
* A lesson's `notation.suspend` (rule N22): decorations that are not
|
|
52
|
+
* operators on this page. A name outside `DECORATION_NAMES`, a decoration
|
|
53
|
+
* suspended twice, and a `notation.local` operator entry for a suspended
|
|
54
|
+
* decoration (the page would contradict itself) each fail the load.
|
|
55
|
+
*/
|
|
56
|
+
declare function notationSuspensions(raw: unknown, localDefinitions: readonly LocalNotationDefinitionInput[], file: string): NotationSuspension[];
|
|
24
57
|
declare function loadNotationRegistryInput(): Promise<NotationRegistryInput>;
|
|
25
58
|
/**
|
|
26
59
|
* Notation frontmatter objects for `remark-notation`'s `definitions` option.
|
|
@@ -68,4 +101,4 @@ declare function notationSourceLocatorGaps(): {
|
|
|
68
101
|
total: number;
|
|
69
102
|
};
|
|
70
103
|
|
|
71
|
-
export { type NotationSpec, extractNotationReferences, loadAbbreviationRegistryInput, loadCurriculumCatalog, loadLessonChecks, loadNotationDefinitions, loadNotationRegistryInput, loadNotationSpecs, loadSourceRecords, notationSourceLocatorGaps };
|
|
104
|
+
export { type NotationSpec, type PartOverviewPage, extractNotationReferences, loadAbbreviationRegistryInput, loadCurriculumCatalog, loadLessonChecks, loadNotationDefinitions, loadNotationRegistryInput, loadNotationSpecs, loadPartOverviews, loadSourceRecords, notationSourceLocatorGaps, notationSuspensions };
|
|
@@ -3,9 +3,14 @@ import { basename, join, relative } from "node:path";
|
|
|
3
3
|
import { parseFrontmatter } from "@astrojs/markdown-remark";
|
|
4
4
|
import { isSubstantiveMeaning } from "../reference/prose.js";
|
|
5
5
|
import { parseEquationRef } from "../reference/equations.mjs";
|
|
6
|
+
import {
|
|
7
|
+
DECORATION_NAMES,
|
|
8
|
+
decorationOfEntry
|
|
9
|
+
} from "../reference/math-glyphs.mjs";
|
|
6
10
|
import { parseKeyedFloatRef } from "../reference/keyed-jsx-floats.mjs";
|
|
7
11
|
import { parseKnowledgeCheckRef } from "../reference/knowledge-checks.mjs";
|
|
8
12
|
import { parseMemoRef } from "../reference/remark-memo.mjs";
|
|
13
|
+
import { parseSectionRef } from "../reference/sections.mjs";
|
|
9
14
|
import { resolveLabel } from "../reference/label.js";
|
|
10
15
|
import { resolveGlosses } from "../reference/gloss.js";
|
|
11
16
|
import {
|
|
@@ -151,7 +156,7 @@ function extractNotationReferences(text, file, kind) {
|
|
|
151
156
|
for (const [pattern, referenceKind] of patterns) {
|
|
152
157
|
for (const match of searchable.matchAll(pattern)) {
|
|
153
158
|
const key = (match[1] ?? "").trim();
|
|
154
|
-
if (parseEquationRef(key) || parseKeyedFloatRef(key, { prefix: "tab" }) || parseKeyedFloatRef(key, { prefix: "fig" }) || parseKeyedFloatRef(key, { prefix: "dia" }) || parseKnowledgeCheckRef(key) || parseMemoRef(key)) {
|
|
159
|
+
if (parseEquationRef(key) || parseKeyedFloatRef(key, { prefix: "tab" }) || parseKeyedFloatRef(key, { prefix: "fig" }) || parseKeyedFloatRef(key, { prefix: "dia" }) || parseKeyedFloatRef(key, { prefix: "ex" }) || parseKnowledgeCheckRef(key) || parseSectionRef(key) || parseMemoRef(key)) {
|
|
155
160
|
continue;
|
|
156
161
|
}
|
|
157
162
|
references.push({
|
|
@@ -184,6 +189,29 @@ function lessonCheckIds(lessonPath) {
|
|
|
184
189
|
const checksPath = lessonPath.replace(/\.mdx?$/, ".checks.yml");
|
|
185
190
|
return existsSync(checksPath) ? parseCheckList(readFileSync(checksPath, "utf8")) : [];
|
|
186
191
|
}
|
|
192
|
+
function loadPartOverviews(parts) {
|
|
193
|
+
const pages = [];
|
|
194
|
+
for (const { dir } of parts) {
|
|
195
|
+
for (const extension of [".mdx", ".md"]) {
|
|
196
|
+
const path = join(CONTENT_ROOT, "docs", dir, `index${extension}`);
|
|
197
|
+
if (!existsSync(path)) continue;
|
|
198
|
+
const { data, file, body, bodyLine } = parseDocument(path);
|
|
199
|
+
const title = typeof data.title === "string" ? data.title : dir;
|
|
200
|
+
const description = typeof data.description === "string" ? data.description : void 0;
|
|
201
|
+
pages.push({
|
|
202
|
+
dir,
|
|
203
|
+
slug: `${dir}/index`,
|
|
204
|
+
file,
|
|
205
|
+
title,
|
|
206
|
+
...description === void 0 ? {} : { description },
|
|
207
|
+
body,
|
|
208
|
+
bodyLine
|
|
209
|
+
});
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return pages;
|
|
214
|
+
}
|
|
187
215
|
function lessonEntries(prerequisitesById) {
|
|
188
216
|
const lessons = [];
|
|
189
217
|
for (const path of filesBelow(join(CONTENT_ROOT, "docs"), [".md", ".mdx"])) {
|
|
@@ -329,6 +357,37 @@ function abbreviationEntries() {
|
|
|
329
357
|
async function loadAbbreviationRegistryInput() {
|
|
330
358
|
return abbreviationEntries();
|
|
331
359
|
}
|
|
360
|
+
function notationSuspensions(raw, localDefinitions, file) {
|
|
361
|
+
if (raw === void 0) return [];
|
|
362
|
+
if (!Array.isArray(raw)) {
|
|
363
|
+
throw new TypeError(`${file} notation.suspend must be an array`);
|
|
364
|
+
}
|
|
365
|
+
const seen = /* @__PURE__ */ new Set();
|
|
366
|
+
return raw.map((item, index) => {
|
|
367
|
+
const at = `${file} notation.suspend[${index}]`;
|
|
368
|
+
const data = record(item, at);
|
|
369
|
+
const operator = string(data.operator, `${at}.operator`).trim();
|
|
370
|
+
if (!DECORATION_NAMES.has(operator)) {
|
|
371
|
+
throw new Error(
|
|
372
|
+
`${at}.operator ${JSON.stringify(operator)} is not a decoration; use one of ${[...DECORATION_NAMES].join(", ")}`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
if (seen.has(operator)) {
|
|
376
|
+
throw new Error(`${at} suspends ${JSON.stringify(operator)} a second time`);
|
|
377
|
+
}
|
|
378
|
+
seen.add(operator);
|
|
379
|
+
const local = localDefinitions.find(
|
|
380
|
+
(definition) => decorationOfEntry(definition.notation) === operator
|
|
381
|
+
);
|
|
382
|
+
if (local) {
|
|
383
|
+
throw new Error(
|
|
384
|
+
`${at} suspends ${JSON.stringify(operator)}, but notation.local entry ${local.key} explains it as an operator (latex ${JSON.stringify(local.notation)}); drop one of them`
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
const reason = optionalString(data.reason, `${at}.reason`);
|
|
388
|
+
return reason === void 0 ? { operator } : { operator, reason: reason.trim() };
|
|
389
|
+
});
|
|
390
|
+
}
|
|
332
391
|
function notationLessonEntries() {
|
|
333
392
|
const lessons = [];
|
|
334
393
|
for (const path of filesBelow(join(CONTENT_ROOT, "docs"), [".md", ".mdx"])) {
|
|
@@ -337,12 +396,14 @@ function notationLessonEntries() {
|
|
|
337
396
|
const { file, data, body, bodyLine } = parseDocument(path);
|
|
338
397
|
const notation = record(data.notation ?? {}, `${file} notation`);
|
|
339
398
|
const local = Array.isArray(notation.local) ? notation.local : [];
|
|
399
|
+
const localDefinitions = local.map(
|
|
400
|
+
(entry, index) => localDefinition(entry, file, index)
|
|
401
|
+
);
|
|
340
402
|
lessons.push({
|
|
341
403
|
lessonId: lessonIdFromSlug(slug),
|
|
342
404
|
status: status(data.editorialStatus, `${file} editorialStatus`),
|
|
343
|
-
localDefinitions
|
|
344
|
-
|
|
345
|
-
),
|
|
405
|
+
localDefinitions,
|
|
406
|
+
suspended: notationSuspensions(notation.suspend, localDefinitions, file),
|
|
346
407
|
references: extractNotationReferences(body, file, void 0),
|
|
347
408
|
body,
|
|
348
409
|
bodyLine,
|
|
@@ -448,6 +509,8 @@ export {
|
|
|
448
509
|
loadNotationDefinitions,
|
|
449
510
|
loadNotationRegistryInput,
|
|
450
511
|
loadNotationSpecs,
|
|
512
|
+
loadPartOverviews,
|
|
451
513
|
loadSourceRecords,
|
|
452
|
-
notationSourceLocatorGaps
|
|
514
|
+
notationSourceLocatorGaps,
|
|
515
|
+
notationSuspensions
|
|
453
516
|
};
|