explico 0.12.0 → 0.13.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 +1122 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +4 -3
- package/dist/compiler/astro.js +45 -15
- package/dist/compiler/cli.d.ts +26 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +9 -1
- package/dist/compiler/collections.js +55 -16
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +14 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +87 -6
- package/dist/compiler/manifest.js +174 -31
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +2 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +2 -2
- package/dist/reference/base-operators.mjs +2 -2
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +34 -4
- package/dist/reference/page-notation.js +54 -2
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +104 -10
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +84 -20
- package/dist/reference/render-lab-math.d.ts +2 -0
- package/dist/reference/render-lab-math.js +17 -5
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +191 -30
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +79 -24
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +32 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +111 -6
- package/docs/authoring/migrating.md +663 -0
- package/docs/authoring/notation.md +281 -29
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +10 -41
- package/docs/authoring/structure.md +53 -2
- package/docs/authoring/visualizations.md +144 -18
- package/package.json +12 -7
- package/src/compiler/astro.ts +57 -17
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +92 -19
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +299 -28
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +12 -9
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/figure/Figure.astro +11 -0
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +300 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +47 -9
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +13 -21
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +2 -2
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +100 -3
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +154 -8
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +84 -20
- package/src/reference/render-lab-math.ts +29 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +205 -29
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +291 -75
|
@@ -45,8 +45,11 @@ import {
|
|
|
45
45
|
} from "../reference/lab-katex-validate.js";
|
|
46
46
|
import {
|
|
47
47
|
gateContentMath,
|
|
48
|
-
pageScope
|
|
48
|
+
pageScope,
|
|
49
|
+
scopeEntry
|
|
49
50
|
} from "../reference/gate-math.js";
|
|
51
|
+
import { gateIndices } from "../reference/gate-indices.js";
|
|
52
|
+
import { derivedNotationEntries } from "../reference/derived-entries.js";
|
|
50
53
|
import {
|
|
51
54
|
gateProseNotation,
|
|
52
55
|
gateProseNotationInAssessments
|
|
@@ -61,12 +64,17 @@ import { gateHeadingLength } from "../reference/gate-heading-length.js";
|
|
|
61
64
|
import { gateHeadingStructure } from "../reference/gate-heading-structure.js";
|
|
62
65
|
import { gatePartPages } from "../reference/gate-part-pages.js";
|
|
63
66
|
import { gateNonChapterPages } from "../reference/gate-non-chapter-pages.js";
|
|
67
|
+
import { findRetiredKeys, findUnsupportedKeys } from "../reference/gate-retired-keys.js";
|
|
68
|
+
import { findMarkupInProps } from "../reference/gate-prop-text.js";
|
|
69
|
+
import { gateMdxExpressions } from "../reference/gate-mdx-expression.js";
|
|
70
|
+
import { CITATION_BRACKET, bracketCitations, withoutLinkCitations } from "../reference/citation-format.mjs";
|
|
71
|
+
import { validateContentSchemas } from "./content-schema.js";
|
|
64
72
|
import {
|
|
65
73
|
scanSectionHeadings,
|
|
66
74
|
scanTitledBlocks
|
|
67
75
|
} from "../reference/sections.mjs";
|
|
68
76
|
import { knowledgeCheckAnchorId } from "../reference/knowledge-checks.mjs";
|
|
69
|
-
import { validateSectionRefs } from "../reference/sections-validate.js";
|
|
77
|
+
import { validateHeadingAnchors, validateSectionRefs } from "../reference/sections-validate.js";
|
|
70
78
|
import {
|
|
71
79
|
splitMixedContent
|
|
72
80
|
} from "../reference/mixed-content.js";
|
|
@@ -77,6 +85,7 @@ import { resolveReferenceId } from "../reference/references.js";
|
|
|
77
85
|
import {
|
|
78
86
|
coursePartsOf,
|
|
79
87
|
normalizeBlockLabels,
|
|
88
|
+
normalizeCards,
|
|
80
89
|
normalizeLessonExports,
|
|
81
90
|
normalizeDisclosure,
|
|
82
91
|
normalizeNumbering
|
|
@@ -97,6 +106,7 @@ import {
|
|
|
97
106
|
} from "./knowledge-version.js";
|
|
98
107
|
import {
|
|
99
108
|
loadAbbreviationRegistryInput,
|
|
109
|
+
loadContentRecords,
|
|
100
110
|
loadCurriculumCatalog,
|
|
101
111
|
loadNotationDefinitions,
|
|
102
112
|
loadNotationRegistryInput,
|
|
@@ -111,7 +121,7 @@ import {
|
|
|
111
121
|
isLessonSlug,
|
|
112
122
|
lessonIdFromSlug
|
|
113
123
|
} from "./lesson-derivation.js";
|
|
114
|
-
const MANIFEST_SCHEMA_VERSION =
|
|
124
|
+
const MANIFEST_SCHEMA_VERSION = 31;
|
|
115
125
|
const REPOSITORY_ROOT = process.cwd();
|
|
116
126
|
const CONTENT_ROOT = join(REPOSITORY_ROOT, "content");
|
|
117
127
|
const MANIFEST_PATH = join(REPOSITORY_ROOT, "build", "manifest.json");
|
|
@@ -124,18 +134,19 @@ function readEnginePackage() {
|
|
|
124
134
|
}
|
|
125
135
|
return enginePackage;
|
|
126
136
|
}
|
|
127
|
-
const CITE_PATTERN = /\[@([a-z0-9][a-z0-9.-]*)(?:;[ \t\r\n]*([^\]]*))?\]/g;
|
|
128
137
|
function lessonCitations(body) {
|
|
129
138
|
const withoutCode = body.replace(/```[\s\S]*?```/g, "").replace(/`[^`\n]*`/g, "");
|
|
130
139
|
const seen = /* @__PURE__ */ new Set();
|
|
131
140
|
const citations = [];
|
|
132
|
-
for (const match of withoutCode.matchAll(
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
for (const match of withoutLinkCitations(withoutCode).matchAll(CITATION_BRACKET)) {
|
|
142
|
+
for (const citation of bracketCitations(match[1] ?? "", match[2])) {
|
|
143
|
+
const id = citation.id;
|
|
144
|
+
const locator = citation.locator || void 0;
|
|
145
|
+
const dedupeKey = `${id} ${locator ?? ""}`;
|
|
146
|
+
if (seen.has(dedupeKey)) continue;
|
|
147
|
+
seen.add(dedupeKey);
|
|
148
|
+
citations.push(locator === void 0 ? { id } : { id, locator });
|
|
149
|
+
}
|
|
139
150
|
}
|
|
140
151
|
return citations;
|
|
141
152
|
}
|
|
@@ -175,17 +186,21 @@ function lessonNotationResolution(lesson, definitionsById, availableDefinitionId
|
|
|
175
186
|
key: reference.key,
|
|
176
187
|
scope: definition ? definition.kind === "shared" ? "shared" : "local" : "unresolved",
|
|
177
188
|
definitionId: definitionId ?? null,
|
|
178
|
-
|
|
189
|
+
// A page's own references are prose or math; a definition's formula
|
|
190
|
+
// reference is reported as the definition reference it always was.
|
|
191
|
+
kind: reference.kind === "formula" ? "definition" : reference.kind,
|
|
179
192
|
line: reference.source.line ?? null,
|
|
180
193
|
column: reference.source.column ?? null
|
|
181
194
|
};
|
|
182
195
|
});
|
|
183
196
|
}
|
|
184
|
-
function lessonNotationBundle(bundle, definitionsById, resolution, cardsByKey) {
|
|
197
|
+
function lessonNotationBundle(bundle, definitionsById, resolution, cardsByKey, derivedUses = []) {
|
|
185
198
|
const definitions = [];
|
|
199
|
+
const records = [];
|
|
186
200
|
for (const definitionId of bundle?.definitionIds ?? []) {
|
|
187
201
|
const definition = definitionsById.get(definitionId);
|
|
188
202
|
if (!definition) continue;
|
|
203
|
+
records.push(definition);
|
|
189
204
|
definitions.push({
|
|
190
205
|
id: definition.id,
|
|
191
206
|
key: definition.key,
|
|
@@ -193,7 +208,6 @@ function lessonNotationBundle(bundle, definitionsById, resolution, cardsByKey) {
|
|
|
193
208
|
notation: definition.notation,
|
|
194
209
|
label: definition.label,
|
|
195
210
|
summary: definition.summary,
|
|
196
|
-
editorialStatus: definition.status,
|
|
197
211
|
seeAlso: [...definition.seeAlso],
|
|
198
212
|
glosses: [...definition.glosses],
|
|
199
213
|
formulaScope: formulaGlyphScope({
|
|
@@ -204,13 +218,19 @@ function lessonNotationBundle(bundle, definitionsById, resolution, cardsByKey) {
|
|
|
204
218
|
...definition.formula === void 0 ? {} : { formula: definition.formula }
|
|
205
219
|
}),
|
|
206
220
|
...definition.units === void 0 ? {} : { units: definition.units },
|
|
207
|
-
...definition.formula === void 0 ? {} : { formula: definition.formula }
|
|
221
|
+
...definition.formula === void 0 ? {} : { formula: definition.formula },
|
|
222
|
+
...definition.range === void 0 ? {} : { range: definition.range }
|
|
208
223
|
});
|
|
209
224
|
}
|
|
210
225
|
return {
|
|
211
226
|
bindings: [...bundle?.bindings ?? []].map((binding) => ({ ...binding })),
|
|
212
227
|
definitionIds: [...bundle?.definitionIds ?? []],
|
|
213
228
|
definitions,
|
|
229
|
+
derived: derivedNotationEntries(
|
|
230
|
+
derivedUses,
|
|
231
|
+
new Map(records.map((record) => [record.key, record])),
|
|
232
|
+
cardsByKey
|
|
233
|
+
),
|
|
214
234
|
resolution: [...resolution]
|
|
215
235
|
};
|
|
216
236
|
}
|
|
@@ -277,7 +297,7 @@ async function compileManifest(courseConfig) {
|
|
|
277
297
|
const cardsByKey = new Map(
|
|
278
298
|
notationInput.sharedDefinitions.map((definition) => [
|
|
279
299
|
definition.key,
|
|
280
|
-
|
|
300
|
+
scopeEntry(definition)
|
|
281
301
|
])
|
|
282
302
|
);
|
|
283
303
|
const definitionsById = new Map(
|
|
@@ -288,13 +308,44 @@ async function compileManifest(courseConfig) {
|
|
|
288
308
|
registry.bundles.map((bundle) => [bundle.lessonId, bundle])
|
|
289
309
|
);
|
|
290
310
|
const assessmentsInput = catalog.assessments;
|
|
291
|
-
const
|
|
311
|
+
const contentRecords = loadContentRecords();
|
|
312
|
+
const curriculumIssues = [
|
|
313
|
+
...validateCurriculum(catalog),
|
|
314
|
+
...validateContentSchemas(contentRecords),
|
|
315
|
+
...findRetiredKeys(contentRecords),
|
|
316
|
+
...findUnsupportedKeys(contentRecords),
|
|
317
|
+
...findMarkupInProps(contentRecords)
|
|
318
|
+
];
|
|
292
319
|
const alignmentIssues = validateNotationAlignment(registry, catalog);
|
|
293
320
|
const mathEndAbbreviations = {
|
|
294
321
|
allow: rules.strings("N12", "allow"),
|
|
295
322
|
deny: rules.strings("N12", "deny")
|
|
296
323
|
};
|
|
324
|
+
const sharedLabels = new Map(
|
|
325
|
+
notationInput.sharedDefinitions.map((definition) => [definition.key, definition.label])
|
|
326
|
+
);
|
|
327
|
+
const localLabelsByLesson = new Map(
|
|
328
|
+
notationInput.lessons.map((lesson) => [
|
|
329
|
+
lesson.lessonId,
|
|
330
|
+
new Map(lesson.localDefinitions.map((definition) => [definition.key, definition.label]))
|
|
331
|
+
])
|
|
332
|
+
);
|
|
333
|
+
const termLabel = (lessonId, key) => localLabelsByLesson.get(lessonId)?.get(key) ?? sharedLabels.get(key);
|
|
334
|
+
const indexGate = gateIndices(
|
|
335
|
+
withPages.lessons,
|
|
336
|
+
new Map(
|
|
337
|
+
notationInput.sharedDefinitions.map((definition) => [definition.key, definition])
|
|
338
|
+
),
|
|
339
|
+
{
|
|
340
|
+
assessments: assessmentsInput,
|
|
341
|
+
lessonAssessments: catalog.lessons.map((lesson) => ({
|
|
342
|
+
lessonId: lesson.id,
|
|
343
|
+
assessmentIds: lesson.assessments
|
|
344
|
+
}))
|
|
345
|
+
}
|
|
346
|
+
);
|
|
297
347
|
const mathIssues = [
|
|
348
|
+
...indexGate.diagnostics,
|
|
298
349
|
...gateContentMath({
|
|
299
350
|
notationInput: withPages,
|
|
300
351
|
assessments: assessmentsInput,
|
|
@@ -303,6 +354,7 @@ async function compileManifest(courseConfig) {
|
|
|
303
354
|
assessmentIds: lesson.assessments
|
|
304
355
|
}))
|
|
305
356
|
}),
|
|
357
|
+
...gateMdxExpressions(withPages.lessons),
|
|
306
358
|
...rules.isEnabled("N9") ? [
|
|
307
359
|
...gateProseNotation(withPages.lessons, {
|
|
308
360
|
allowSpelledUnits: rules.strings("N9", "allow")
|
|
@@ -321,7 +373,8 @@ async function compileManifest(courseConfig) {
|
|
|
321
373
|
courseAbbreviations: rules.settings("N14")
|
|
322
374
|
}) : [],
|
|
323
375
|
...rules.isEnabled("S1") ? gateHeadingLength(notationInput.lessons, {
|
|
324
|
-
maxLength: rules.number("S1", "maxLength")
|
|
376
|
+
maxLength: rules.number("S1", "maxLength"),
|
|
377
|
+
labelFor: termLabel
|
|
325
378
|
}) : [],
|
|
326
379
|
...gateHeadingStructure(notationInput.lessons, {
|
|
327
380
|
levels: rules.isEnabled("S6"),
|
|
@@ -341,22 +394,46 @@ async function compileManifest(courseConfig) {
|
|
|
341
394
|
assessmentsInput.map((assessment) => [assessment.id, assessment])
|
|
342
395
|
);
|
|
343
396
|
const assessmentContent = [];
|
|
397
|
+
const assessmentDerived = /* @__PURE__ */ new Map();
|
|
344
398
|
for (const lesson of catalog.lessons) {
|
|
345
399
|
if (lesson.assessments.length === 0) continue;
|
|
346
400
|
const lessonInput = notationLessonById.get(lesson.id);
|
|
347
401
|
if (!lessonInput) continue;
|
|
348
402
|
const scope = pageScope(lessonInput, cardsByKey);
|
|
403
|
+
const derived = /* @__PURE__ */ new Map();
|
|
404
|
+
assessmentDerived.set(lesson.id, derived);
|
|
405
|
+
const page = { derive: true, derived };
|
|
349
406
|
for (const assessmentId of lesson.assessments) {
|
|
350
407
|
const assessment = assessmentInputById.get(assessmentId);
|
|
351
408
|
if (!assessment?.items) continue;
|
|
352
409
|
for (const item of assessment.items) {
|
|
353
410
|
if (!item.id) continue;
|
|
411
|
+
const numeric = item.type === "numeric" && typeof item.answer?.value === "number" && typeof item.answer.tolerance === "number";
|
|
354
412
|
assessmentContent.push({
|
|
355
413
|
lessonId: lesson.id,
|
|
356
414
|
assessmentId,
|
|
357
415
|
itemId: item.id,
|
|
358
|
-
promptSegments: splitMixedContent(item.prompt ?? "", scope),
|
|
359
|
-
explanationSegments: splitMixedContent(item.explanation ?? "", scope)
|
|
416
|
+
promptSegments: splitMixedContent(item.prompt ?? "", scope, page),
|
|
417
|
+
explanationSegments: splitMixedContent(item.explanation ?? "", scope, page),
|
|
418
|
+
type: item.type === "numeric" ? "numeric" : "single-choice",
|
|
419
|
+
...item.options ? {
|
|
420
|
+
options: item.options.flatMap(
|
|
421
|
+
(option) => option.id ? [
|
|
422
|
+
{
|
|
423
|
+
id: option.id,
|
|
424
|
+
label: option.label ?? "",
|
|
425
|
+
labelSegments: splitMixedContent(option.label ?? "", scope, page)
|
|
426
|
+
}
|
|
427
|
+
] : []
|
|
428
|
+
)
|
|
429
|
+
} : {},
|
|
430
|
+
...item.correctOptionId ? { correctOptionId: item.correctOptionId } : {},
|
|
431
|
+
...numeric ? {
|
|
432
|
+
answer: {
|
|
433
|
+
value: item.answer.value,
|
|
434
|
+
tolerance: item.answer.tolerance
|
|
435
|
+
}
|
|
436
|
+
} : {}
|
|
360
437
|
});
|
|
361
438
|
}
|
|
362
439
|
}
|
|
@@ -380,9 +457,31 @@ async function compileManifest(courseConfig) {
|
|
|
380
457
|
);
|
|
381
458
|
const frontmatterById = lessonFrontmatterById();
|
|
382
459
|
const lessonSlugs = [...notationInput.lessons].map((lesson) => lesson.lessonId.replace(/\./g, "/")).sort();
|
|
383
|
-
const
|
|
384
|
-
const overviewPages = loadPartOverviews(
|
|
460
|
+
const listedParts = coursePartsOf(courseConfig);
|
|
461
|
+
const overviewPages = loadPartOverviews(listedParts);
|
|
385
462
|
const overviewByDir = new Map(overviewPages.map((page) => [page.dir, page]));
|
|
463
|
+
const hasChapter = (dir) => lessonSlugs.some((slug) => slug.startsWith(`${dir}/`));
|
|
464
|
+
const configuredParts = listedParts.filter(
|
|
465
|
+
(part) => hasChapter(part.dir) || overviewByDir.has(part.dir)
|
|
466
|
+
);
|
|
467
|
+
for (const part of listedParts) {
|
|
468
|
+
if (configuredParts.includes(part)) continue;
|
|
469
|
+
curriculumIssues.push({
|
|
470
|
+
kind: "part-empty",
|
|
471
|
+
severity: "warning",
|
|
472
|
+
message: `course.settings.json \`parts\` lists "${part.dir}" (${JSON.stringify(part.label)}), but content/docs/${part.dir}/ has no chapter and no overview page yet, so the part is left out of the sidebar and the numbering until it has one.`
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
const partDirs = new Set(listedParts.map((part) => part.dir));
|
|
476
|
+
for (const lesson of notationInput.lessons) {
|
|
477
|
+
const dir = lesson.lessonId.split(".")[0] ?? "";
|
|
478
|
+
if (partDirs.has(dir)) continue;
|
|
479
|
+
curriculumIssues.push({
|
|
480
|
+
kind: "lesson-outside-parts",
|
|
481
|
+
message: `${lesson.source.file} is in content/docs/${dir}/, which no part in course.settings.json \`parts\` lists, so it has no part, no chapter number and no place in the sidebar. Add { "dir": "${dir}", "label": "\u2026" } to \`parts\`, or move the lesson into a part's directory.`,
|
|
482
|
+
file: lesson.source.file
|
|
483
|
+
});
|
|
484
|
+
}
|
|
386
485
|
if (rules.isEnabled("S2")) {
|
|
387
486
|
mathIssues.push(
|
|
388
487
|
...gatePartPages(
|
|
@@ -423,10 +522,10 @@ async function compileManifest(courseConfig) {
|
|
|
423
522
|
const placementByLessonId = /* @__PURE__ */ new Map();
|
|
424
523
|
const chapterScoped = numberingSettings.floats === "chapter";
|
|
425
524
|
let partCursor = 0;
|
|
426
|
-
for (const group of sidebar) {
|
|
525
|
+
for (const group of sidebar.slice(0, configuredParts.length)) {
|
|
526
|
+
partCursor += 1;
|
|
427
527
|
const lessonIds = group.items.filter((item) => typeof item === "string").map(lessonIdFromSlug);
|
|
428
528
|
if (lessonIds.length === 0) continue;
|
|
429
|
-
partCursor += 1;
|
|
430
529
|
const used = {
|
|
431
530
|
equations: 0,
|
|
432
531
|
tables: 0,
|
|
@@ -467,7 +566,8 @@ async function compileManifest(courseConfig) {
|
|
|
467
566
|
lesson.lessonId,
|
|
468
567
|
scanSectionHeadings(lesson.body, {
|
|
469
568
|
...placement ? { prefix: `${placement.part}.${placement.chapter}` } : {},
|
|
470
|
-
depth: numberingSettings.sections.depth
|
|
569
|
+
depth: numberingSettings.sections.depth,
|
|
570
|
+
labelFor: (key) => termLabel(lesson.lessonId, key)
|
|
471
571
|
})
|
|
472
572
|
];
|
|
473
573
|
})
|
|
@@ -482,7 +582,8 @@ async function compileManifest(courseConfig) {
|
|
|
482
582
|
headingSlugs: (headingsByLessonId.get(lesson.lessonId) ?? []).map(
|
|
483
583
|
(heading) => heading.slug
|
|
484
584
|
)
|
|
485
|
-
}))
|
|
585
|
+
})),
|
|
586
|
+
nonChapterPages.map((page) => page.slug)
|
|
486
587
|
)
|
|
487
588
|
);
|
|
488
589
|
const manifestParts = configuredParts.map((part, index) => {
|
|
@@ -584,6 +685,45 @@ async function compileManifest(courseConfig) {
|
|
|
584
685
|
})
|
|
585
686
|
])
|
|
586
687
|
);
|
|
688
|
+
const engineAnchorsFor = (lessonId, body) => {
|
|
689
|
+
const slug = lessonId.replace(/\./g, "/");
|
|
690
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
691
|
+
const keyed = (floats, prefix, owner) => {
|
|
692
|
+
for (const float of floats) anchors.set(`${prefix}-${float.key}`, owner(float.key));
|
|
693
|
+
};
|
|
694
|
+
keyed(equationsBySlug.get(slug) ?? [], "eq", (key) => `the equation labelled eq:${key}`);
|
|
695
|
+
keyed(tablesBySlug.get(slug) ?? [], "tab", (key) => `<Table id="${key}">`);
|
|
696
|
+
keyed(figuresBySlug.get(slug) ?? [], "fig", (key) => `<Figure id="${key}">`);
|
|
697
|
+
keyed(diagramsBySlug.get(slug) ?? [], "dia", (key) => `<Diagram id="${key}">`);
|
|
698
|
+
keyed(examplesBySlug.get(slug) ?? [], "ex", (key) => `<CompactExamples id="${key}">`);
|
|
699
|
+
for (const check of checksBySlug.get(slug) ?? []) {
|
|
700
|
+
anchors.set(knowledgeCheckAnchorId(check.key), `the knowledge check ${check.key}`);
|
|
701
|
+
}
|
|
702
|
+
for (const [name, prefix] of [
|
|
703
|
+
["Memo", "memo"],
|
|
704
|
+
["ShortNote", "short-note"]
|
|
705
|
+
]) {
|
|
706
|
+
const tag = new RegExp(`<${name}\\b[^>]*?\\bid=["']([^"']+)["']`, "g");
|
|
707
|
+
for (const match of body.matchAll(tag)) {
|
|
708
|
+
anchors.set(`${prefix}-${match[1]}`, `<${name} id="${match[1]}">`);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (deriveSources(body).length > 0) {
|
|
712
|
+
anchors.set("references", "the References section generated from the page\u2019s citations");
|
|
713
|
+
}
|
|
714
|
+
return anchors;
|
|
715
|
+
};
|
|
716
|
+
mathIssues.push(
|
|
717
|
+
...validateHeadingAnchors(
|
|
718
|
+
notationInput.lessons.map((lesson) => ({
|
|
719
|
+
file: lesson.source.file,
|
|
720
|
+
body: lesson.body,
|
|
721
|
+
...lesson.bodyLine === void 0 ? {} : { bodyLine: lesson.bodyLine },
|
|
722
|
+
headings: headingsByLessonId.get(lesson.lessonId) ?? [],
|
|
723
|
+
anchors: engineAnchorsFor(lesson.lessonId, lesson.body)
|
|
724
|
+
}))
|
|
725
|
+
)
|
|
726
|
+
);
|
|
587
727
|
const titledBlocksFor = (lessonId) => {
|
|
588
728
|
const slug = lessonId.replace(/\./g, "/");
|
|
589
729
|
const body = bodyByLessonId.get(lessonId) ?? "";
|
|
@@ -656,7 +796,6 @@ async function compileManifest(courseConfig) {
|
|
|
656
796
|
title: frontmatter.title,
|
|
657
797
|
description: frontmatter.description,
|
|
658
798
|
...frontmatter.studyMinutes === void 0 ? {} : { studyMinutes: frontmatter.studyMinutes },
|
|
659
|
-
status: meta.status,
|
|
660
799
|
teaches: [...teaches],
|
|
661
800
|
requires: [...meta.requires],
|
|
662
801
|
assumptions: [...meta.assumptions],
|
|
@@ -683,7 +822,11 @@ async function compileManifest(courseConfig) {
|
|
|
683
822
|
definitionsById,
|
|
684
823
|
availableDefinitionIds
|
|
685
824
|
),
|
|
686
|
-
cardsByKey
|
|
825
|
+
cardsByKey,
|
|
826
|
+
[
|
|
827
|
+
...indexGate.derivedByLesson.get(id) ?? [],
|
|
828
|
+
...assessmentDerived.get(id)?.values() ?? []
|
|
829
|
+
]
|
|
687
830
|
)
|
|
688
831
|
});
|
|
689
832
|
}
|
|
@@ -700,16 +843,15 @@ async function compileManifest(courseConfig) {
|
|
|
700
843
|
definitionsById,
|
|
701
844
|
availableDefinitionIds
|
|
702
845
|
),
|
|
703
|
-
cardsByKey
|
|
846
|
+
cardsByKey,
|
|
847
|
+
indexGate.derivedByLesson.get(page.id)
|
|
704
848
|
)
|
|
705
849
|
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
706
850
|
const consistencyIssues = runConsistencyChecks({
|
|
707
851
|
registry,
|
|
708
852
|
notationInput: withPages,
|
|
709
853
|
specs: loadNotationSpecs(),
|
|
710
|
-
catalog,
|
|
711
854
|
lintIgnore: loadLintIgnore(),
|
|
712
|
-
conventions: courseConfig.conventions,
|
|
713
855
|
operators: rules.settings("N8"),
|
|
714
856
|
romanLabels: rules.settings("N10"),
|
|
715
857
|
accents: rules.settings("N22")
|
|
@@ -764,6 +906,7 @@ async function compileManifest(courseConfig) {
|
|
|
764
906
|
disclosure: normalizeDisclosure(courseConfig),
|
|
765
907
|
numbering: numberingSettings,
|
|
766
908
|
blockLabels,
|
|
909
|
+
cards: normalizeCards(courseConfig),
|
|
767
910
|
about,
|
|
768
911
|
notation: {
|
|
769
912
|
definitions: registry.definitions,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { DiagnosticSeverity } from '../reference/types.js';
|
|
2
|
+
import { Manifest } from './manifest.js';
|
|
3
|
+
import '../curriculum/validation.js';
|
|
4
|
+
import '../reference/consistency.js';
|
|
5
|
+
import '../course-config-rRtME5UV.js';
|
|
6
|
+
import '../rules/catalog.js';
|
|
7
|
+
import '../rules/course-rules.js';
|
|
8
|
+
import './collections.js';
|
|
9
|
+
import '../reference/gate-retired-keys.js';
|
|
10
|
+
import '../reference/lint-ignore.js';
|
|
11
|
+
import '../reference/equations-validate.js';
|
|
12
|
+
import '../reference/tables-validate.js';
|
|
13
|
+
import '../reference/keyed-float-validate.js';
|
|
14
|
+
import '../reference/figures-validate.js';
|
|
15
|
+
import '../reference/diagrams-validate.js';
|
|
16
|
+
import '../reference/examples-validate.js';
|
|
17
|
+
import '../reference/folds-validate.js';
|
|
18
|
+
import '../reference/knowledge-checks-validate.js';
|
|
19
|
+
import '../reference/raw-floats-validate.js';
|
|
20
|
+
import '../reference/lab-katex-validate.js';
|
|
21
|
+
import '../reference/gate-math.js';
|
|
22
|
+
import '../reference/mixed-content.js';
|
|
23
|
+
import '../reference/gloss.js';
|
|
24
|
+
import '../rules/waivers.js';
|
|
25
|
+
import './knowledge-version.js';
|
|
26
|
+
import './lesson-derivation.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Diagnostics only a rendered page can give, kept from one `astro build` for
|
|
30
|
+
* `content warnings`.
|
|
31
|
+
*
|
|
32
|
+
* Most checks read the content tree, so the manifest carries them and every
|
|
33
|
+
* `content` command recomputes them. A few need the page as Astro renders it:
|
|
34
|
+
* a diagram drawn by a wrapper component lays out to a width only its render
|
|
35
|
+
* knows (rule V8, `reference/diagram-fit.ts`). `compiler/astro.ts` reports
|
|
36
|
+
* those as the build finishes and writes them to
|
|
37
|
+
* `build/render-diagnostics.json`, replacing the previous build's; the
|
|
38
|
+
* `content` CLI lists them beside the manifest's under the `render:` source.
|
|
39
|
+
* They are as current as the last build: run `pnpm build` (or `astro build`)
|
|
40
|
+
* after changing a diagram to refresh them.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
declare const RENDER_DIAGNOSTICS_PATH: string;
|
|
44
|
+
interface RenderDiagnostic {
|
|
45
|
+
readonly code: string;
|
|
46
|
+
readonly severity: DiagnosticSeverity;
|
|
47
|
+
readonly message: string;
|
|
48
|
+
/** The lesson's source file, e.g. `content/docs/motion/range.mdx`; else the built page. */
|
|
49
|
+
readonly file: string;
|
|
50
|
+
readonly lessonId?: string;
|
|
51
|
+
/** The float the finding is about, e.g. a diagram's `id`. */
|
|
52
|
+
readonly key?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The render diagnostics of one built page. A diagram that appears on more
|
|
56
|
+
* than one page (a lesson and its standalone export) is reported once per
|
|
57
|
+
* lesson by {@link writeRenderDiagnostics}.
|
|
58
|
+
*/
|
|
59
|
+
declare function pageRenderDiagnostics(manifest: Pick<Manifest, 'lessons'>, page: string, html: string): RenderDiagnostic[];
|
|
60
|
+
/** Replace the last build's render diagnostics with these, deduplicated and sorted. */
|
|
61
|
+
declare function writeRenderDiagnostics(diagnostics: readonly RenderDiagnostic[], path?: string): readonly RenderDiagnostic[];
|
|
62
|
+
/** What the last build reported; `[]` before the first build. */
|
|
63
|
+
declare function readRenderDiagnostics(path?: string): readonly RenderDiagnostic[];
|
|
64
|
+
|
|
65
|
+
export { RENDER_DIAGNOSTICS_PATH, type RenderDiagnostic, pageRenderDiagnostics, readRenderDiagnostics, writeRenderDiagnostics };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
diagramTooWideMessage,
|
|
5
|
+
oversizedDiagrams
|
|
6
|
+
} from "../reference/diagram-fit.js";
|
|
7
|
+
const RENDER_DIAGNOSTICS_PATH = join(
|
|
8
|
+
process.cwd(),
|
|
9
|
+
"build",
|
|
10
|
+
"render-diagnostics.json"
|
|
11
|
+
);
|
|
12
|
+
function slugOfPage(page) {
|
|
13
|
+
return page.split(/[\\/]/u).join("/").replace(/(^|\/)index\.html$/u, "").replace(/\.html$/u, "");
|
|
14
|
+
}
|
|
15
|
+
function pageRenderDiagnostics(manifest, page, html) {
|
|
16
|
+
const oversized = oversizedDiagrams(html);
|
|
17
|
+
if (oversized.length === 0) return [];
|
|
18
|
+
const slug = slugOfPage(page);
|
|
19
|
+
const lesson = manifest.lessons.find((candidate) => candidate.slug === slug);
|
|
20
|
+
return oversized.map((diagram) => ({
|
|
21
|
+
code: diagram.code,
|
|
22
|
+
severity: "warning",
|
|
23
|
+
message: diagramTooWideMessage(diagram.key, diagram.width, diagram.limit),
|
|
24
|
+
file: lesson?.file ?? page,
|
|
25
|
+
...lesson ? { lessonId: lesson.id } : {},
|
|
26
|
+
key: diagram.key
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
function writeRenderDiagnostics(diagnostics, path = RENDER_DIAGNOSTICS_PATH) {
|
|
30
|
+
const unique = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const diagnostic of diagnostics) {
|
|
32
|
+
unique.set(`${diagnostic.file}\0${diagnostic.code}\0${diagnostic.key ?? diagnostic.message}`, diagnostic);
|
|
33
|
+
}
|
|
34
|
+
const sorted = [...unique.values()].sort(
|
|
35
|
+
(a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code) || (a.key ?? "").localeCompare(b.key ?? "")
|
|
36
|
+
);
|
|
37
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
38
|
+
writeFileSync(path, `${JSON.stringify({ diagnostics: sorted }, null, 2)}
|
|
39
|
+
`);
|
|
40
|
+
return sorted;
|
|
41
|
+
}
|
|
42
|
+
function readRenderDiagnostics(path = RENDER_DIAGNOSTICS_PATH) {
|
|
43
|
+
if (!existsSync(path)) return [];
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
46
|
+
return Array.isArray(parsed.diagnostics) ? parsed.diagnostics : [];
|
|
47
|
+
} catch {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
RENDER_DIAGNOSTICS_PATH,
|
|
53
|
+
pageRenderDiagnostics,
|
|
54
|
+
readRenderDiagnostics,
|
|
55
|
+
writeRenderDiagnostics
|
|
56
|
+
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Manifest } from './manifest.js';
|
|
2
2
|
import '../curriculum/validation.js';
|
|
3
3
|
import '../reference/consistency.js';
|
|
4
|
-
import '../course-config-
|
|
4
|
+
import '../course-config-rRtME5UV.js';
|
|
5
5
|
import '../rules/catalog.js';
|
|
6
6
|
import '../rules/course-rules.js';
|
|
7
7
|
import './collections.js';
|
|
8
8
|
import '../reference/types.js';
|
|
9
|
+
import '../reference/gate-retired-keys.js';
|
|
9
10
|
import '../reference/lint-ignore.js';
|
|
10
11
|
import '../reference/equations-validate.js';
|
|
11
12
|
import '../reference/tables-validate.js';
|
|
@@ -138,12 +138,6 @@ interface CoursePart {
|
|
|
138
138
|
* `##` heading inside a lesson. Removed in the next MINOR release.
|
|
139
139
|
*/
|
|
140
140
|
type CourseSection = CoursePart;
|
|
141
|
-
interface CourseConventions {
|
|
142
|
-
/** Notation key a lesson's stated sign convention must resolve to. */
|
|
143
|
-
readonly signConventionKey: string;
|
|
144
|
-
/** Competency id that also counts as declaring the cash-flow perspective. */
|
|
145
|
-
readonly cashFlowPerspectiveCompetency: string;
|
|
146
|
-
}
|
|
147
141
|
/**
|
|
148
142
|
* A course's edits to the shipped named-operator baseline (`BASE_OPERATORS`),
|
|
149
143
|
* consumed by the `operator-explained` consistency check (rule N8). An operator
|
|
@@ -367,6 +361,27 @@ type BlockLabels = 'icon' | 'icon-word';
|
|
|
367
361
|
declare const BLOCK_LABELS_DEFAULT: BlockLabels;
|
|
368
362
|
/** Validate `CourseConfig.blockLabels` and apply its default. Throws on a bad value. */
|
|
369
363
|
declare function normalizeBlockLabels(config: CourseConfig): BlockLabels;
|
|
364
|
+
/**
|
|
365
|
+
* How a course's explanation cards start for a reader who has not chosen
|
|
366
|
+
* yet (`cards` in the course settings). Every field is optional;
|
|
367
|
+
* {@link normalizeCards} fills in the defaults.
|
|
368
|
+
*/
|
|
369
|
+
interface CourseCards {
|
|
370
|
+
/**
|
|
371
|
+
* Whether "Carry cards" starts on (rule K1, `card-carry.ts`): a kept card
|
|
372
|
+
* stays on screen as the page scrolls and comes along to every page of the
|
|
373
|
+
* course. A reader's own choice always wins. Default `false`.
|
|
374
|
+
*/
|
|
375
|
+
readonly carry?: boolean;
|
|
376
|
+
}
|
|
377
|
+
/** {@link CourseCards} with every default applied. */
|
|
378
|
+
interface NormalizedCards {
|
|
379
|
+
readonly carry: boolean;
|
|
380
|
+
}
|
|
381
|
+
/** The engine's defaults: a reader turns carrying on (D8). */
|
|
382
|
+
declare const CARDS_DEFAULTS: NormalizedCards;
|
|
383
|
+
/** Validate `CourseConfig.cards` and apply its defaults. Throws on a bad value. */
|
|
384
|
+
declare function normalizeCards(config: CourseConfig): NormalizedCards;
|
|
370
385
|
/**
|
|
371
386
|
* Rule S2's word ranges (`rules.S2.bridgeMinWords` … in the course settings),
|
|
372
387
|
* in the shape `gate-part-pages.ts` takes. Built by `partPageLimits` in
|
|
@@ -382,15 +397,33 @@ interface NormalizedPartPages {
|
|
|
382
397
|
readonly maxWords: number;
|
|
383
398
|
};
|
|
384
399
|
}
|
|
385
|
-
/**
|
|
400
|
+
/**
|
|
401
|
+
* Optional, build-time downloads and print actions: each chapter, each part and
|
|
402
|
+
* the course download; every page prints.
|
|
403
|
+
*/
|
|
386
404
|
interface LessonExportsConfig {
|
|
387
|
-
/** Emit one self-contained, offline-capable HTML file per
|
|
405
|
+
/** Emit one self-contained, offline-capable HTML file per page. */
|
|
388
406
|
readonly standaloneHtml?: boolean;
|
|
389
|
-
/** Offer the browser's native print dialog with explico's
|
|
407
|
+
/** Offer the browser's native print dialog with explico's print layout. */
|
|
390
408
|
readonly print?: boolean;
|
|
409
|
+
/**
|
|
410
|
+
* Emit each chapter's LaTeX source — a zipped folder with explico's class,
|
|
411
|
+
* the chapter and its figures — and the PDF compiled from that folder.
|
|
412
|
+
*/
|
|
413
|
+
readonly latex?: boolean;
|
|
414
|
+
/**
|
|
415
|
+
* Paper size of the LaTeX documents: `letter` (default, LaTeX's own) or
|
|
416
|
+
* `a4`. A plain `string` because the settings arrive as JSON.
|
|
417
|
+
*/
|
|
418
|
+
readonly latexPaper?: string;
|
|
419
|
+
/**
|
|
420
|
+
* Emit each chapter, each part and the course as Markdown — GitHub's
|
|
421
|
+
* flavour with `$…$` math, its figures as PNG — zipped with its assets.
|
|
422
|
+
*/
|
|
423
|
+
readonly markdown?: boolean;
|
|
391
424
|
/**
|
|
392
425
|
* Published course root used for links that intentionally leave the exported
|
|
393
|
-
*
|
|
426
|
+
* page. Required at export time when such a link is present.
|
|
394
427
|
*/
|
|
395
428
|
readonly canonicalBaseUrl?: string;
|
|
396
429
|
}
|
|
@@ -398,6 +431,9 @@ interface LessonExportsConfig {
|
|
|
398
431
|
interface NormalizedLessonExports {
|
|
399
432
|
readonly standaloneHtml: boolean;
|
|
400
433
|
readonly print: boolean;
|
|
434
|
+
readonly latex: boolean;
|
|
435
|
+
readonly latexPaper: 'letter' | 'a4';
|
|
436
|
+
readonly markdown: boolean;
|
|
401
437
|
readonly canonicalBaseUrl?: string;
|
|
402
438
|
}
|
|
403
439
|
interface CourseConfig {
|
|
@@ -415,7 +451,12 @@ interface CourseConfig {
|
|
|
415
451
|
readonly sections?: readonly CoursePart[];
|
|
416
452
|
/** Namespaces used by competency / notation `domain` fields. */
|
|
417
453
|
readonly domains: readonly string[];
|
|
418
|
-
|
|
454
|
+
/**
|
|
455
|
+
* @deprecated No longer read: rule S5, the only reader, was retired. A
|
|
456
|
+
* course that still sets it gets a `config-deprecated-key` warning; delete
|
|
457
|
+
* the block. Removed from the type in the next MINOR release.
|
|
458
|
+
*/
|
|
459
|
+
readonly conventions?: unknown;
|
|
419
460
|
/** Reader-facing identity + knowledge version (the `[?]` About panel). */
|
|
420
461
|
readonly about: CourseAbout;
|
|
421
462
|
/**
|
|
@@ -438,12 +479,14 @@ interface CourseConfig {
|
|
|
438
479
|
readonly romanLabels?: CourseRomanLabels;
|
|
439
480
|
/** @deprecated Moved to `rules.N14` (same shape). Honoured for now; removed in a later MINOR. */
|
|
440
481
|
readonly abbreviations?: CourseAbbreviations;
|
|
441
|
-
/** Per-
|
|
482
|
+
/** Per-page export actions and downloadable artifacts. Disabled when omitted. */
|
|
442
483
|
readonly lessonExports?: LessonExportsConfig;
|
|
443
484
|
/** Every collapse default: headings, checks, memos, floats, tables. */
|
|
444
485
|
readonly disclosure?: CourseDisclosure;
|
|
445
486
|
/** Outline and float numbering. The defaults apply when omitted. */
|
|
446
487
|
readonly numbering?: CourseNumbering;
|
|
488
|
+
/** How explanation cards start for a reader: "Carry cards" on or off. */
|
|
489
|
+
readonly cards?: CourseCards;
|
|
447
490
|
/**
|
|
448
491
|
* How a check's and an example set's heading names its kind: `icon-word`
|
|
449
492
|
* (default) or `icon` ({@link BlockLabels}). A plain `string` because the
|
|
@@ -461,4 +504,4 @@ declare function normalizeLessonExports(config: CourseConfig): NormalizedLessonE
|
|
|
461
504
|
*/
|
|
462
505
|
declare function coursePartsOf(config: CourseConfig): readonly CoursePart[];
|
|
463
506
|
|
|
464
|
-
export { type
|
|
507
|
+
export { type CourseOpenDefault as A, type BlockLabels as B, type CourseConfig as C, type CoursePart as D, type CourseSection as E, DISCLOSURE_DEFAULTS as F, coursePartsOf as G, normalizeBlockLabels as H, normalizeCards as I, normalizeDisclosure as J, normalizeLessonExports as K, type LessonExportsConfig as L, type ManifestRules as M, type NormalizedLessonExports as N, normalizeNumbering as O, type ResolvedRules as R, type NormalizedDisclosure as a, type NormalizedNumbering as b, type NormalizedCards as c, type ConfigDiagnostic as d, type CourseOperators as e, type CourseRomanLabels as f, type CourseAccents as g, type CourseAbbreviations as h, type NormalizedPartPages as i, type CourseRulesConfig as j, type RuleSettingsInput as k, catalogIds as l, disabledCodes as m, dropDisabled as n, rulesJsonSchema as o, partPageLimits as p, rulesSnapshot as q, resolveRules as r, BLOCK_LABELS_DEFAULT as s, CARDS_DEFAULTS as t, type CourseAbout as u, type CourseAuthor as v, type CourseCards as w, type CourseDisclosure as x, type CourseHeadingDisclosure as y, type CourseNumbering as z };
|