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.
- package/CHANGELOG.md +1409 -1
- package/README.md +60 -15
- package/dist/compiler/astro.d.ts +6 -1
- package/dist/compiler/cli.d.ts +54 -3
- package/dist/compiler/cli.js +80 -6
- package/dist/compiler/collections.d.ts +35 -2
- package/dist/compiler/collections.js +84 -8
- 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 +14 -1
- package/dist/compiler/logging.js +6 -2
- 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 +21 -11
- package/dist/reference/delimiter-size.js +15 -39
- 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 +69 -34
- package/dist/reference/equations.mjs +90 -44
- 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 +3 -2
- 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 +47 -23
- 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 +44 -6
- package/dist/reference/gate-math.js +63 -10
- 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 +32 -11
- package/dist/reference/gate-prose-notation.js +30 -8
- package/dist/reference/katex-delimiters.d.mts +15 -0
- package/dist/reference/katex-delimiters.mjs +138 -0
- package/dist/reference/katex-options.mjs +4 -0
- 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 +588 -39
- 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 +5 -5
- 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 +24 -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 +1324 -2
- package/docs/authoring/notation.md +616 -344
- 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/docs/katex-bracket-scaling.md +191 -0
- package/package.json +3 -2
- package/src/compiler/cli.ts +139 -6
- package/src/compiler/collections.ts +144 -10
- 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 +21 -4
- 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 +24 -14
- package/src/components/notation/NotationLayer.astro +169 -162
- package/src/components/notation/NotationMath.astro +10 -1
- package/src/components/notation/render-notation-math.ts +111 -10
- package/src/components/reference/FloatRefLayer.astro +485 -423
- package/src/components/starlight/AboutPanel.astro +22 -6
- 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 +40 -61
- package/src/reference/diagrams-validate.ts +17 -1
- package/src/reference/equations-validate.ts +10 -5
- package/src/reference/equations.mjs +90 -44
- 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 +3 -2
- package/src/reference/gate-course-rules.ts +134 -0
- package/src/reference/gate-heading-length.ts +68 -37
- package/src/reference/gate-heading-structure.ts +193 -0
- package/src/reference/gate-math-punctuation.ts +381 -0
- package/src/reference/gate-math.ts +119 -12
- package/src/reference/gate-part-pages.ts +217 -0
- package/src/reference/gate-prose-notation.ts +74 -13
- package/src/reference/katex-delimiters.mjs +138 -0
- package/src/reference/katex-options.mjs +4 -0
- 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 +588 -39
- 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 +17 -32
- 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 +24 -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/src/compiler/manifest.ts
CHANGED
|
@@ -69,6 +69,12 @@ import {
|
|
|
69
69
|
type DiagramDiagnostic,
|
|
70
70
|
type DiagramLabelRecord,
|
|
71
71
|
} from '../reference/diagrams-validate';
|
|
72
|
+
import {
|
|
73
|
+
validateExamples,
|
|
74
|
+
type ExampleDiagnostic,
|
|
75
|
+
type ExampleLabelRecord,
|
|
76
|
+
} from '../reference/examples-validate';
|
|
77
|
+
import { validateFolds, type FoldDiagnostic } from '../reference/folds-validate';
|
|
72
78
|
import {
|
|
73
79
|
validateKnowledgeChecks,
|
|
74
80
|
type KnowledgeCheckDiagnostic,
|
|
@@ -87,8 +93,21 @@ import {
|
|
|
87
93
|
gateProseNotation,
|
|
88
94
|
gateProseNotationInAssessments,
|
|
89
95
|
} from '../reference/gate-prose-notation';
|
|
96
|
+
import {
|
|
97
|
+
gateMathPunctuation,
|
|
98
|
+
gateMathPunctuationInAssessments,
|
|
99
|
+
} from '../reference/gate-math-punctuation';
|
|
90
100
|
import { gateAbbreviations } from '../reference/gate-abbreviations';
|
|
101
|
+
import { gateCourseRules } from '../reference/gate-course-rules';
|
|
91
102
|
import { gateHeadingLength } from '../reference/gate-heading-length';
|
|
103
|
+
import { gateHeadingStructure } from '../reference/gate-heading-structure';
|
|
104
|
+
import { gatePartPages } from '../reference/gate-part-pages';
|
|
105
|
+
import {
|
|
106
|
+
scanSectionHeadings,
|
|
107
|
+
scanTitledBlocks,
|
|
108
|
+
} from '../reference/sections.mjs';
|
|
109
|
+
import { knowledgeCheckAnchorId } from '../reference/knowledge-checks.mjs';
|
|
110
|
+
import { validateSectionRefs } from '../reference/sections-validate';
|
|
92
111
|
import {
|
|
93
112
|
splitMixedContent,
|
|
94
113
|
type ContentSegment,
|
|
@@ -109,12 +128,30 @@ import type {
|
|
|
109
128
|
} from '../reference/types';
|
|
110
129
|
import {
|
|
111
130
|
coursePartsOf,
|
|
131
|
+
normalizeBlockLabels,
|
|
112
132
|
normalizeLessonExports,
|
|
113
|
-
|
|
133
|
+
normalizeDisclosure,
|
|
134
|
+
normalizeNumbering,
|
|
135
|
+
type BlockLabels,
|
|
114
136
|
type CourseConfig,
|
|
115
137
|
type NormalizedLessonExports,
|
|
116
|
-
type
|
|
138
|
+
type NormalizedDisclosure,
|
|
139
|
+
type NormalizedNumbering,
|
|
117
140
|
} from './course-config';
|
|
141
|
+
import {
|
|
142
|
+
disabledCodes,
|
|
143
|
+
dropDisabled,
|
|
144
|
+
partPageLimits,
|
|
145
|
+
resolveRules,
|
|
146
|
+
rulesSnapshot,
|
|
147
|
+
type ConfigDiagnostic,
|
|
148
|
+
type ManifestRules,
|
|
149
|
+
} from '../rules/settings';
|
|
150
|
+
import {
|
|
151
|
+
applyWaivers,
|
|
152
|
+
collectWaivers,
|
|
153
|
+
type WaiverDiagnostic,
|
|
154
|
+
} from '../rules/waivers';
|
|
118
155
|
import {
|
|
119
156
|
resolveKnowledgeVersion,
|
|
120
157
|
type KnowledgeVersionDiagnostic,
|
|
@@ -125,6 +162,7 @@ import {
|
|
|
125
162
|
loadNotationDefinitions,
|
|
126
163
|
loadNotationRegistryInput,
|
|
127
164
|
loadNotationSpecs,
|
|
165
|
+
loadPartOverviews,
|
|
128
166
|
loadSourceRecords,
|
|
129
167
|
} from './collections';
|
|
130
168
|
import {
|
|
@@ -190,8 +228,70 @@ import {
|
|
|
190
228
|
* optional advice. Unused keys/definitions and restructuring candidates move
|
|
191
229
|
* from `warning` to `info`; their diagnostic codes and container fields stay
|
|
192
230
|
* unchanged.
|
|
231
|
+
* v17 (part pages, additive): `parts` — every part with its chapters in
|
|
232
|
+
* reading order and, where the course authored one, its overview page. A part
|
|
233
|
+
* with an overview page also gains a leading `Overview` item in its
|
|
234
|
+
* `sidebar` group, so `sidebar[].items` is now a mixed list of lesson slugs
|
|
235
|
+
* and `{ label, link, attrs? }` entries rather than one kind per group.
|
|
236
|
+
* Also `lessons[].studyMinutes` from the optional frontmatter field, and
|
|
237
|
+
* `parts[].studyMinutes` totalling it across a part whose chapters all
|
|
238
|
+
* state one.
|
|
239
|
+
*
|
|
240
|
+
* v18 (rule settings, additive): `rules` — the course's rule switches
|
|
241
|
+
* (`disabled`) and every rule's effective settings; `diagnostics.config` —
|
|
242
|
+
* findings about the course settings themselves (a deprecated top-level
|
|
243
|
+
* `operators` / `romanLabels` / `abbreviations` block, a block for a retired
|
|
244
|
+
* rule), from `resolveRules`. A diagnostic owned by a disabled rule is not
|
|
245
|
+
* published at all; one covered by a per-place waiver
|
|
246
|
+
* (`{/* explico-allow N9: reason *\/}`) is dropped too, and
|
|
247
|
+
* `diagnostics.waivers` reports the waivers themselves (malformed, invalid,
|
|
248
|
+
* unused). Every math-gate finding now carries a `code`
|
|
249
|
+
* (`prose-notation`, `abbreviation-unexplained`, `title-length`,
|
|
250
|
+
* `unresolved-glyph`, `math-compile-error`, or the resolver's own).
|
|
251
|
+
*
|
|
252
|
+
* v19 (course rules, additive): `rules.course` — the course's own `X` rules
|
|
253
|
+
* from `courseRules` in the settings, validated, in file order, so
|
|
254
|
+
* `build/rules-in-effect.md` and `content rules` list them beside the engine's.
|
|
255
|
+
* A finding from one is in `diagnostics.math` with the rule's ID as its `code`.
|
|
256
|
+
*
|
|
257
|
+
* v20 (outline numbering): `numbering` — the course's resolved
|
|
258
|
+
* `numbering` settings; `lessons[].headings` — every top-level heading with
|
|
259
|
+
* its anchor, text, level and, down to `numbering.sections.depth`, its
|
|
260
|
+
* `‹part›.‹chapter›.‹section›…` number; `lessons[].numbering.prefix` — the
|
|
261
|
+
* float-number prefix. Under the default `numbering.floats: "chapter"` that
|
|
262
|
+
* prefix is `‹part›.‹chapter›` and every per-kind offset is 0, so a float
|
|
263
|
+
* number is `2.2.1` where it used to be `2.1`. A `[[sec-…]]` that names no
|
|
264
|
+
* heading is a `sec-ref-resolves` error in `diagnostics.math`.
|
|
265
|
+
*
|
|
266
|
+
* v21 (one caption pair): `lessons[].equations` / `.tables` / `.figures` /
|
|
267
|
+
* `.diagrams` entries, and the `labels` of `equations` / `tables` / `figures`
|
|
268
|
+
* / `diagrams`, carry the float's `short` caption (an equation's
|
|
269
|
+
* `\caption{…}`, or the `short` prop) and, for a JSX float, its long
|
|
270
|
+
* `caption`, each when stated as a literal. `diagnostics.figures` /
|
|
271
|
+
* `diagnostics.diagrams` gain `fig-removed-prop` / `dia-removed-prop`.
|
|
272
|
+
*
|
|
273
|
+
* v22 (one collapse model): `disclosure` replaces `disclosureDefaults` — the
|
|
274
|
+
* course's whole `disclosure` settings block with the engine defaults applied
|
|
275
|
+
* (`NormalizedDisclosure`): `sections` / `subsections` / `knowledgeChecks`
|
|
276
|
+
* as `{ collapsible, defaultOpen }`, `notation` / `references` / `memos` /
|
|
277
|
+
* `figures` / `diagrams` / `workedExamples` as `{ defaultOpen }`, and
|
|
278
|
+
* `tables.truncateAfter`.
|
|
279
|
+
*
|
|
280
|
+
* v23 (kind badges): a worked-example set is a numbered kind of its own —
|
|
281
|
+
* `examples` (same shape as `figures`), `lessons[].examples`,
|
|
282
|
+
* `lessons[].numbering.examples` and `diagnostics.examples` (`ex-…` codes,
|
|
283
|
+
* `ex-missing-prop` among them). `lessons[].knowledgeChecks` entries carry
|
|
284
|
+
* the check's `title`; `lessons[].titledBlocks` lists every check and example
|
|
285
|
+
* set with the anchor and title of the `<h2>` it draws and the heading it
|
|
286
|
+
* follows; `blockLabels` is the course's resolved badge form.
|
|
287
|
+
*
|
|
288
|
+
* v24 (figures stop compacting; `<Fold>`): `disclosure` loses `diagrams` —
|
|
289
|
+
* a diagram no longer folds by itself — and gains `folds`, the first-visit
|
|
290
|
+
* state of a `<Fold>`; `disclosure.figures` now says whether a lab's tools
|
|
291
|
+
* start open; `diagnostics.folds` holds `fold-unnamed`
|
|
292
|
+
* (docs/plans/figures-and-short-captions.md, Parts 1–2).
|
|
193
293
|
*/
|
|
194
|
-
export const MANIFEST_SCHEMA_VERSION =
|
|
294
|
+
export const MANIFEST_SCHEMA_VERSION = 24;
|
|
195
295
|
|
|
196
296
|
const REPOSITORY_ROOT = process.cwd();
|
|
197
297
|
// Content is the top-level `content/` folder; the build output is `build/`
|
|
@@ -275,74 +375,121 @@ export interface ManifestLessonNotation {
|
|
|
275
375
|
readonly formulaScope: readonly GlyphScopeEntry[];
|
|
276
376
|
}
|
|
277
377
|
|
|
378
|
+
/**
|
|
379
|
+
* One keyed float of a lesson (v21): its key and number, and its caption pair
|
|
380
|
+
* — `short` (an equation's `\caption{…}`, or the `short` prop) and, for a
|
|
381
|
+
* `<Table>` / `<Figure>` / `<Diagram>`, the long `caption`. Each is present
|
|
382
|
+
* only when the source states it as a literal.
|
|
383
|
+
*/
|
|
384
|
+
export interface ManifestLessonFloat {
|
|
385
|
+
readonly key: string;
|
|
386
|
+
readonly number: string;
|
|
387
|
+
readonly short?: string;
|
|
388
|
+
readonly caption?: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A block that draws a heading of its own where its tag stands (v23): a
|
|
393
|
+
* knowledge check (`<AssessmentSet />`) or a worked-example set
|
|
394
|
+
* (`<CompactExamples>`). `anchor` is the heading's id, `title` the author's
|
|
395
|
+
* topical title, `after` the slug of the top-level heading it follows.
|
|
396
|
+
*/
|
|
397
|
+
export interface ManifestTitledBlock {
|
|
398
|
+
readonly kind: 'check' | 'example';
|
|
399
|
+
readonly key: string;
|
|
400
|
+
readonly anchor: string;
|
|
401
|
+
readonly title: string;
|
|
402
|
+
readonly after?: string;
|
|
403
|
+
}
|
|
404
|
+
|
|
278
405
|
export interface ManifestLesson {
|
|
279
406
|
readonly id: string;
|
|
280
407
|
/** Docs-loader slug, e.g. `bonds/price-yield-relationship`. */
|
|
281
408
|
readonly slug: string;
|
|
282
409
|
/**
|
|
283
410
|
* The 1-based ordinal of the **part** this lesson sits in — its sidebar
|
|
284
|
-
* group's position in `courseConfig.parts`. It is the number
|
|
285
|
-
*
|
|
286
|
-
* the page
|
|
287
|
-
* `docs/authoring/structure.md`.
|
|
411
|
+
* group's position in `courseConfig.parts`. It is the first number of every
|
|
412
|
+
* section, equation, table, figure, diagram, and knowledge-check number on
|
|
413
|
+
* the page. See `docs/authoring/structure.md`.
|
|
288
414
|
*/
|
|
289
415
|
readonly part: number;
|
|
290
416
|
/**
|
|
291
417
|
* The lesson's 1-based ordinal **within its part** (merged track order, then
|
|
292
|
-
* any unranked lessons by slug) — its chapter number
|
|
293
|
-
*
|
|
418
|
+
* any unranked lessons by slug) — its chapter number, the second number of
|
|
419
|
+
* every section number (`1.2.3`) and, under the default
|
|
420
|
+
* `numbering.floats: "chapter"`, of every float number (`(1.2.1)`).
|
|
294
421
|
*/
|
|
295
422
|
readonly chapter: number;
|
|
296
423
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
424
|
+
* The float numbers' `prefix` — `‹part›.‹chapter›` under
|
|
425
|
+
* `numbering.floats: "chapter"`, `‹part›` under `"part"` — and, per kind,
|
|
426
|
+
* how many floats of that kind precede this lesson in that scope: always 0
|
|
427
|
+
* for `chapter`, the earlier chapters' count for `part`, whose sequence
|
|
428
|
+
* runs unbroken across the part. A float is `‹prefix›.‹offset + n›`.
|
|
300
429
|
*/
|
|
301
430
|
readonly numbering: {
|
|
431
|
+
readonly prefix: string;
|
|
302
432
|
readonly equations: number;
|
|
303
433
|
readonly tables: number;
|
|
304
434
|
readonly figures: number;
|
|
305
435
|
readonly diagrams: number;
|
|
306
436
|
readonly checks: number;
|
|
437
|
+
readonly examples: number;
|
|
307
438
|
};
|
|
439
|
+
/**
|
|
440
|
+
* Every top-level heading in document order (`sections.mjs`): its anchor
|
|
441
|
+
* (`slug`, which the page's heading is given, and which `[[sec-slug]]`
|
|
442
|
+
* names), its text and level, and — for a `##` to the course's
|
|
443
|
+
* `numbering.sections.depth` — its outline number, `‹part›.‹chapter›.‹s›…`.
|
|
444
|
+
*/
|
|
445
|
+
readonly headings: readonly {
|
|
446
|
+
readonly slug: string;
|
|
447
|
+
readonly text: string;
|
|
448
|
+
readonly level: number;
|
|
449
|
+
readonly number?: string;
|
|
450
|
+
}[];
|
|
308
451
|
readonly file: string;
|
|
309
452
|
readonly title: string;
|
|
310
453
|
readonly description: string;
|
|
454
|
+
/** Authored reader-facing estimate; `40` and `[30, 40]` both land here. */
|
|
455
|
+
readonly studyMinutes?: { readonly min: number; readonly max: number };
|
|
311
456
|
readonly status: EditorialStatus;
|
|
312
457
|
/** Ordered — the curriculum contract. */
|
|
313
458
|
readonly teaches: readonly string[];
|
|
314
459
|
readonly requires: readonly string[];
|
|
315
460
|
readonly assumptions: readonly string[];
|
|
316
461
|
readonly assessments: readonly string[];
|
|
317
|
-
/**
|
|
462
|
+
/**
|
|
463
|
+
* Numbered knowledge checks from `assessments`, in `.checks.yml` order,
|
|
464
|
+
* each with the `title` its assessment file gives it (v23) — the topic its
|
|
465
|
+
* heading shows after the engine's badge.
|
|
466
|
+
*/
|
|
318
467
|
readonly knowledgeChecks: readonly {
|
|
319
468
|
readonly key: string;
|
|
320
469
|
readonly number: string;
|
|
470
|
+
readonly title?: string;
|
|
321
471
|
}[];
|
|
472
|
+
/**
|
|
473
|
+
* The blocks that draw an `<h2>` of their own (v23): each knowledge check
|
|
474
|
+
* and worked-example set, in document order, with that heading's `anchor`
|
|
475
|
+
* and `title` and `after`, the slug of the top-level heading it follows
|
|
476
|
+
* (absent before the first) — where "On this page" lists it.
|
|
477
|
+
*/
|
|
478
|
+
readonly titledBlocks: readonly ManifestTitledBlock[];
|
|
322
479
|
readonly sources: readonly string[];
|
|
323
480
|
readonly citations: readonly ManifestCitation[];
|
|
324
481
|
/** Competency prerequisite edges this lesson introduces. */
|
|
325
482
|
readonly prereqEdges: readonly PrereqEdge[];
|
|
326
483
|
/** Labelled display equations in appearance order (D7). */
|
|
327
|
-
readonly equations: readonly
|
|
328
|
-
readonly key: string;
|
|
329
|
-
readonly number: string;
|
|
330
|
-
}[];
|
|
484
|
+
readonly equations: readonly ManifestLessonFloat[];
|
|
331
485
|
/** Keyed `<Table>` elements in appearance order. */
|
|
332
|
-
readonly tables: readonly
|
|
333
|
-
readonly key: string;
|
|
334
|
-
readonly number: string;
|
|
335
|
-
}[];
|
|
486
|
+
readonly tables: readonly ManifestLessonFloat[];
|
|
336
487
|
/** Keyed `<Figure>` elements in appearance order. */
|
|
337
|
-
readonly figures: readonly
|
|
338
|
-
readonly key: string;
|
|
339
|
-
readonly number: string;
|
|
340
|
-
}[];
|
|
488
|
+
readonly figures: readonly ManifestLessonFloat[];
|
|
341
489
|
/** Keyed `<Diagram>` elements in appearance order. */
|
|
342
|
-
readonly diagrams: readonly
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}[];
|
|
490
|
+
readonly diagrams: readonly ManifestLessonFloat[];
|
|
491
|
+
/** Keyed `<CompactExamples>` sets in appearance order; `short` is the set's title (v23). */
|
|
492
|
+
readonly examples: readonly ManifestLessonFloat[];
|
|
346
493
|
readonly notation: {
|
|
347
494
|
readonly bindings: readonly {
|
|
348
495
|
readonly key: string;
|
|
@@ -391,12 +538,46 @@ export interface ManifestAssessmentItemContent {
|
|
|
391
538
|
readonly explanationSegments: readonly ContentSegment[];
|
|
392
539
|
}
|
|
393
540
|
|
|
541
|
+
/**
|
|
542
|
+
* One **part** (v17) — a sidebar group and the directory its chapters live in,
|
|
543
|
+
* with its chapters in reading order and its overview page when the course
|
|
544
|
+
* authored one at `content/docs/<dir>/index.mdx`.
|
|
545
|
+
*
|
|
546
|
+
* `link` is where the directory URL resolves; without an `overview` that URL
|
|
547
|
+
* has no page behind it, which is exactly the 404 a part-level page removes.
|
|
548
|
+
*/
|
|
549
|
+
export interface ManifestPart {
|
|
550
|
+
readonly dir: string;
|
|
551
|
+
readonly label: string;
|
|
552
|
+
/** 1-based position in `courseConfig.parts` — the float-number prefix. */
|
|
553
|
+
readonly ordinal: number;
|
|
554
|
+
/** Base-relative href of the part's own page, `/<dir>/`. */
|
|
555
|
+
readonly link: string;
|
|
556
|
+
/** Lesson ids in chapter order. */
|
|
557
|
+
readonly lessons: readonly string[];
|
|
558
|
+
/**
|
|
559
|
+
* The part's total study time — present only when **every** chapter in it
|
|
560
|
+
* states one, so a half-annotated part reports the chapters it knows and no
|
|
561
|
+
* misleading sum.
|
|
562
|
+
*/
|
|
563
|
+
readonly studyMinutes?: { readonly min: number; readonly max: number };
|
|
564
|
+
readonly overview?: {
|
|
565
|
+
readonly title: string;
|
|
566
|
+
readonly file: string;
|
|
567
|
+
readonly description?: string;
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
394
571
|
export interface Manifest {
|
|
395
572
|
readonly schemaVersion: number;
|
|
396
573
|
/** Normalized build/UI settings for opt-in per-lesson exports. */
|
|
397
574
|
readonly lessonExports: NormalizedLessonExports;
|
|
398
|
-
/**
|
|
399
|
-
readonly
|
|
575
|
+
/** Every collapse default, engine defaults applied (`CourseConfig.disclosure`). */
|
|
576
|
+
readonly disclosure: NormalizedDisclosure;
|
|
577
|
+
/** Outline and float numbering, defaults applied (`CourseConfig.numbering`). */
|
|
578
|
+
readonly numbering: NormalizedNumbering;
|
|
579
|
+
/** How a check's and an example set's heading names its kind (`CourseConfig.blockLabels`). */
|
|
580
|
+
readonly blockLabels: BlockLabels;
|
|
400
581
|
/** Reader-facing identity + versions (the `[?]` About panel). */
|
|
401
582
|
readonly about: ManifestAbout;
|
|
402
583
|
readonly notation: {
|
|
@@ -413,6 +594,8 @@ export interface Manifest {
|
|
|
413
594
|
/** Abbreviations table (N14), for `remarkAbbreviations`. Ordered by key. */
|
|
414
595
|
readonly abbreviations: readonly Record<string, unknown>[];
|
|
415
596
|
readonly sidebar: readonly SidebarGroup[];
|
|
597
|
+
/** The course's parts in config order, with their chapters and overview pages. */
|
|
598
|
+
readonly parts: readonly ManifestPart[];
|
|
416
599
|
readonly lessons: readonly ManifestLesson[];
|
|
417
600
|
/** Full competency prerequisite graph. */
|
|
418
601
|
readonly prereqEdges: readonly PrereqEdge[];
|
|
@@ -442,6 +625,11 @@ export interface Manifest {
|
|
|
442
625
|
readonly labels: readonly KnowledgeCheckLabelRecord[];
|
|
443
626
|
readonly numbersBySlug: Record<string, Record<string, string>>;
|
|
444
627
|
};
|
|
628
|
+
/** Keyed-float identity for `<CompactExamples>` — same shape as `figures` (v23). */
|
|
629
|
+
readonly examples: {
|
|
630
|
+
readonly labels: readonly ExampleLabelRecord[];
|
|
631
|
+
readonly numbersBySlug: Record<string, Record<string, string>>;
|
|
632
|
+
};
|
|
445
633
|
/**
|
|
446
634
|
* Every assessment item's `prompt` / `explanation`, pre-split into
|
|
447
635
|
* text/math segments (v8). `AssessmentSet.astro` filters this by
|
|
@@ -452,6 +640,13 @@ export interface Manifest {
|
|
|
452
640
|
* lesson's scope can resolve its glyphs differently.
|
|
453
641
|
*/
|
|
454
642
|
readonly assessmentContent: readonly ManifestAssessmentItemContent[];
|
|
643
|
+
/**
|
|
644
|
+
* The course's rule switches and settings (`CourseConfig.rules`, resolved
|
|
645
|
+
* against `src/rules/catalog.ts`). `disabled` names the rules whose
|
|
646
|
+
* diagnostics are withheld below; `settings` is every rule's effective
|
|
647
|
+
* values, defaults applied.
|
|
648
|
+
*/
|
|
649
|
+
readonly rules: ManifestRules;
|
|
455
650
|
readonly diagnostics: {
|
|
456
651
|
readonly curriculum: readonly CurriculumIssue[];
|
|
457
652
|
readonly notation: readonly NotationDiagnostic[];
|
|
@@ -471,12 +666,20 @@ export interface Manifest {
|
|
|
471
666
|
readonly diagrams: readonly DiagramDiagnostic[];
|
|
472
667
|
/** Knowledge-check identity and `[[check-…]]` reference checks. */
|
|
473
668
|
readonly checks: readonly KnowledgeCheckDiagnostic[];
|
|
669
|
+
/** `<CompactExamples>` identity checks — the keyed-float codes, `ex-` prefixed, plus `ex-missing-prop`. */
|
|
670
|
+
readonly examples: readonly ExampleDiagnostic[];
|
|
671
|
+
/** `<Fold>` checks: `fold-unnamed`, a fold with no `label` and no numbered float to name its bar by. */
|
|
672
|
+
readonly folds: readonly FoldDiagnostic[];
|
|
474
673
|
/**
|
|
475
674
|
* A raw Markdown table, a raw HTML `<table>`, or an Explico `<Diagram>`
|
|
476
675
|
* that is unkeyed or nested outside `<Table>`/`<Figure>` — invisible to
|
|
477
676
|
* keyed-float validation above. Warnings only.
|
|
478
677
|
*/
|
|
479
678
|
readonly rawFloats: readonly RawFloatDiagnostic[];
|
|
679
|
+
/** Findings about `CourseConfig.rules` and the deprecated blocks it replaces. Warnings only. */
|
|
680
|
+
readonly config: readonly ConfigDiagnostic[];
|
|
681
|
+
/** Per-place waivers that are malformed, name an unwaivable rule, or silenced nothing. */
|
|
682
|
+
readonly waivers: readonly WaiverDiagnostic[];
|
|
480
683
|
};
|
|
481
684
|
readonly hashes: {
|
|
482
685
|
/** `sha256` of every content source file, keyed by repo-relative path. */
|
|
@@ -617,13 +820,45 @@ function lessonNotationBundle(
|
|
|
617
820
|
};
|
|
618
821
|
}
|
|
619
822
|
|
|
620
|
-
/**
|
|
823
|
+
/**
|
|
824
|
+
* `studyMinutes: 40` and `studyMinutes: [30, 40]` are the same estimate; the
|
|
825
|
+
* manifest carries one shape so a total is a sum of two numbers.
|
|
826
|
+
*/
|
|
827
|
+
function studyMinutesRange(
|
|
828
|
+
value: unknown,
|
|
829
|
+
): { min: number; max: number } | undefined {
|
|
830
|
+
if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
|
|
831
|
+
return { min: value, max: value };
|
|
832
|
+
}
|
|
833
|
+
if (
|
|
834
|
+
Array.isArray(value) &&
|
|
835
|
+
value.length === 2 &&
|
|
836
|
+
value.every((entry) => typeof entry === 'number' && entry > 0)
|
|
837
|
+
) {
|
|
838
|
+
const [min, max] = value as [number, number];
|
|
839
|
+
return min <= max ? { min, max } : { min: max, max: min };
|
|
840
|
+
}
|
|
841
|
+
return undefined;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/** `title` / `description` / `studyMinutes` from a lesson's raw docs frontmatter. */
|
|
621
845
|
function lessonFrontmatterById(): Map<
|
|
622
846
|
string,
|
|
623
|
-
{
|
|
847
|
+
{
|
|
848
|
+
title: string;
|
|
849
|
+
description: string;
|
|
850
|
+
studyMinutes?: { min: number; max: number };
|
|
851
|
+
}
|
|
624
852
|
> {
|
|
625
853
|
const base = join(CONTENT_ROOT, 'docs');
|
|
626
|
-
const result = new Map<
|
|
854
|
+
const result = new Map<
|
|
855
|
+
string,
|
|
856
|
+
{
|
|
857
|
+
title: string;
|
|
858
|
+
description: string;
|
|
859
|
+
studyMinutes?: { min: number; max: number };
|
|
860
|
+
}
|
|
861
|
+
>();
|
|
627
862
|
const walk = (directory: string): void => {
|
|
628
863
|
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
629
864
|
const path = join(directory, entry.name);
|
|
@@ -637,10 +872,12 @@ function lessonFrontmatterById(): Map<
|
|
|
637
872
|
const id = slug.replace(/\.(md|mdx)$/, '').replace(/\//g, '.');
|
|
638
873
|
const data = (parseFrontmatter(readFileSync(path, 'utf8')).frontmatter ??
|
|
639
874
|
{}) as Record<string, unknown>;
|
|
875
|
+
const studyMinutes = studyMinutesRange(data.studyMinutes);
|
|
640
876
|
result.set(id, {
|
|
641
877
|
title: typeof data.title === 'string' ? data.title : id,
|
|
642
878
|
description:
|
|
643
879
|
typeof data.description === 'string' ? data.description : '',
|
|
880
|
+
...(studyMinutes === undefined ? {} : { studyMinutes }),
|
|
644
881
|
});
|
|
645
882
|
}
|
|
646
883
|
};
|
|
@@ -672,6 +909,16 @@ export async function compileManifest(
|
|
|
672
909
|
);
|
|
673
910
|
}
|
|
674
911
|
|
|
912
|
+
// Every rule switch and setting, validated against the catalog. Throws on
|
|
913
|
+
// a wrong ID, key, or value — before any gate runs with it.
|
|
914
|
+
const rules = resolveRules(courseConfig);
|
|
915
|
+
// Codes a disabled rule owns — filtered out of every diagnostics group
|
|
916
|
+
// below; the whole-rule gates are skipped at their call site as well.
|
|
917
|
+
const off = disabledCodes(rules);
|
|
918
|
+
// Throws on a bad `numbering` or `blockLabels` value, like `resolveRules` above.
|
|
919
|
+
const numberingSettings = normalizeNumbering(courseConfig);
|
|
920
|
+
const blockLabels = normalizeBlockLabels(courseConfig);
|
|
921
|
+
|
|
675
922
|
const [catalog, notationInput, abbreviationsInput] = await Promise.all([
|
|
676
923
|
loadCurriculumCatalog(),
|
|
677
924
|
loadNotationRegistryInput(),
|
|
@@ -697,11 +944,16 @@ export async function compileManifest(
|
|
|
697
944
|
|
|
698
945
|
const assessmentsInput = catalog.assessments as unknown as {
|
|
699
946
|
id: string;
|
|
947
|
+
title?: string;
|
|
700
948
|
items?: { id?: string; prompt?: string; explanation?: string }[];
|
|
701
949
|
}[];
|
|
702
950
|
|
|
703
951
|
const curriculumIssues = validateCurriculum(catalog);
|
|
704
952
|
const alignmentIssues = validateNotationAlignment(registry, catalog);
|
|
953
|
+
const mathEndAbbreviations = {
|
|
954
|
+
allow: rules.strings('N12', 'allow'),
|
|
955
|
+
deny: rules.strings('N12', 'deny'),
|
|
956
|
+
};
|
|
705
957
|
const mathIssues = [
|
|
706
958
|
...gateContentMath({
|
|
707
959
|
notationInput,
|
|
@@ -711,14 +963,42 @@ export async function compileManifest(
|
|
|
711
963
|
assessmentIds: lesson.assessments,
|
|
712
964
|
})),
|
|
713
965
|
}),
|
|
714
|
-
...
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
966
|
+
...(rules.isEnabled('N9')
|
|
967
|
+
? [
|
|
968
|
+
...gateProseNotation(notationInput.lessons, {
|
|
969
|
+
allowSpelledUnits: rules.strings('N9', 'allow'),
|
|
970
|
+
}),
|
|
971
|
+
...gateProseNotationInAssessments(assessmentsInput, {
|
|
972
|
+
allowSpelledUnits: rules.strings('N9', 'allow'),
|
|
973
|
+
}),
|
|
974
|
+
]
|
|
975
|
+
: []),
|
|
976
|
+
...(rules.isEnabled('N12')
|
|
977
|
+
? [
|
|
978
|
+
...gateMathPunctuation(notationInput.lessons, mathEndAbbreviations),
|
|
979
|
+
...gateMathPunctuationInAssessments(assessmentsInput, mathEndAbbreviations),
|
|
980
|
+
]
|
|
981
|
+
: []),
|
|
982
|
+
...(rules.isEnabled('N14')
|
|
983
|
+
? gateAbbreviations({
|
|
984
|
+
notationInput,
|
|
985
|
+
abbreviations: abbreviationsInput,
|
|
986
|
+
courseAbbreviations: rules.settings('N14'),
|
|
987
|
+
})
|
|
988
|
+
: []),
|
|
989
|
+
...(rules.isEnabled('S1')
|
|
990
|
+
? gateHeadingLength(notationInput.lessons, {
|
|
991
|
+
maxLength: rules.number('S1', 'maxLength'),
|
|
992
|
+
})
|
|
993
|
+
: []),
|
|
994
|
+
...gateHeadingStructure(notationInput.lessons, {
|
|
995
|
+
levels: rules.isEnabled('S6'),
|
|
996
|
+
adjacency: rules.isEnabled('S7'),
|
|
720
997
|
}),
|
|
721
|
-
|
|
998
|
+
// The course's own rules (`courseRules`): one pass for every enabled `X`
|
|
999
|
+
// rule that carries a `forbid` pattern. A disabled one, and a guide rule
|
|
1000
|
+
// with no pattern, do no work here.
|
|
1001
|
+
...gateCourseRules(notationInput.lessons, rules.course),
|
|
722
1002
|
];
|
|
723
1003
|
|
|
724
1004
|
// Pre-render every assessment `prompt` / `explanation` into text/math
|
|
@@ -780,20 +1060,60 @@ export async function compileManifest(
|
|
|
780
1060
|
const lessonSlugs = [...notationInput.lessons]
|
|
781
1061
|
.map((lesson) => lesson.lessonId.replace(/\./g, '/'))
|
|
782
1062
|
.sort();
|
|
1063
|
+
const configuredParts = coursePartsOf(courseConfig);
|
|
1064
|
+
const overviewPages = loadPartOverviews(configuredParts);
|
|
1065
|
+
const overviewByDir = new Map(overviewPages.map((page) => [page.dir, page]));
|
|
1066
|
+
// S2: every authored part page carries its bridge and scope paragraphs.
|
|
1067
|
+
if (rules.isEnabled('S2')) {
|
|
1068
|
+
mathIssues.push(
|
|
1069
|
+
...gatePartPages(
|
|
1070
|
+
overviewPages.map((page) => ({
|
|
1071
|
+
...page,
|
|
1072
|
+
ordinal: configuredParts.findIndex((part) => part.dir === page.dir) + 1,
|
|
1073
|
+
})),
|
|
1074
|
+
partPageLimits(rules),
|
|
1075
|
+
),
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
// Per-place waivers: drop the located findings each one covers, and
|
|
1079
|
+
// report the waivers themselves — a stale one is a warning, a bad one an
|
|
1080
|
+
// error. Only lesson bodies are scanned; a part page has no waivable rule.
|
|
1081
|
+
const waiverDiagnostics: WaiverDiagnostic[] = [];
|
|
1082
|
+
const waiverRules = { courseRules: rules.course };
|
|
1083
|
+
const waivers = notationInput.lessons.flatMap((lesson) => {
|
|
1084
|
+
const collected = collectWaivers(lesson, waiverRules);
|
|
1085
|
+
waiverDiagnostics.push(...collected.diagnostics);
|
|
1086
|
+
return collected.waivers;
|
|
1087
|
+
});
|
|
1088
|
+
const waived = applyWaivers(mathIssues, waivers, waiverRules);
|
|
1089
|
+
mathIssues.splice(0, mathIssues.length, ...waived.kept);
|
|
1090
|
+
waiverDiagnostics.push(...waived.unused);
|
|
1091
|
+
|
|
783
1092
|
const sidebar = buildSidebar(
|
|
784
1093
|
catalog.tracks.map((track) => ({ id: track.id, lessons: track.lessons })),
|
|
785
1094
|
lessonSlugs,
|
|
786
|
-
|
|
1095
|
+
configuredParts.map((part) => ({
|
|
1096
|
+
...part,
|
|
1097
|
+
...(overviewByDir.has(part.dir)
|
|
1098
|
+
? { overviewLink: `/${part.dir}/` }
|
|
1099
|
+
: {}),
|
|
1100
|
+
})),
|
|
1101
|
+
{
|
|
1102
|
+
floatIndex: ['.mdx', '.md'].some((extension) =>
|
|
1103
|
+
existsSync(join(CONTENT_ROOT, 'docs', `figures-and-tables${extension}`)),
|
|
1104
|
+
),
|
|
1105
|
+
},
|
|
787
1106
|
);
|
|
788
1107
|
|
|
789
1108
|
// Part and chapter, read straight off the sidebar so there is one
|
|
790
1109
|
// lesson-ordering source and not two: a part is a sidebar group (parts in
|
|
791
1110
|
// config order), a chapter is a lesson's position inside its part (merged
|
|
792
|
-
// track order, then slug).
|
|
793
|
-
//
|
|
794
|
-
//
|
|
795
|
-
//
|
|
796
|
-
//
|
|
1111
|
+
// track order, then slug). Both prefix every section number (`1.2.3`).
|
|
1112
|
+
// A float number is `‹prefix›.‹n›`, each kind counting on its own: under
|
|
1113
|
+
// `numbering.floats: "chapter"` the prefix is `‹part›.‹chapter›` and `n`
|
|
1114
|
+
// restarts in every chapter; under `"part"` the prefix is the part alone
|
|
1115
|
+
// and `n` runs on across its chapters, so every lesson also needs the
|
|
1116
|
+
// running count that precedes it. See `docs/authoring/structure.md`.
|
|
797
1117
|
const bodyByLessonId = new Map(
|
|
798
1118
|
notationInput.lessons.map((lesson) => [lesson.lessonId, lesson.body]),
|
|
799
1119
|
);
|
|
@@ -802,15 +1122,10 @@ export async function compileManifest(
|
|
|
802
1122
|
{
|
|
803
1123
|
part: number;
|
|
804
1124
|
chapter: number;
|
|
805
|
-
numbering:
|
|
806
|
-
equations: number;
|
|
807
|
-
tables: number;
|
|
808
|
-
figures: number;
|
|
809
|
-
diagrams: number;
|
|
810
|
-
checks: number;
|
|
811
|
-
};
|
|
1125
|
+
numbering: ManifestLesson['numbering'];
|
|
812
1126
|
}
|
|
813
1127
|
>();
|
|
1128
|
+
const chapterScoped = numberingSettings.floats === 'chapter';
|
|
814
1129
|
let partCursor = 0;
|
|
815
1130
|
for (const group of sidebar) {
|
|
816
1131
|
const lessonIds = group.items
|
|
@@ -818,32 +1133,122 @@ export async function compileManifest(
|
|
|
818
1133
|
.map(lessonIdFromSlug);
|
|
819
1134
|
if (lessonIds.length === 0) continue; // the static Reference group
|
|
820
1135
|
partCursor += 1;
|
|
821
|
-
// Running totals for this part, advanced one chapter at a time
|
|
1136
|
+
// Running totals for this part, advanced one chapter at a time; they
|
|
1137
|
+
// only reach a number under the part scope.
|
|
822
1138
|
const used = {
|
|
823
1139
|
equations: 0,
|
|
824
1140
|
tables: 0,
|
|
825
1141
|
figures: 0,
|
|
826
1142
|
diagrams: 0,
|
|
827
1143
|
checks: 0,
|
|
1144
|
+
examples: 0,
|
|
828
1145
|
};
|
|
829
1146
|
let chapterCursor = 0;
|
|
830
1147
|
for (const lessonId of lessonIds) {
|
|
831
1148
|
const body = bodyByLessonId.get(lessonId) ?? '';
|
|
1149
|
+
const chapter = ++chapterCursor;
|
|
832
1150
|
placementByLessonId.set(lessonId, {
|
|
833
1151
|
part: partCursor,
|
|
834
|
-
chapter
|
|
835
|
-
numbering:
|
|
1152
|
+
chapter,
|
|
1153
|
+
numbering: chapterScoped
|
|
1154
|
+
? {
|
|
1155
|
+
prefix: `${partCursor}.${chapter}`,
|
|
1156
|
+
equations: 0,
|
|
1157
|
+
tables: 0,
|
|
1158
|
+
figures: 0,
|
|
1159
|
+
diagrams: 0,
|
|
1160
|
+
checks: 0,
|
|
1161
|
+
examples: 0,
|
|
1162
|
+
}
|
|
1163
|
+
: { prefix: String(partCursor), ...used },
|
|
836
1164
|
});
|
|
837
1165
|
used.equations += countDisplayEquations(body);
|
|
838
1166
|
used.tables += countKeyedJsxFloats(body, { tagName: 'Table' });
|
|
839
1167
|
used.figures += countKeyedJsxFloats(body, { tagName: 'Figure' });
|
|
840
1168
|
used.diagrams += countKeyedJsxFloats(body, { tagName: 'Diagram' });
|
|
841
1169
|
used.checks += lessonMetaById.get(lessonId)?.assessments.length ?? 0;
|
|
1170
|
+
used.examples += countKeyedJsxFloats(body, { tagName: 'CompactExamples' });
|
|
842
1171
|
}
|
|
843
1172
|
}
|
|
844
1173
|
|
|
1174
|
+
// The outline: every lesson's top-level headings with their anchors and,
|
|
1175
|
+
// for a placed lesson, their `‹part›.‹chapter›.‹s›…` numbers. A `[[sec-…]]`
|
|
1176
|
+
// must name one of them.
|
|
1177
|
+
const headingsByLessonId = new Map(
|
|
1178
|
+
notationInput.lessons.map((lesson) => {
|
|
1179
|
+
const placement = placementByLessonId.get(lesson.lessonId);
|
|
1180
|
+
return [
|
|
1181
|
+
lesson.lessonId,
|
|
1182
|
+
scanSectionHeadings(lesson.body, {
|
|
1183
|
+
...(placement
|
|
1184
|
+
? { prefix: `${placement.part}.${placement.chapter}` }
|
|
1185
|
+
: {}),
|
|
1186
|
+
depth: numberingSettings.sections.depth,
|
|
1187
|
+
}) as ManifestLesson['headings'],
|
|
1188
|
+
];
|
|
1189
|
+
}),
|
|
1190
|
+
);
|
|
1191
|
+
mathIssues.push(
|
|
1192
|
+
...validateSectionRefs(
|
|
1193
|
+
notationInput.lessons.map((lesson) => ({
|
|
1194
|
+
slug: lesson.lessonId.replace(/\./g, '/'),
|
|
1195
|
+
file: lesson.source.file,
|
|
1196
|
+
body: lesson.body,
|
|
1197
|
+
...(lesson.bodyLine === undefined ? {} : { bodyLine: lesson.bodyLine }),
|
|
1198
|
+
headingSlugs: (headingsByLessonId.get(lesson.lessonId) ?? []).map(
|
|
1199
|
+
(heading) => heading.slug,
|
|
1200
|
+
),
|
|
1201
|
+
})),
|
|
1202
|
+
),
|
|
1203
|
+
);
|
|
1204
|
+
|
|
1205
|
+
// The parts themselves, in config order, with their chapters in reading
|
|
1206
|
+
// order — the one place a part-level page or a breadcrumb reads, so neither
|
|
1207
|
+
// has to re-derive a part from lesson slugs.
|
|
1208
|
+
const manifestParts: ManifestPart[] = configuredParts.map((part, index) => {
|
|
1209
|
+
const overview = overviewByDir.get(part.dir);
|
|
1210
|
+
const lessonIds = [...placementByLessonId]
|
|
1211
|
+
.filter(([lessonId]) => lessonId.startsWith(`${part.dir}.`))
|
|
1212
|
+
.sort(([, a], [, b]) => a.chapter - b.chapter)
|
|
1213
|
+
.map(([lessonId]) => lessonId);
|
|
1214
|
+
const chapterMinutes = lessonIds.map(
|
|
1215
|
+
(lessonId) => frontmatterById.get(lessonId)?.studyMinutes,
|
|
1216
|
+
);
|
|
1217
|
+
// A total only means something when no chapter is missing from it.
|
|
1218
|
+
const studyMinutes =
|
|
1219
|
+
chapterMinutes.length > 0 &&
|
|
1220
|
+
chapterMinutes.every((range) => range !== undefined)
|
|
1221
|
+
? chapterMinutes.reduce(
|
|
1222
|
+
(total, range) => ({
|
|
1223
|
+
min: total.min + range!.min,
|
|
1224
|
+
max: total.max + range!.max,
|
|
1225
|
+
}),
|
|
1226
|
+
{ min: 0, max: 0 },
|
|
1227
|
+
)
|
|
1228
|
+
: undefined;
|
|
1229
|
+
return {
|
|
1230
|
+
dir: part.dir,
|
|
1231
|
+
label: part.label,
|
|
1232
|
+
ordinal: index + 1,
|
|
1233
|
+
link: `/${part.dir}/`,
|
|
1234
|
+
lessons: lessonIds,
|
|
1235
|
+
...(studyMinutes === undefined ? {} : { studyMinutes }),
|
|
1236
|
+
...(overview
|
|
1237
|
+
? {
|
|
1238
|
+
overview: {
|
|
1239
|
+
title: overview.title,
|
|
1240
|
+
file: overview.file,
|
|
1241
|
+
...(overview.description === undefined
|
|
1242
|
+
? {}
|
|
1243
|
+
: { description: overview.description }),
|
|
1244
|
+
},
|
|
1245
|
+
}
|
|
1246
|
+
: {}),
|
|
1247
|
+
};
|
|
1248
|
+
});
|
|
1249
|
+
|
|
845
1250
|
const floatInputs = (
|
|
846
|
-
kind: 'equations' | 'tables' | 'figures' | 'diagrams',
|
|
1251
|
+
kind: 'equations' | 'tables' | 'figures' | 'diagrams' | 'examples',
|
|
847
1252
|
) =>
|
|
848
1253
|
notationInput.lessons.map((lesson) => {
|
|
849
1254
|
const placement = placementByLessonId.get(lesson.lessonId);
|
|
@@ -855,41 +1260,49 @@ export async function compileManifest(
|
|
|
855
1260
|
...(placement
|
|
856
1261
|
? {
|
|
857
1262
|
numbering: {
|
|
858
|
-
prefix: placement.
|
|
1263
|
+
prefix: placement.numbering.prefix,
|
|
859
1264
|
offset: placement.numbering[kind],
|
|
860
1265
|
},
|
|
861
1266
|
}
|
|
862
1267
|
: {}),
|
|
863
1268
|
};
|
|
864
1269
|
});
|
|
1270
|
+
// `lessons[].equations` / `.tables` / `.figures` / `.diagrams` /
|
|
1271
|
+
// `.examples`: each keyed float of the lesson in appearance order, with its
|
|
1272
|
+
// caption pair (v21) — an example set's `short` is its title.
|
|
1273
|
+
const floatsBySlug = (
|
|
1274
|
+
labels: readonly {
|
|
1275
|
+
readonly slug: string;
|
|
1276
|
+
readonly key: string;
|
|
1277
|
+
readonly number: string;
|
|
1278
|
+
readonly short?: string;
|
|
1279
|
+
readonly caption?: string;
|
|
1280
|
+
}[],
|
|
1281
|
+
): Map<string, ManifestLessonFloat[]> => {
|
|
1282
|
+
const bySlug = new Map<string, ManifestLessonFloat[]>();
|
|
1283
|
+
for (const { slug, key, number, short, caption } of labels) {
|
|
1284
|
+
const list = bySlug.get(slug) ?? [];
|
|
1285
|
+
list.push({
|
|
1286
|
+
key,
|
|
1287
|
+
number,
|
|
1288
|
+
...(short === undefined ? {} : { short }),
|
|
1289
|
+
...(caption === undefined ? {} : { caption }),
|
|
1290
|
+
});
|
|
1291
|
+
bySlug.set(slug, list);
|
|
1292
|
+
}
|
|
1293
|
+
return bySlug;
|
|
1294
|
+
};
|
|
865
1295
|
const equationValidation = validateEquations(floatInputs('equations'));
|
|
866
|
-
const equationsBySlug =
|
|
867
|
-
Object.entries(equationValidation.numbersBySlug).map(([slug, table]) => [
|
|
868
|
-
slug,
|
|
869
|
-
Object.entries(table).map(([key, number]) => ({ key, number })),
|
|
870
|
-
]),
|
|
871
|
-
);
|
|
1296
|
+
const equationsBySlug = floatsBySlug(equationValidation.labels);
|
|
872
1297
|
const tableValidation = validateTables(floatInputs('tables'));
|
|
873
|
-
const tablesBySlug =
|
|
874
|
-
Object.entries(tableValidation.numbersBySlug).map(([slug, table]) => [
|
|
875
|
-
slug,
|
|
876
|
-
Object.entries(table).map(([key, number]) => ({ key, number })),
|
|
877
|
-
]),
|
|
878
|
-
);
|
|
1298
|
+
const tablesBySlug = floatsBySlug(tableValidation.labels);
|
|
879
1299
|
const figureValidation = validateFigures(floatInputs('figures'));
|
|
880
|
-
const figuresBySlug =
|
|
881
|
-
Object.entries(figureValidation.numbersBySlug).map(([slug, table]) => [
|
|
882
|
-
slug,
|
|
883
|
-
Object.entries(table).map(([key, number]) => ({ key, number })),
|
|
884
|
-
]),
|
|
885
|
-
);
|
|
1300
|
+
const figuresBySlug = floatsBySlug(figureValidation.labels);
|
|
886
1301
|
const diagramValidation = validateDiagrams(floatInputs('diagrams'));
|
|
887
|
-
const diagramsBySlug =
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
]),
|
|
892
|
-
);
|
|
1302
|
+
const diagramsBySlug = floatsBySlug(diagramValidation.labels);
|
|
1303
|
+
const exampleValidation = validateExamples(floatInputs('examples'));
|
|
1304
|
+
const examplesBySlug = floatsBySlug(exampleValidation.labels);
|
|
1305
|
+
const foldValidation = validateFolds(floatInputs('figures'));
|
|
893
1306
|
const checkValidation = validateKnowledgeChecks(
|
|
894
1307
|
notationInput.lessons.map((lesson) => {
|
|
895
1308
|
const placement = placementByLessonId.get(lesson.lessonId);
|
|
@@ -903,7 +1316,7 @@ export async function compileManifest(
|
|
|
903
1316
|
...(placement
|
|
904
1317
|
? {
|
|
905
1318
|
numbering: {
|
|
906
|
-
prefix: placement.
|
|
1319
|
+
prefix: placement.numbering.prefix,
|
|
907
1320
|
offset: placement.numbering.checks,
|
|
908
1321
|
},
|
|
909
1322
|
}
|
|
@@ -911,12 +1324,51 @@ export async function compileManifest(
|
|
|
911
1324
|
};
|
|
912
1325
|
}),
|
|
913
1326
|
);
|
|
1327
|
+
// Each check with the title its heading shows after the badge (v23).
|
|
1328
|
+
const checkTitleById = new Map(
|
|
1329
|
+
assessmentsInput.map((assessment) => [assessment.id, assessment.title]),
|
|
1330
|
+
);
|
|
914
1331
|
const checksBySlug = new Map(
|
|
915
1332
|
Object.entries(checkValidation.numbersBySlug).map(([slug, table]) => [
|
|
916
1333
|
slug,
|
|
917
|
-
Object.entries(table).map(([key, number]) =>
|
|
1334
|
+
Object.entries(table).map(([key, number]) => {
|
|
1335
|
+
const title = checkTitleById.get(key);
|
|
1336
|
+
return { key, number, ...(title === undefined ? {} : { title }) };
|
|
1337
|
+
}),
|
|
918
1338
|
]),
|
|
919
1339
|
);
|
|
1340
|
+
// The blocks that draw an `<h2>` where their tag stands, placed after the
|
|
1341
|
+
// outline heading they follow — "On this page" lists them there (v23).
|
|
1342
|
+
// `<AssessmentSet />` draws every check of the lesson, or the one its `id`
|
|
1343
|
+
// names; `<CompactExamples>` draws its own set.
|
|
1344
|
+
const titledBlocksFor = (lessonId: string): ManifestTitledBlock[] => {
|
|
1345
|
+
const slug = lessonId.replace(/\./g, '/');
|
|
1346
|
+
const body = bodyByLessonId.get(lessonId) ?? '';
|
|
1347
|
+
const headings = headingsByLessonId.get(lessonId) ?? [];
|
|
1348
|
+
const checks = checksBySlug.get(slug) ?? [];
|
|
1349
|
+
const examples = examplesBySlug.get(slug) ?? [];
|
|
1350
|
+
return scanTitledBlocks(body, ['AssessmentSet', 'CompactExamples']).flatMap(
|
|
1351
|
+
(block: { name: string; heading: number; id?: string }): ManifestTitledBlock[] => {
|
|
1352
|
+
const after = headings[block.heading]?.slug;
|
|
1353
|
+
const place = after === undefined ? {} : { after };
|
|
1354
|
+
if (block.name === 'CompactExamples') {
|
|
1355
|
+
const set = examples.find((example) => example.key === block.id);
|
|
1356
|
+
return set?.short
|
|
1357
|
+
? [{ kind: 'example' as const, key: set.key, anchor: `ex-${set.key}`, title: set.short, ...place }]
|
|
1358
|
+
: [];
|
|
1359
|
+
}
|
|
1360
|
+
return checks
|
|
1361
|
+
.filter((check) => block.id === undefined || check.key === block.id)
|
|
1362
|
+
.map((check) => ({
|
|
1363
|
+
kind: 'check' as const,
|
|
1364
|
+
key: check.key,
|
|
1365
|
+
anchor: knowledgeCheckAnchorId(check.key),
|
|
1366
|
+
title: check.title ?? check.key,
|
|
1367
|
+
...place,
|
|
1368
|
+
}));
|
|
1369
|
+
},
|
|
1370
|
+
);
|
|
1371
|
+
};
|
|
920
1372
|
const rawFloatDiagnostics = validateRawFloats(
|
|
921
1373
|
notationInput.lessons.map((lesson) => ({
|
|
922
1374
|
lessonId: lesson.lessonId,
|
|
@@ -945,27 +1397,35 @@ export async function compileManifest(
|
|
|
945
1397
|
part: placementByLessonId.get(id)?.part ?? 0,
|
|
946
1398
|
chapter: placementByLessonId.get(id)?.chapter ?? 0,
|
|
947
1399
|
numbering: placementByLessonId.get(id)?.numbering ?? {
|
|
1400
|
+
prefix: '',
|
|
948
1401
|
equations: 0,
|
|
949
1402
|
tables: 0,
|
|
950
1403
|
figures: 0,
|
|
951
1404
|
diagrams: 0,
|
|
952
1405
|
checks: 0,
|
|
1406
|
+
examples: 0,
|
|
953
1407
|
},
|
|
1408
|
+
headings: headingsByLessonId.get(id) ?? [],
|
|
954
1409
|
file: notationLesson.source.file,
|
|
955
1410
|
title: frontmatter.title,
|
|
956
1411
|
description: frontmatter.description,
|
|
1412
|
+
...(frontmatter.studyMinutes === undefined
|
|
1413
|
+
? {}
|
|
1414
|
+
: { studyMinutes: frontmatter.studyMinutes }),
|
|
957
1415
|
status: meta.status,
|
|
958
1416
|
teaches: [...teaches],
|
|
959
1417
|
requires: [...meta.requires],
|
|
960
1418
|
assumptions: [...meta.assumptions],
|
|
961
1419
|
assessments: [...meta.assessments],
|
|
962
1420
|
knowledgeChecks: checksBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
1421
|
+
titledBlocks: titledBlocksFor(id),
|
|
963
1422
|
sources: deriveSources(notationLesson.body),
|
|
964
1423
|
citations: lessonCitations(notationLesson.body),
|
|
965
1424
|
equations: equationsBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
966
1425
|
tables: tablesBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
967
1426
|
figures: figuresBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
968
1427
|
diagrams: diagramsBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
1428
|
+
examples: examplesBySlug.get(id.replace(/\./g, '/')) ?? [],
|
|
969
1429
|
prereqEdges: sortEdges(
|
|
970
1430
|
teaches.flatMap((to) =>
|
|
971
1431
|
(prerequisitesById.get(to) ?? [])
|
|
@@ -994,12 +1454,9 @@ export async function compileManifest(
|
|
|
994
1454
|
catalog,
|
|
995
1455
|
lintIgnore: loadLintIgnore(),
|
|
996
1456
|
conventions: courseConfig.conventions,
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
...(courseConfig.romanLabels === undefined
|
|
1001
|
-
? {}
|
|
1002
|
-
: { romanLabels: courseConfig.romanLabels }),
|
|
1457
|
+
operators: rules.settings('N8'),
|
|
1458
|
+
romanLabels: rules.settings('N10'),
|
|
1459
|
+
accents: rules.settings('N22'),
|
|
1003
1460
|
});
|
|
1004
1461
|
|
|
1005
1462
|
const rawNotation = [...loadNotationDefinitions()].sort((a, b) =>
|
|
@@ -1068,7 +1525,9 @@ export async function compileManifest(
|
|
|
1068
1525
|
return {
|
|
1069
1526
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
1070
1527
|
lessonExports: normalizeLessonExports(courseConfig),
|
|
1071
|
-
|
|
1528
|
+
disclosure: normalizeDisclosure(courseConfig),
|
|
1529
|
+
numbering: numberingSettings,
|
|
1530
|
+
blockLabels,
|
|
1072
1531
|
about,
|
|
1073
1532
|
notation: {
|
|
1074
1533
|
definitions: registry.definitions,
|
|
@@ -1082,6 +1541,7 @@ export async function compileManifest(
|
|
|
1082
1541
|
tracks,
|
|
1083
1542
|
abbreviations,
|
|
1084
1543
|
sidebar,
|
|
1544
|
+
parts: manifestParts,
|
|
1085
1545
|
lessons,
|
|
1086
1546
|
prereqEdges,
|
|
1087
1547
|
equations: {
|
|
@@ -1104,20 +1564,29 @@ export async function compileManifest(
|
|
|
1104
1564
|
labels: checkValidation.labels,
|
|
1105
1565
|
numbersBySlug: checkValidation.numbersBySlug,
|
|
1106
1566
|
},
|
|
1567
|
+
examples: {
|
|
1568
|
+
labels: exampleValidation.labels,
|
|
1569
|
+
numbersBySlug: exampleValidation.numbersBySlug,
|
|
1570
|
+
},
|
|
1107
1571
|
assessmentContent,
|
|
1572
|
+
rules: rulesSnapshot(rules),
|
|
1108
1573
|
diagnostics: {
|
|
1109
|
-
curriculum: curriculumIssues,
|
|
1110
|
-
notation: registry.diagnostics,
|
|
1111
|
-
alignment: alignmentIssues,
|
|
1112
|
-
math: mathIssues,
|
|
1113
|
-
consistency: consistencyIssues,
|
|
1114
|
-
equations: equationValidation.diagnostics,
|
|
1115
|
-
tables: tableValidation.diagnostics,
|
|
1116
|
-
figures: figureValidation.diagnostics,
|
|
1117
|
-
diagrams: diagramValidation.diagnostics,
|
|
1118
|
-
checks: checkValidation.diagnostics,
|
|
1119
|
-
|
|
1120
|
-
|
|
1574
|
+
curriculum: dropDisabled(curriculumIssues, off),
|
|
1575
|
+
notation: dropDisabled(registry.diagnostics, off),
|
|
1576
|
+
alignment: dropDisabled(alignmentIssues, off),
|
|
1577
|
+
math: dropDisabled(mathIssues, off),
|
|
1578
|
+
consistency: dropDisabled(consistencyIssues, off),
|
|
1579
|
+
equations: dropDisabled(equationValidation.diagnostics, off),
|
|
1580
|
+
tables: dropDisabled(tableValidation.diagnostics, off),
|
|
1581
|
+
figures: dropDisabled(figureValidation.diagnostics, off),
|
|
1582
|
+
diagrams: dropDisabled(diagramValidation.diagnostics, off),
|
|
1583
|
+
checks: dropDisabled(checkValidation.diagnostics, off),
|
|
1584
|
+
examples: dropDisabled(exampleValidation.diagnostics, off),
|
|
1585
|
+
folds: dropDisabled(foldValidation.diagnostics, off),
|
|
1586
|
+
knowledge: dropDisabled(knowledge.diagnostics, off),
|
|
1587
|
+
rawFloats: dropDisabled(rawFloatDiagnostics, off),
|
|
1588
|
+
config: rules.diagnostics,
|
|
1589
|
+
waivers: waiverDiagnostics,
|
|
1121
1590
|
},
|
|
1122
1591
|
hashes,
|
|
1123
1592
|
};
|