explico 0.13.1 → 0.14.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 +879 -1
- package/README.md +200 -30
- package/dist/compiler/astro.d.ts +15 -2
- package/dist/compiler/astro.js +40 -11
- package/dist/compiler/cli-main.d.ts +43 -0
- package/dist/compiler/cli-main.js +392 -0
- package/dist/compiler/cli.d.ts +424 -9
- package/dist/compiler/cli.js +1289 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +105 -1
- package/dist/compiler/decks.d.ts +161 -0
- package/dist/compiler/decks.js +235 -0
- package/dist/compiler/exports/combined-html.d.ts +5 -1
- package/dist/compiler/exports/deck-fit.d.ts +55 -0
- package/dist/compiler/exports/deck-fit.js +90 -0
- package/dist/compiler/exports/export-chapters.d.ts +37 -6
- package/dist/compiler/exports/export-chapters.js +64 -5
- package/dist/compiler/exports/export-pages.d.ts +30 -3
- package/dist/compiler/exports/export-pages.js +24 -1
- package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/dist/compiler/exports/latex/cache.d.ts +78 -0
- package/dist/compiler/exports/latex/cache.js +129 -0
- package/dist/compiler/exports/latex/capture.d.ts +10 -1
- package/dist/compiler/exports/latex/capture.js +3 -1
- package/dist/compiler/exports/latex/compile.d.ts +13 -2
- package/dist/compiler/exports/latex/compile.js +12 -1
- package/dist/compiler/exports/latex/deck.d.ts +92 -0
- package/dist/compiler/exports/latex/deck.js +349 -0
- package/dist/compiler/exports/latex/document.d.ts +51 -6
- package/dist/compiler/exports/latex/document.js +71 -12
- package/dist/compiler/exports/latex/explico-common.sty +198 -0
- package/dist/compiler/exports/latex/explico.cls +13 -183
- package/dist/compiler/exports/latex/serialize.d.ts +60 -4
- package/dist/compiler/exports/latex/serialize.js +4 -2
- package/dist/compiler/exports/latex-export.d.ts +24 -2
- package/dist/compiler/exports/latex-export.js +107 -26
- package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
- package/dist/compiler/exports/markdown/serialize.js +85 -8
- package/dist/compiler/exports/markdown-export.d.ts +6 -1
- package/dist/compiler/exports/markdown-export.js +50 -11
- package/dist/compiler/exports/standalone-html.d.ts +10 -5
- package/dist/compiler/exports/standalone-html.js +3 -3
- package/dist/compiler/exports/static-tree.d.ts +38 -1
- package/dist/compiler/exports/static-tree.js +120 -4
- package/dist/compiler/knowledge-version.d.ts +26 -2
- package/dist/compiler/knowledge-version.js +27 -17
- package/dist/compiler/lesson-derivation.d.ts +143 -6
- package/dist/compiler/lesson-derivation.js +145 -13
- package/dist/compiler/manifest.d.ts +133 -4
- package/dist/compiler/manifest.js +359 -58
- package/dist/compiler/page-versions.d.ts +160 -0
- package/dist/compiler/page-versions.js +198 -0
- package/dist/compiler/render-diagnostics.d.ts +5 -1
- package/dist/compiler/resolution-report.d.ts +24 -6
- package/dist/compiler/resolution-report.js +22 -4
- package/dist/compiler/validate-content.d.ts +7 -0
- package/dist/compiler/validate-content.js +160 -0
- package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
- package/dist/curriculum/competency-graph.d.ts +54 -0
- package/dist/curriculum/competency-graph.js +41 -0
- package/dist/reference/base-library.d.mts +8 -0
- package/dist/reference/base-library.mjs +19 -0
- package/dist/reference/consistency.d.ts +8 -4
- package/dist/reference/consistency.js +76 -26
- package/dist/reference/deck-remark.d.mts +123 -0
- package/dist/reference/deck-remark.mjs +600 -0
- package/dist/reference/deck-source.d.ts +107 -0
- package/dist/reference/deck-source.js +140 -0
- package/dist/reference/decks-validate.d.ts +133 -0
- package/dist/reference/decks-validate.js +359 -0
- package/dist/reference/derived-entries.d.ts +5 -1
- package/dist/reference/diagram-fit.d.ts +1 -1
- package/dist/reference/figure-symbols.d.ts +23 -6
- package/dist/reference/figure-symbols.js +51 -15
- package/dist/reference/float-name.d.ts +43 -0
- package/dist/reference/float-name.js +58 -0
- package/dist/reference/folds-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-indices.js +5 -4
- package/dist/reference/gate-math.d.ts +29 -2
- package/dist/reference/gate-math.js +99 -18
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/lab-katex-validate.d.ts +10 -6
- package/dist/reference/lab-katex-validate.js +17 -9
- package/dist/reference/lab-math-scope.js +29 -4
- package/dist/reference/math-glyphs.d.mts +25 -0
- package/dist/reference/math-glyphs.mjs +189 -25
- package/dist/reference/page-notation.d.ts +22 -3
- package/dist/reference/page-notation.js +32 -10
- package/dist/reference/references.d.ts +14 -1
- package/dist/reference/references.js +13 -0
- package/dist/reference/registry-scope.d.mts +33 -0
- package/dist/reference/registry-scope.mjs +34 -0
- package/dist/reference/registry.js +29 -10
- package/dist/reference/rehype-deck.d.mts +6 -0
- package/dist/reference/rehype-deck.mjs +286 -0
- package/dist/reference/rehype-heading-anchors.d.mts +20 -0
- package/dist/reference/rehype-heading-anchors.mjs +48 -6
- package/dist/reference/remark-notation.mjs +249 -40
- package/dist/reference/source-lines.d.mts +12 -0
- package/dist/reference/source-lines.mjs +65 -0
- package/dist/reference/types.d.ts +28 -0
- package/dist/rules/catalog.d.ts +21 -4
- package/dist/rules/catalog.js +221 -2
- package/dist/rules/course-rules.d.ts +5 -1
- package/dist/rules/course-rules.js +17 -3
- package/dist/rules/course-rules.schema.json +12 -0
- package/dist/rules/in-effect.d.ts +13 -3
- package/dist/rules/in-effect.js +30 -7
- package/dist/rules/rules.schema.json +259 -1
- package/dist/rules/settings.d.ts +1 -1
- package/dist/session/PreferenceStore.d.ts +6 -0
- package/dist/session/PreferenceStore.js +18 -1
- package/dist/session/deck-memory.d.ts +116 -0
- package/dist/session/deck-memory.js +143 -0
- package/dist/session/reading-memory.d.ts +96 -0
- package/dist/session/reading-memory.js +133 -0
- package/docs/VERSIONING.md +21 -18
- package/docs/authoring/README.md +29 -9
- package/docs/authoring/agents.md +63 -16
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +588 -0
- package/docs/authoring/migrating.md +1045 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +54 -2
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +37 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
- package/docs/course-agent/skills/release-content/SKILL.md +24 -0
- package/docs/diagram-scaling.md +148 -0
- package/docs/privacy.md +59 -0
- package/package.json +8 -2
- package/src/compiler/astro.ts +60 -21
- package/src/compiler/cli-main.ts +469 -0
- package/src/compiler/cli.ts +1905 -16
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/course-config.ts +267 -0
- package/src/compiler/decks.ts +455 -0
- package/src/compiler/exports/deck-fit.ts +127 -0
- package/src/compiler/exports/export-chapters.ts +105 -6
- package/src/compiler/exports/export-pages.ts +46 -2
- package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/src/compiler/exports/latex/cache.ts +183 -0
- package/src/compiler/exports/latex/capture.ts +5 -2
- package/src/compiler/exports/latex/compile.ts +18 -0
- package/src/compiler/exports/latex/deck.ts +419 -0
- package/src/compiler/exports/latex/document.ts +117 -21
- package/src/compiler/exports/latex/explico-common.sty +198 -0
- package/src/compiler/exports/latex/explico.cls +13 -183
- package/src/compiler/exports/latex/serialize.ts +25 -21
- package/src/compiler/exports/latex/texlive-packages.txt +6 -2
- package/src/compiler/exports/latex-export.ts +187 -45
- package/src/compiler/exports/markdown/serialize.ts +118 -9
- package/src/compiler/exports/markdown-export.ts +56 -11
- package/src/compiler/exports/standalone-html.ts +8 -7
- package/src/compiler/exports/static-tree.ts +175 -3
- package/src/compiler/knowledge-version.ts +56 -21
- package/src/compiler/lesson-derivation.ts +282 -16
- package/src/compiler/manifest.ts +558 -63
- package/src/compiler/page-versions.ts +359 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +212 -0
- package/src/components/CourseContents.astro +124 -6
- package/src/components/CurriculumMap.astro +49 -1
- package/src/components/FloatIndex.astro +1 -1
- package/src/components/PartOverview.astro +51 -5
- package/src/components/assessments/AssessmentSet.astro +41 -15
- package/src/components/block-heading.ts +15 -6
- package/src/components/card-carry.ts +7 -4
- package/src/components/card-manager.ts +14 -2
- package/src/components/card-memory.ts +13 -9
- package/src/components/deck/DeckEnhancer.astro +13 -0
- package/src/components/deck/deck-context.ts +104 -0
- package/src/components/deck/deck-controller.ts +1287 -0
- package/src/components/deck/deck-map.ts +91 -0
- package/src/components/deck-lane.ts +163 -0
- package/src/components/diagram/Diagram.astro +131 -86
- package/src/components/disclosure/persisted-disclosure.ts +9 -1
- package/src/components/figure/Figure.astro +7 -2
- package/src/components/figure/FloatCaption.astro +5 -3
- package/src/components/fold/Fold.astro +2 -2
- package/src/components/notation/NotationFormula.astro +81 -11
- package/src/components/notation/NotationGlossary.astro +132 -1
- package/src/components/notation/NotationLayer.astro +15 -7
- package/src/components/starlight/AboutPanel.astro +186 -3
- package/src/components/starlight/CollapsibleSections.astro +24 -3
- package/src/components/starlight/DiagramEnhancer.astro +5 -1
- package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
- package/src/components/starlight/LayoutHeader.astro +17 -0
- package/src/components/starlight/LayoutPageTitle.astro +110 -0
- package/src/components/starlight/LayoutSidebar.astro +807 -21
- package/src/components/starlight/LayoutSocialIcons.astro +62 -6
- package/src/components/starlight/LessonExportActions.astro +27 -9
- package/src/components/starlight/LessonFooter.astro +59 -0
- package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
- package/src/components/starlight/TextSizeControl.astro +24 -13
- package/src/components/starlight/page-marks.ts +139 -0
- package/src/components/starlight/section-summary.ts +1 -1
- package/src/components/starlight/sidebar-editions.ts +245 -0
- package/src/components/table/Table.astro +15 -7
- package/src/content-config.ts +87 -1
- package/src/curriculum/competency-graph.ts +95 -0
- package/src/reference/base-library.mjs +19 -0
- package/src/reference/consistency.ts +126 -39
- package/src/reference/deck-remark.mjs +600 -0
- package/src/reference/deck-source.ts +273 -0
- package/src/reference/decks-validate.ts +604 -0
- package/src/reference/diagram-layout.ts +3 -1
- package/src/reference/figure-symbols.ts +108 -31
- package/src/reference/folds-validate.ts +1 -1
- package/src/reference/gate-indices.ts +5 -3
- package/src/reference/gate-math.ts +169 -25
- package/src/reference/lab-katex-validate.ts +30 -15
- package/src/reference/lab-math-scope.ts +34 -3
- package/src/reference/math-glyphs.mjs +189 -25
- package/src/reference/page-notation.ts +69 -15
- package/src/reference/references.ts +28 -0
- package/src/reference/registry-scope.mjs +34 -0
- package/src/reference/registry.ts +41 -11
- package/src/reference/rehype-deck.mjs +286 -0
- package/src/reference/rehype-heading-anchors.mjs +48 -6
- package/src/reference/remark-notation.mjs +249 -40
- package/src/reference/source-lines.mjs +65 -0
- package/src/reference/types.ts +28 -0
- package/src/rules/catalog.ts +257 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +54 -8
- package/src/session/PreferenceStore.ts +23 -0
- package/src/session/deck-memory.ts +263 -0
- package/src/session/reading-memory.ts +243 -0
- package/src/styles/deck.css +1150 -0
- package/src/styles/global.css +958 -27
- package/src/styles/zones.css +277 -0
- /package/src/{components → reference}/float-name.ts +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/** A step mark, `<Pause />`, with the props of a driven figure or a spotlight. */
|
|
2
|
+
interface DeckPause {
|
|
3
|
+
/** Offset of the tag in the deck body. */
|
|
4
|
+
readonly index: number;
|
|
5
|
+
/** The label of the lab control a driven figure moves. */
|
|
6
|
+
readonly control?: string;
|
|
7
|
+
readonly from?: string;
|
|
8
|
+
readonly to?: string;
|
|
9
|
+
readonly seconds?: string;
|
|
10
|
+
/** A notation key whose every occurrence on the frame lights up. */
|
|
11
|
+
readonly highlight?: string;
|
|
12
|
+
/** Any prop the deck grammar does not know, by name. */
|
|
13
|
+
readonly unknown: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
interface DeckRecall {
|
|
16
|
+
readonly index: number;
|
|
17
|
+
/** As written: `eq-range`, `fig-projectile-trajectory`, `tab-…`, `dia-…`. */
|
|
18
|
+
readonly ref?: string;
|
|
19
|
+
}
|
|
20
|
+
interface DeckFloatTag {
|
|
21
|
+
readonly index: number;
|
|
22
|
+
readonly name: 'Figure' | 'Table' | 'Diagram' | 'CompactExamples' | 'AssessmentSet';
|
|
23
|
+
readonly id?: string;
|
|
24
|
+
}
|
|
25
|
+
interface DeckMath {
|
|
26
|
+
readonly index: number;
|
|
27
|
+
readonly latex: string;
|
|
28
|
+
}
|
|
29
|
+
interface DeckFrameSource {
|
|
30
|
+
/** `section`: a `##` divider frame; `frame`: a `###` frame. */
|
|
31
|
+
readonly kind: 'section' | 'frame';
|
|
32
|
+
/** What the reader sees: math as it reads, a `[[key]]` term as its label. */
|
|
33
|
+
readonly title: string;
|
|
34
|
+
/** The heading's anchor, as the page gives it. */
|
|
35
|
+
readonly slug: string;
|
|
36
|
+
/** `### Title [morph]`: the frame morphs from the one before it. */
|
|
37
|
+
readonly morph: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* `## Title [chapter: <slug>]` on a part's deck: the chapter the section
|
|
40
|
+
* covers, as written (the chapter's name in the part's directory). A `###`
|
|
41
|
+
* frame carries its section's.
|
|
42
|
+
*/
|
|
43
|
+
readonly chapter?: string;
|
|
44
|
+
/** Offset of the heading line in the deck body. */
|
|
45
|
+
readonly index: number;
|
|
46
|
+
/** Offset where the frame's body ends (the next frame's heading, or the end). */
|
|
47
|
+
readonly end: number;
|
|
48
|
+
/** The slug of the `##` section the frame is in, if any. */
|
|
49
|
+
readonly section?: string;
|
|
50
|
+
/** The frame's body source, after its heading line. */
|
|
51
|
+
readonly body: string;
|
|
52
|
+
/** Offset of {@link body} in the deck body. */
|
|
53
|
+
readonly bodyIndex: number;
|
|
54
|
+
readonly pauses: readonly DeckPause[];
|
|
55
|
+
/** Each `<Notes>…</Notes>` block's inner text. */
|
|
56
|
+
readonly notes: readonly {
|
|
57
|
+
readonly index: number;
|
|
58
|
+
readonly text: string;
|
|
59
|
+
}[];
|
|
60
|
+
readonly recalls: readonly DeckRecall[];
|
|
61
|
+
readonly floats: readonly DeckFloatTag[];
|
|
62
|
+
/** Display equations in the frame's own text (not its notes). */
|
|
63
|
+
readonly displayMath: readonly DeckMath[];
|
|
64
|
+
/** Words a reader sees on the frame: its prose, not its math, tags or notes. */
|
|
65
|
+
readonly words: number;
|
|
66
|
+
/** List items on the frame. */
|
|
67
|
+
readonly bullets: number;
|
|
68
|
+
}
|
|
69
|
+
interface DeckSource {
|
|
70
|
+
/** Every section divider and frame, in order. */
|
|
71
|
+
readonly frames: readonly DeckFrameSource[];
|
|
72
|
+
/** Headings a deck cannot hold: `#`, and `####` or deeper (rule D1). */
|
|
73
|
+
readonly deepHeadings: readonly {
|
|
74
|
+
readonly index: number;
|
|
75
|
+
readonly level: number;
|
|
76
|
+
readonly text: string;
|
|
77
|
+
}[];
|
|
78
|
+
/**
|
|
79
|
+
* Content that belongs to no frame (rule D1): before the first heading, or
|
|
80
|
+
* under a `##` before its first `###`.
|
|
81
|
+
*/
|
|
82
|
+
readonly loose: readonly {
|
|
83
|
+
readonly index: number;
|
|
84
|
+
readonly where: 'before' | 'section';
|
|
85
|
+
}[];
|
|
86
|
+
/** A heading marker on the wrong level: `[chapter: …]` on a `###`, `[morph]` on a `##`. */
|
|
87
|
+
readonly misplacedMarkers: readonly {
|
|
88
|
+
readonly index: number;
|
|
89
|
+
readonly marker: 'chapter' | 'morph';
|
|
90
|
+
readonly title: string;
|
|
91
|
+
}[];
|
|
92
|
+
}
|
|
93
|
+
/** A component tag's string props, by name. */
|
|
94
|
+
declare function tagProps(source: string): Map<string, string>;
|
|
95
|
+
/** The words a frame shows: its prose, without math, tags, comments, citations or notes. */
|
|
96
|
+
declare function visibleWords(text: string): number;
|
|
97
|
+
/**
|
|
98
|
+
* Read a deck body as frames. `labelFor` names a `[[key]]` term in a heading
|
|
99
|
+
* as the reader sees it, as for a chapter's outline.
|
|
100
|
+
*/
|
|
101
|
+
declare function readDeckSource(body: string, options?: {
|
|
102
|
+
readonly labelFor?: (key: string) => string | undefined;
|
|
103
|
+
}): DeckSource;
|
|
104
|
+
/** The frame an offset of the deck body falls in, if any. */
|
|
105
|
+
declare function frameAt(source: DeckSource, index: number): DeckFrameSource | undefined;
|
|
106
|
+
|
|
107
|
+
export { type DeckFloatTag, type DeckFrameSource, type DeckMath, type DeckPause, type DeckRecall, type DeckSource, frameAt, readDeckSource, tagProps, visibleWords };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { stripFencedCode } from "./equations.mjs";
|
|
2
|
+
import { headingChapter, headingMorphs } from "./rehype-heading-anchors.mjs";
|
|
3
|
+
import { scanOutlineBlocks, scanSectionHeadings } from "./sections.mjs";
|
|
4
|
+
const FLOAT_NAMES = ["Figure", "Table", "Diagram", "CompactExamples", "AssessmentSet"];
|
|
5
|
+
const FLOAT_TAG = new RegExp(`<(${FLOAT_NAMES.join("|")})\\b((?:"[^"]*"|'[^']*'|[^>"'])*)>`, "g");
|
|
6
|
+
const PAUSE_TAG = /<Pause\b((?:"[^"]*"|'[^']*'|[^>"'])*)\/?>/g;
|
|
7
|
+
const RECALL_TAG = /<Recall\b((?:"[^"]*"|'[^']*'|[^>"'])*)\/?>/g;
|
|
8
|
+
const NOTES_BLOCK = /<Notes\s*>([\s\S]*?)<\/Notes\s*>/g;
|
|
9
|
+
const DISPLAY_MATH = /\$\$([\s\S]+?)\$\$/g;
|
|
10
|
+
const PROP = /([A-Za-z][\w-]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
11
|
+
const PAUSE_PROPS = /* @__PURE__ */ new Set(["control", "from", "to", "seconds", "highlight"]);
|
|
12
|
+
function tagProps(source) {
|
|
13
|
+
const props = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const match of source.matchAll(PROP)) {
|
|
15
|
+
props.set(match[1] ?? "", match[2] ?? match[3] ?? "");
|
|
16
|
+
}
|
|
17
|
+
return props;
|
|
18
|
+
}
|
|
19
|
+
function blankMatches(text, pattern) {
|
|
20
|
+
return text.replace(pattern, (match) => match.replace(/[^\n]/g, " "));
|
|
21
|
+
}
|
|
22
|
+
function visibleWords(text) {
|
|
23
|
+
const prose = text.replace(NOTES_BLOCK, " ").replace(/\{\/\*[\s\S]*?\*\/\}/g, " ").replace(/\$\$[\s\S]+?\$\$/g, " ").replace(/\$[^$\n]+\$/g, " ").replace(/\[@[^\]]*\]/g, " ").replace(/\[\[\s*[^\][]+?\s*\]\]/g, " term ").replace(/<\/?[A-Za-z][^>]*>/g, " ").replace(/^[ \t]*(?:import|export)\s.*$/gm, " ").replace(/[#>*_`|~-]/g, " ");
|
|
24
|
+
return (prose.match(/[\p{L}\p{N}][\p{L}\p{N}'’.-]*/gu) ?? []).length;
|
|
25
|
+
}
|
|
26
|
+
function bulletCount(text) {
|
|
27
|
+
return (text.replace(NOTES_BLOCK, " ").match(/^[ \t]*(?:[-*+]|\d+[.)])[ \t]+\S/gm) ?? []).length;
|
|
28
|
+
}
|
|
29
|
+
function readDeckSource(body, options = {}) {
|
|
30
|
+
const source = String(body);
|
|
31
|
+
const blocks = scanOutlineBlocks(source);
|
|
32
|
+
const headings = scanSectionHeadings(source, { labelFor: options.labelFor });
|
|
33
|
+
const scanText = stripFencedCode(source);
|
|
34
|
+
const deepHeadings = [];
|
|
35
|
+
const loose = [];
|
|
36
|
+
const starts = [];
|
|
37
|
+
let headingCursor = -1;
|
|
38
|
+
let current;
|
|
39
|
+
for (const block of blocks) {
|
|
40
|
+
if (block.kind === "heading") {
|
|
41
|
+
headingCursor += 1;
|
|
42
|
+
const heading = headings[headingCursor];
|
|
43
|
+
if (heading === void 0) continue;
|
|
44
|
+
if (block.level === 2 || block.level === 3) {
|
|
45
|
+
const lineEnd = source.indexOf("\n", block.index);
|
|
46
|
+
starts.push({
|
|
47
|
+
index: block.index,
|
|
48
|
+
level: block.level,
|
|
49
|
+
heading,
|
|
50
|
+
lineEnd: lineEnd === -1 ? source.length : lineEnd + 1
|
|
51
|
+
});
|
|
52
|
+
current = block.level;
|
|
53
|
+
} else {
|
|
54
|
+
deepHeadings.push({ index: block.index, level: block.level, text: heading.text });
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (current === void 0) loose.push({ index: block.index, where: "before" });
|
|
59
|
+
else if (current === 2) loose.push({ index: block.index, where: "section" });
|
|
60
|
+
}
|
|
61
|
+
const frames = [];
|
|
62
|
+
const misplacedMarkers = [];
|
|
63
|
+
let section;
|
|
64
|
+
let sectionChapter;
|
|
65
|
+
starts.forEach((start, position) => {
|
|
66
|
+
const end = starts[position + 1]?.index ?? source.length;
|
|
67
|
+
const bodyIndex = Math.min(start.lineEnd, end);
|
|
68
|
+
const frameBody = source.slice(bodyIndex, end);
|
|
69
|
+
const frameScan = scanText.slice(bodyIndex, end);
|
|
70
|
+
const withoutNotes = blankMatches(frameScan, NOTES_BLOCK);
|
|
71
|
+
const at = (offset) => bodyIndex + (offset ?? 0);
|
|
72
|
+
const headingText = source.slice(start.index, start.lineEnd).replace(/^[ \t]*#{1,6}[ \t]+/, "").trimEnd();
|
|
73
|
+
const morphs = headingMorphs(headingText);
|
|
74
|
+
const named = headingChapter(headingText) ?? void 0;
|
|
75
|
+
if (start.level === 2) {
|
|
76
|
+
section = start.heading.slug;
|
|
77
|
+
sectionChapter = named;
|
|
78
|
+
if (morphs) misplacedMarkers.push({ index: start.index, marker: "morph", title: start.heading.text });
|
|
79
|
+
} else if (named !== void 0) {
|
|
80
|
+
misplacedMarkers.push({ index: start.index, marker: "chapter", title: start.heading.text });
|
|
81
|
+
}
|
|
82
|
+
frames.push({
|
|
83
|
+
kind: start.level === 2 ? "section" : "frame",
|
|
84
|
+
title: start.heading.text,
|
|
85
|
+
slug: start.heading.slug,
|
|
86
|
+
morph: start.level === 3 && morphs,
|
|
87
|
+
...sectionChapter === void 0 ? {} : { chapter: sectionChapter },
|
|
88
|
+
index: start.index,
|
|
89
|
+
end,
|
|
90
|
+
...start.level === 3 && section !== void 0 ? { section } : {},
|
|
91
|
+
body: frameBody,
|
|
92
|
+
bodyIndex,
|
|
93
|
+
pauses: [...withoutNotes.matchAll(PAUSE_TAG)].map((match) => {
|
|
94
|
+
const props = tagProps(match[1] ?? "");
|
|
95
|
+
const value = (name) => props.get(name);
|
|
96
|
+
return {
|
|
97
|
+
index: at(match.index),
|
|
98
|
+
...value("control") === void 0 ? {} : { control: value("control") },
|
|
99
|
+
...value("from") === void 0 ? {} : { from: value("from") },
|
|
100
|
+
...value("to") === void 0 ? {} : { to: value("to") },
|
|
101
|
+
...value("seconds") === void 0 ? {} : { seconds: value("seconds") },
|
|
102
|
+
...value("highlight") === void 0 ? {} : { highlight: value("highlight") },
|
|
103
|
+
unknown: [...props.keys()].filter((name) => !PAUSE_PROPS.has(name))
|
|
104
|
+
};
|
|
105
|
+
}),
|
|
106
|
+
notes: [...frameScan.matchAll(NOTES_BLOCK)].map((match) => ({
|
|
107
|
+
index: at(match.index),
|
|
108
|
+
text: match[1] ?? ""
|
|
109
|
+
})),
|
|
110
|
+
recalls: [...withoutNotes.matchAll(RECALL_TAG)].map((match) => {
|
|
111
|
+
const ref = tagProps(match[1] ?? "").get("ref");
|
|
112
|
+
return { index: at(match.index), ...ref === void 0 ? {} : { ref } };
|
|
113
|
+
}),
|
|
114
|
+
floats: [...withoutNotes.matchAll(FLOAT_TAG)].map((match) => {
|
|
115
|
+
const id = tagProps(match[2] ?? "").get("id");
|
|
116
|
+
return {
|
|
117
|
+
index: at(match.index),
|
|
118
|
+
name: match[1],
|
|
119
|
+
...id === void 0 ? {} : { id }
|
|
120
|
+
};
|
|
121
|
+
}),
|
|
122
|
+
displayMath: [...withoutNotes.matchAll(DISPLAY_MATH)].map((match) => ({
|
|
123
|
+
index: at(match.index),
|
|
124
|
+
latex: match[1] ?? ""
|
|
125
|
+
})),
|
|
126
|
+
words: start.level === 3 ? visibleWords(withoutNotes) : 0,
|
|
127
|
+
bullets: start.level === 3 ? bulletCount(withoutNotes) : 0
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
return { frames, deepHeadings, loose, misplacedMarkers };
|
|
131
|
+
}
|
|
132
|
+
function frameAt(source, index) {
|
|
133
|
+
return source.frames.find((frame) => index >= frame.index && index < frame.end);
|
|
134
|
+
}
|
|
135
|
+
export {
|
|
136
|
+
frameAt,
|
|
137
|
+
readDeckSource,
|
|
138
|
+
tagProps,
|
|
139
|
+
visibleWords
|
|
140
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { MathGateDiagnostic } from './gate-math.js';
|
|
2
|
+
import { DeckSource } from './deck-source.js';
|
|
3
|
+
import './types.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The deck rules (`docs/authoring/deck.md`): the `D` area and the `decks`
|
|
7
|
+
* invariant, over each deck read as frames (`deck-source.ts`). One pass per
|
|
8
|
+
* deck; the manifest runs it and drops the codes of a rule the course turned
|
|
9
|
+
* off, as for every gate.
|
|
10
|
+
*
|
|
11
|
+
* What it cannot see is the rendered fit of a frame (rule D2's
|
|
12
|
+
* `frame-overflow`), which the build measures in a browser after Astro has
|
|
13
|
+
* built the deck.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* What a chapter numbers, by kind: each key with its number, and an
|
|
18
|
+
* equation's LaTeX (for rule D8's retyped check). What a deck may recall.
|
|
19
|
+
*/
|
|
20
|
+
interface ChapterFloats {
|
|
21
|
+
readonly equations: ReadonlyMap<string, {
|
|
22
|
+
readonly number: string;
|
|
23
|
+
readonly latex?: string;
|
|
24
|
+
}>;
|
|
25
|
+
readonly figures: ReadonlyMap<string, string>;
|
|
26
|
+
readonly tables: ReadonlyMap<string, string>;
|
|
27
|
+
readonly diagrams: ReadonlyMap<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/** A part, as its deck's rules see it (`<part>/index.deck.mdx`). */
|
|
30
|
+
interface PartDeckFacts {
|
|
31
|
+
/** The part's directory: `motion`. */
|
|
32
|
+
readonly dir: string;
|
|
33
|
+
/**
|
|
34
|
+
* The part's chapters in reading order: each by its name in the part's
|
|
35
|
+
* directory (what `[chapter: <name>]` writes), with its lesson slug and
|
|
36
|
+
* what it numbers.
|
|
37
|
+
*/
|
|
38
|
+
readonly chapters: readonly {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly slug: string;
|
|
41
|
+
readonly floats: ChapterFloats;
|
|
42
|
+
}[];
|
|
43
|
+
/** The part's lessons that are only slides, by name: they have no chapter to cover. */
|
|
44
|
+
readonly slidesFirst?: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
/** One deck, as the manifest hands it to the rules. */
|
|
47
|
+
interface DeckValidationInput {
|
|
48
|
+
/** Repository-relative path of the deck file. */
|
|
49
|
+
readonly file: string;
|
|
50
|
+
/** The deck's page id (`motion.range.slides`, the lesson's own, or a part's `motion.slides`). */
|
|
51
|
+
readonly pageId: string;
|
|
52
|
+
/** True when the lesson has a chapter beside the deck. */
|
|
53
|
+
readonly hasChapter: boolean;
|
|
54
|
+
/** True when the deck sits in a part's directory, as a lesson does. */
|
|
55
|
+
readonly inPart: boolean;
|
|
56
|
+
readonly body: string;
|
|
57
|
+
/** 1-based file line the body starts on. */
|
|
58
|
+
readonly bodyLine: number;
|
|
59
|
+
/** The deck file's frontmatter. */
|
|
60
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
61
|
+
readonly source: DeckSource;
|
|
62
|
+
/** What the deck may recall from its chapter, by kind. */
|
|
63
|
+
readonly chapter?: ChapterFloats;
|
|
64
|
+
/** A part's deck: its part, whose chapters its sections may cover. */
|
|
65
|
+
readonly part?: PartDeckFacts;
|
|
66
|
+
/** Per frame of {@link source}, the notation keys it shows for the first time in the deck. */
|
|
67
|
+
readonly newSymbols?: readonly (readonly string[])[];
|
|
68
|
+
}
|
|
69
|
+
/** One chapter a part deck's section covers. */
|
|
70
|
+
interface CoveredChapter {
|
|
71
|
+
readonly name: string;
|
|
72
|
+
readonly slug: string;
|
|
73
|
+
readonly floats: ChapterFloats;
|
|
74
|
+
/** The section's place in {@link DeckSource.frames}: its divider. */
|
|
75
|
+
readonly position: number;
|
|
76
|
+
}
|
|
77
|
+
/** What a part's deck recalls, and from where (`resolvePartRecalls`). */
|
|
78
|
+
interface PartRecalls {
|
|
79
|
+
/** The chapters its sections cover, in deck order, each once. */
|
|
80
|
+
readonly covered: readonly CoveredChapter[];
|
|
81
|
+
/** Each frame's chapter, by its place in {@link DeckSource.frames}: its section's, when that names one of the part. */
|
|
82
|
+
readonly frameChapters: readonly (CoveredChapter | undefined)[];
|
|
83
|
+
/** The chapter each recalled float is the chapter's own, by its ref (`eq-range`). */
|
|
84
|
+
readonly chapterOf: ReadonlyMap<string, CoveredChapter>;
|
|
85
|
+
/** Why a recall names nothing, by its offset in the deck body. */
|
|
86
|
+
readonly problems: ReadonlyMap<number, string>;
|
|
87
|
+
}
|
|
88
|
+
/** The number a chapter gives the float `ref` names (`eq-range`, `fig-…`), if it numbers one. */
|
|
89
|
+
declare function chapterNumberOf(ref: string, floats: ChapterFloats | undefined): string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* The chapters a part deck's sections cover: each a `## Title [chapter:
|
|
92
|
+
* <name>]` whose name is one of `chapters`, in deck order and once (a
|
|
93
|
+
* repeat is the same chapter), with the place of its divider in
|
|
94
|
+
* `source.frames`; and each frame's chapter, its section's. The divider's
|
|
95
|
+
* frame number is that place plus 2, after the title frame.
|
|
96
|
+
*/
|
|
97
|
+
declare function coveredSections(source: DeckSource, chapters: ReadonlySet<string>): {
|
|
98
|
+
readonly covered: readonly {
|
|
99
|
+
readonly name: string;
|
|
100
|
+
readonly position: number;
|
|
101
|
+
}[];
|
|
102
|
+
readonly frameChapters: readonly (string | undefined)[];
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Where each recall of a part's deck comes from. A section that names a
|
|
106
|
+
* chapter covers it; a recall is the float of the chapter its section
|
|
107
|
+
* covers when that chapter numbers it, and otherwise of the one other
|
|
108
|
+
* covered chapter that does. Two that do, with neither the section's own,
|
|
109
|
+
* or a ref one frame recalls from one chapter and another from a second,
|
|
110
|
+
* name no float of their own: a deck page holds one float per anchor.
|
|
111
|
+
*/
|
|
112
|
+
declare function resolvePartRecalls(source: DeckSource, part: PartDeckFacts): PartRecalls;
|
|
113
|
+
interface DeckRuleSettings {
|
|
114
|
+
/** D2 */
|
|
115
|
+
readonly maxWords: number;
|
|
116
|
+
readonly maxBullets: number;
|
|
117
|
+
/** D5 */
|
|
118
|
+
readonly maxTitleLength: number;
|
|
119
|
+
/** D6 */
|
|
120
|
+
readonly maxSteps: number;
|
|
121
|
+
/** D9 */
|
|
122
|
+
readonly maxNewSymbols: number;
|
|
123
|
+
}
|
|
124
|
+
declare const DECK_RULE_DEFAULTS: DeckRuleSettings;
|
|
125
|
+
/**
|
|
126
|
+
* A display equation's LaTeX as rule D8 compares it: no `\label` or
|
|
127
|
+
* `\caption`, each `\explain{key}{body}` as its body, no spacing commands, no
|
|
128
|
+
* `\left` / `\right`, no whitespace.
|
|
129
|
+
*/
|
|
130
|
+
declare function comparableLatex(latex: string): string;
|
|
131
|
+
declare function validateDecks(decks: readonly DeckValidationInput[], settings?: DeckRuleSettings): MathGateDiagnostic[];
|
|
132
|
+
|
|
133
|
+
export { type ChapterFloats, type CoveredChapter, DECK_RULE_DEFAULTS, type DeckRuleSettings, type DeckValidationInput, type PartDeckFacts, type PartRecalls, chapterNumberOf, comparableLatex, coveredSections, resolvePartRecalls, validateDecks };
|