explico 0.1.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/README.md +108 -0
- package/dist/analytics/AnalyticsEmitter.d.ts +22 -0
- package/dist/analytics/AnalyticsEmitter.js +5 -0
- package/dist/compiler/cli.d.ts +189 -0
- package/dist/compiler/cli.js +552 -0
- package/dist/compiler/collections.d.ts +70 -0
- package/dist/compiler/collections.js +383 -0
- package/dist/compiler/course-config.d.ts +31 -0
- package/dist/compiler/course-config.js +0 -0
- package/dist/compiler/lesson-derivation.d.ts +89 -0
- package/dist/compiler/lesson-derivation.js +91 -0
- package/dist/compiler/manifest.d.ts +178 -0
- package/dist/compiler/manifest.js +345 -0
- package/dist/compiler/resolution-report.d.ts +45 -0
- package/dist/compiler/resolution-report.js +97 -0
- package/dist/curriculum/validation.d.ts +76 -0
- package/dist/curriculum/validation.js +320 -0
- package/dist/progress/ProgressRepository.d.ts +53 -0
- package/dist/progress/ProgressRepository.js +12 -0
- package/dist/reference/base-library.mjs +27 -0
- package/dist/reference/citation-format.mjs +133 -0
- package/dist/reference/consistency.d.ts +64 -0
- package/dist/reference/consistency.js +234 -0
- package/dist/reference/curriculum-alignment.d.ts +7 -0
- package/dist/reference/curriculum-alignment.js +166 -0
- package/dist/reference/equations-validate.d.ts +50 -0
- package/dist/reference/equations-validate.js +90 -0
- package/dist/reference/equations.mjs +144 -0
- package/dist/reference/gate-math.d.ts +41 -0
- package/dist/reference/gate-math.js +151 -0
- package/dist/reference/katex-options.mjs +91 -0
- package/dist/reference/lab-math-scope.d.ts +21 -0
- package/dist/reference/lab-math-scope.js +28 -0
- package/dist/reference/label.d.ts +11 -0
- package/dist/reference/label.js +38 -0
- package/dist/reference/lint-ignore.d.ts +32 -0
- package/dist/reference/lint-ignore.js +39 -0
- package/dist/reference/math-glyphs.mjs +830 -0
- package/dist/reference/prose.d.ts +15 -0
- package/dist/reference/prose.js +12 -0
- package/dist/reference/references.d.ts +17 -0
- package/dist/reference/references.js +42 -0
- package/dist/reference/registry.d.ts +6 -0
- package/dist/reference/registry.js +548 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +55 -0
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +753 -0
- package/dist/reference/render-lab-math.d.ts +21 -0
- package/dist/reference/render-lab-math.js +58 -0
- package/dist/reference/types.d.ts +151 -0
- package/dist/reference/types.js +0 -0
- package/dist/reference/units-vocab.d.ts +26 -0
- package/dist/reference/units-vocab.js +119 -0
- package/dist/session/PreferenceStore.d.ts +28 -0
- package/dist/session/PreferenceStore.js +30 -0
- package/dist/session/user-context.d.ts +7 -0
- package/dist/session/user-context.js +10 -0
- package/dist/session/user.d.ts +21 -0
- package/dist/session/user.js +8 -0
- package/package.json +53 -0
- package/src/analytics/AnalyticsEmitter.ts +23 -0
- package/src/compiler/cli.ts +866 -0
- package/src/compiler/collections.ts +554 -0
- package/src/compiler/course-config.ts +32 -0
- package/src/compiler/lesson-derivation.ts +186 -0
- package/src/compiler/manifest.ts +601 -0
- package/src/compiler/resolution-report.ts +150 -0
- package/src/components/CurriculumMap.astro +208 -0
- package/src/components/HoverPanel.astro +67 -0
- package/src/components/assessments/AssessmentRunner.tsx +320 -0
- package/src/components/assessments/AssessmentSet.astro +54 -0
- package/src/components/citation/CitationLayer.astro +173 -0
- package/src/components/examples/CompactExample.astro +34 -0
- package/src/components/examples/CompactExamples.astro +253 -0
- package/src/components/hover-panel.ts +273 -0
- package/src/components/notation/NotationGlossary.astro +412 -0
- package/src/components/notation/NotationLayer.astro +594 -0
- package/src/components/notation/NotationMath.astro +24 -0
- package/src/components/notation/SafeMathNode.astro +23 -0
- package/src/components/notation/render-notation-math.ts +223 -0
- package/src/components/starlight/EquationEnhancer.astro +72 -0
- package/src/components/starlight/LayoutHeader.astro +102 -0
- package/src/components/starlight/LayoutPageSidebar.astro +33 -0
- package/src/components/starlight/LayoutSidebar.astro +29 -0
- package/src/components/starlight/LessonFooter.astro +58 -0
- package/src/content-config.ts +259 -0
- package/src/curriculum/validation.ts +481 -0
- package/src/progress/ProgressRepository.ts +64 -0
- package/src/reference/base-library.mjs +27 -0
- package/src/reference/citation-format.mjs +133 -0
- package/src/reference/consistency.ts +375 -0
- package/src/reference/curriculum-alignment.ts +228 -0
- package/src/reference/equations-validate.ts +167 -0
- package/src/reference/equations.mjs +144 -0
- package/src/reference/gate-math.ts +250 -0
- package/src/reference/katex-options.mjs +91 -0
- package/src/reference/lab-math-scope.ts +54 -0
- package/src/reference/label.ts +47 -0
- package/src/reference/lint-ignore.ts +75 -0
- package/src/reference/math-glyphs.mjs +830 -0
- package/src/reference/prose.ts +21 -0
- package/src/reference/references.ts +82 -0
- package/src/reference/registry.ts +723 -0
- package/src/reference/rehype-fail-katex-errors.mjs +55 -0
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +753 -0
- package/src/reference/render-lab-math.ts +99 -0
- package/src/reference/types.ts +182 -0
- package/src/reference/units-vocab.ts +143 -0
- package/src/session/PreferenceStore.ts +54 -0
- package/src/session/user-context.ts +18 -0
- package/src/session/user.ts +24 -0
- package/src/styles/global.css +763 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure derivations for facts that used to be authored in lesson frontmatter
|
|
3
|
+
* (Phase C2). Nothing here reads the filesystem; `collections.ts` supplies the
|
|
4
|
+
* inputs and every consumer (the CLI validator, the Astro build, the Starlight
|
|
5
|
+
* layout, the tests) goes through that one loader.
|
|
6
|
+
*
|
|
7
|
+
* Authored per lesson after C2: `title`, `description`, `teaches`, `assumptions`,
|
|
8
|
+
* `editorialStatus`, `notation.local`. Everything below is derived:
|
|
9
|
+
*
|
|
10
|
+
* - `lessonId` — the doc slug, `/` → `.` (`foundations/discount-factors`).
|
|
11
|
+
* - `requires` — direct competency-graph prerequisites of `teaches`, minus
|
|
12
|
+
* what the lesson teaches itself. `teaches` is kept
|
|
13
|
+
* topologically ordered, so the intra-lesson subtraction is
|
|
14
|
+
* safe for the `lesson-order` check.
|
|
15
|
+
* - `sources` — the `[@…]` ids in the body (the validator already
|
|
16
|
+
* required frontmatter `sources` to equal this set exactly).
|
|
17
|
+
* - `assessments` — the id list in the colocated `<lesson>.checks.yml`.
|
|
18
|
+
* - `sidebar` order — per section, lessons in the order the tracks introduce
|
|
19
|
+
* them (a stable merge of every track's `lessons`).
|
|
20
|
+
*
|
|
21
|
+
* `notation.uses` is retired (D3): the completeness gate compiles every
|
|
22
|
+
* lesson's math against the page glyph table — `notation.local` plus the
|
|
23
|
+
* shared keys the body names with `[[key]]` / `\explain` — so an import list
|
|
24
|
+
* is redundant.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** `foundations/discount-factors` → `foundations.discount-factors`. */
|
|
28
|
+
export function lessonIdFromSlug(slug: string): string {
|
|
29
|
+
return slug.replace(/\.(md|mdx)$/, '').replace(/\//g, '.');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A docs entry is a lesson when it lives in a section directory. The three
|
|
34
|
+
* top-level pages (`index`, `curriculum-map`, `glossary`) are not lessons; a
|
|
35
|
+
* future `<section>/index` page would not be one either.
|
|
36
|
+
*/
|
|
37
|
+
export function isLessonSlug(slug: string): boolean {
|
|
38
|
+
const clean = slug.replace(/\.(md|mdx)$/, '');
|
|
39
|
+
return clean.includes('/') && !clean.endsWith('/index');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Direct prerequisites of everything the lesson `teaches`, minus the taught
|
|
44
|
+
* competencies themselves, sorted. Editorial "you should also know" extras that
|
|
45
|
+
* a few lessons used to list by hand are intentionally not reconstructed — a
|
|
46
|
+
* real dependency belongs in the competency graph, not per lesson.
|
|
47
|
+
*/
|
|
48
|
+
export function deriveRequires(
|
|
49
|
+
teaches: readonly string[],
|
|
50
|
+
prerequisitesById: ReadonlyMap<string, readonly string[]>,
|
|
51
|
+
): string[] {
|
|
52
|
+
const taught = new Set(teaches);
|
|
53
|
+
const required = new Set<string>();
|
|
54
|
+
for (const competencyId of teaches) {
|
|
55
|
+
for (const prerequisiteId of prerequisitesById.get(competencyId) ?? []) {
|
|
56
|
+
if (!taught.has(prerequisiteId)) required.add(prerequisiteId);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return [...required].sort();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Source ids cited with `[@id]` (optionally `[@id; locator]`) in a lesson body,
|
|
64
|
+
* with fenced and inline code stripped first so a syntax example does not
|
|
65
|
+
* count. Mirrors the reader in `curriculum/validation.ts`.
|
|
66
|
+
*/
|
|
67
|
+
export function citedSourceIds(body: string): Set<string> {
|
|
68
|
+
const withoutCode = body
|
|
69
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
70
|
+
.replace(/`[^`\n]*`/g, '');
|
|
71
|
+
const ids = new Set<string>();
|
|
72
|
+
for (const match of withoutCode.matchAll(
|
|
73
|
+
/\[@([a-z0-9][a-z0-9.-]*)(?:;[^\]]*)?\]/g,
|
|
74
|
+
)) {
|
|
75
|
+
ids.add((match[1] ?? '').trim());
|
|
76
|
+
}
|
|
77
|
+
return ids;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Cited source ids as a sorted array — the derived frontmatter `sources`. */
|
|
81
|
+
export function deriveSources(body: string): string[] {
|
|
82
|
+
return [...citedSourceIds(body)].sort();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parse a colocated `<lesson>.checks.yml`. The file is a flat YAML list of
|
|
87
|
+
* assessment ids (`- discount-factor-check`); `[]` and an empty file mean no
|
|
88
|
+
* assessments. Deliberately tiny — a colocated check *spec* with inline items
|
|
89
|
+
* is a later step; C2 only relocates the id list.
|
|
90
|
+
*/
|
|
91
|
+
export function parseCheckList(text: string): string[] {
|
|
92
|
+
const ids: string[] = [];
|
|
93
|
+
for (const rawLine of text.split('\n')) {
|
|
94
|
+
const line = rawLine.replace(/#.*$/, '').trim();
|
|
95
|
+
if (line === '' || line === '[]') continue;
|
|
96
|
+
const match = line.match(/^-\s+(['"]?)([A-Za-z0-9][A-Za-z0-9._-]*)\1$/);
|
|
97
|
+
if (!match) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`checks.yml: expected "- <assessment-id>" lines, got ${JSON.stringify(rawLine)}`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
ids.push(match[2]);
|
|
103
|
+
}
|
|
104
|
+
return ids;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface TrackLike {
|
|
108
|
+
readonly id: string;
|
|
109
|
+
readonly lessons: readonly string[];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* One global lesson order from every track: start with the tracks sorted by id,
|
|
114
|
+
* then splice each later track's new lessons in right after the last lesson from
|
|
115
|
+
* that track already placed. Lessons shared between tracks keep their first
|
|
116
|
+
* track's position; a lesson in no track is absent (callers append leftovers).
|
|
117
|
+
*/
|
|
118
|
+
export function mergeTrackOrder(tracks: readonly TrackLike[]): string[] {
|
|
119
|
+
const ordered: string[] = [];
|
|
120
|
+
for (const track of [...tracks].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
121
|
+
let anchor = -1;
|
|
122
|
+
for (const lessonId of track.lessons) {
|
|
123
|
+
const at = ordered.indexOf(lessonId);
|
|
124
|
+
if (at !== -1) {
|
|
125
|
+
anchor = at;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
ordered.splice(anchor + 1, 0, lessonId);
|
|
129
|
+
anchor += 1;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return ordered;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** One sidebar section group. Data lives in `content/course.config.ts` (Phase F). */
|
|
136
|
+
export interface SidebarSection {
|
|
137
|
+
readonly dir: string;
|
|
138
|
+
readonly label: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type SidebarGroup =
|
|
142
|
+
| { readonly label: string; readonly items: readonly string[] }
|
|
143
|
+
| {
|
|
144
|
+
readonly label: string;
|
|
145
|
+
readonly items: readonly {
|
|
146
|
+
readonly label: string;
|
|
147
|
+
readonly link: string;
|
|
148
|
+
}[];
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The Starlight `sidebar` config: one group per section, lessons ordered by the
|
|
153
|
+
* merged track order (ties broken by slug), then the static Reference group.
|
|
154
|
+
* Replaces seven `autogenerate` blocks that read an authored `sidebar.order`.
|
|
155
|
+
*/
|
|
156
|
+
export function buildSidebar(
|
|
157
|
+
tracks: readonly TrackLike[],
|
|
158
|
+
lessonSlugs: readonly string[],
|
|
159
|
+
sections: readonly SidebarSection[],
|
|
160
|
+
): SidebarGroup[] {
|
|
161
|
+
const rank = new Map(
|
|
162
|
+
mergeTrackOrder(tracks).map((lessonId, index) => [lessonId, index]),
|
|
163
|
+
);
|
|
164
|
+
const positionOf = (slug: string) =>
|
|
165
|
+
rank.get(lessonIdFromSlug(slug)) ?? Number.POSITIVE_INFINITY;
|
|
166
|
+
|
|
167
|
+
const groups: SidebarGroup[] = sections.map(({ dir, label }) => ({
|
|
168
|
+
label,
|
|
169
|
+
items: lessonSlugs
|
|
170
|
+
.filter((slug) => slug.startsWith(`${dir}/`))
|
|
171
|
+
.sort(
|
|
172
|
+
(left, right) =>
|
|
173
|
+
positionOf(left) - positionOf(right) || left.localeCompare(right),
|
|
174
|
+
),
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
groups.push({
|
|
178
|
+
label: 'Reference',
|
|
179
|
+
items: [
|
|
180
|
+
{ label: 'Curriculum map', link: '/curriculum-map/' },
|
|
181
|
+
{ label: 'Notation glossary', link: '/glossary/' },
|
|
182
|
+
],
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return groups;
|
|
186
|
+
}
|