explico 0.4.0 → 0.5.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 +273 -1
- package/README.md +103 -8
- package/dist/compiler/astro.d.ts +9 -1
- package/dist/compiler/astro.js +182 -3
- package/dist/compiler/cli.d.ts +13 -0
- package/dist/compiler/cli.js +28 -4
- package/dist/compiler/collections.d.ts +3 -2
- package/dist/compiler/collections.js +28 -1
- package/dist/compiler/course-config.d.ts +58 -1
- package/dist/compiler/course-config.js +28 -1
- package/dist/compiler/exports/standalone-html.d.ts +34 -0
- package/dist/compiler/exports/standalone-html.js +803 -0
- package/dist/compiler/manifest.d.ts +90 -6
- package/dist/compiler/manifest.js +150 -17
- package/dist/compiler/resolution-report.d.ts +4 -0
- package/dist/reference/base-abbreviations.d.mts +30 -0
- package/dist/reference/base-abbreviations.mjs +60 -0
- package/dist/reference/base-operators.d.mts +15 -0
- package/dist/reference/base-operators.mjs +40 -0
- package/dist/reference/base-roman-labels.d.mts +35 -0
- package/dist/reference/base-roman-labels.mjs +43 -0
- package/dist/reference/consistency.d.ts +8 -2
- package/dist/reference/consistency.js +50 -3
- package/dist/reference/diagrams-validate.d.ts +21 -0
- package/dist/reference/diagrams-validate.js +13 -0
- package/dist/reference/equations.d.mts +10 -15
- package/dist/reference/equations.mjs +67 -14
- package/dist/reference/gate-abbreviations.d.ts +17 -0
- package/dist/reference/gate-abbreviations.js +64 -0
- package/dist/reference/gate-math.d.ts +28 -5
- package/dist/reference/gate-math.js +5 -2
- package/dist/reference/gate-prose-notation.d.ts +60 -0
- package/dist/reference/gate-prose-notation.js +125 -0
- package/dist/reference/keyed-float-validate.d.ts +5 -5
- package/dist/reference/keyed-jsx-floats.d.mts +7 -12
- package/dist/reference/keyed-jsx-floats.mjs +50 -25
- package/dist/reference/knowledge-checks-validate.d.ts +35 -0
- package/dist/reference/knowledge-checks-validate.js +78 -0
- package/dist/reference/knowledge-checks.d.mts +25 -0
- package/dist/reference/knowledge-checks.mjs +45 -0
- package/dist/reference/lab-math-scope.d.ts +9 -1
- package/dist/reference/lab-math-scope.js +32 -4
- package/dist/reference/math-glyphs.d.mts +30 -0
- package/dist/reference/math-glyphs.mjs +367 -0
- package/dist/reference/mdx-attributes.d.mts +13 -0
- package/dist/reference/mdx-attributes.mjs +38 -0
- package/dist/reference/mixed-content.d.ts +17 -0
- package/dist/reference/mixed-content.js +29 -0
- package/dist/reference/page-notation.d.ts +52 -0
- package/dist/reference/page-notation.js +171 -0
- package/dist/reference/raw-floats-validate.d.ts +18 -0
- package/dist/reference/raw-floats-validate.js +53 -0
- package/dist/reference/raw-floats.d.mts +18 -0
- package/dist/reference/raw-floats.mjs +129 -0
- package/dist/reference/rehype-heading-anchors.d.mts +1 -1
- package/dist/reference/rehype-heading-anchors.mjs +107 -1
- package/dist/reference/rehype-table-header-labels.d.mts +26 -0
- package/dist/reference/rehype-table-header-labels.mjs +152 -0
- package/dist/reference/remark-abbreviations.d.mts +7 -0
- package/dist/reference/remark-abbreviations.mjs +174 -0
- package/dist/reference/remark-memo.d.mts +16 -0
- package/dist/reference/remark-memo.mjs +339 -0
- package/dist/reference/remark-notation.d.mts +57 -9
- package/dist/reference/remark-notation.mjs +354 -42
- package/dist/reference/remark-short-note.d.mts +4 -0
- package/dist/reference/remark-short-note.mjs +237 -0
- package/dist/reference/types.d.ts +16 -1
- package/dist/reference/units-vocab.js +4 -0
- package/docs/VERSIONING.md +33 -4
- package/docs/authoring/README.md +8 -0
- package/docs/authoring/agents.md +17 -2
- package/docs/authoring/components.md +135 -0
- package/docs/authoring/migrating.md +92 -7
- package/docs/authoring/notation.md +560 -1
- package/docs/authoring/structure.md +120 -8
- package/docs/authoring/visualizations.md +36 -3
- package/package.json +5 -2
- package/src/compiler/astro.ts +208 -3
- package/src/compiler/cli.ts +29 -2
- package/src/compiler/collections.ts +45 -4
- package/src/compiler/course-config.ts +92 -0
- package/src/compiler/exports/standalone-html.ts +963 -0
- package/src/compiler/manifest.ts +268 -22
- package/src/components/HoverPanel.astro +45 -4
- package/src/components/abbreviation/AbbreviationGlossary.astro +70 -0
- package/src/components/abbreviation/AbbreviationLayer.astro +127 -0
- package/src/components/assessments/AssessmentRunner.tsx +52 -17
- package/src/components/assessments/AssessmentSet.astro +98 -14
- package/src/components/assessments/RenderedContent.tsx +55 -0
- package/src/components/assessments/assessment-randomization.ts +16 -0
- package/src/components/diagram/Diagram.astro +444 -83
- package/src/components/disclosure/hover-preview.ts +202 -0
- package/src/components/disclosure/persisted-disclosure.ts +66 -0
- package/src/components/examples/CompactExamples.astro +2 -0
- package/src/components/figure/Figure.astro +279 -10
- package/src/components/memo/Memo.astro +453 -0
- package/src/components/memo/ShortNote.astro +223 -0
- package/src/components/notation/NotationFormula.astro +18 -1
- package/src/components/notation/NotationLayer.astro +105 -8
- package/src/components/notation/render-notation-math.ts +39 -2
- package/src/components/notation/safe-math-to-react.ts +50 -0
- package/src/components/reference/FloatRefLayer.astro +233 -15
- package/src/components/starlight/CollapsibleSections.astro +461 -0
- package/src/components/starlight/DiagramEnhancer.astro +385 -0
- package/src/components/starlight/HeadingAnchorEnhancer.astro +5 -17
- package/src/components/starlight/KeyedFloatEnhancer.astro +81 -3
- package/src/components/starlight/LayoutHeader.astro +50 -0
- package/src/components/starlight/LayoutSocialIcons.astro +41 -2
- package/src/components/starlight/LessonExportActions.astro +436 -0
- package/src/components/starlight/LessonFooter.astro +27 -2
- package/src/components/starlight/section-parts.ts +31 -0
- package/src/components/table/Table.astro +293 -7
- package/src/components/table/TableOverflowExpander.astro +489 -0
- package/src/content-config.ts +20 -0
- package/src/reference/base-abbreviations.mjs +60 -0
- package/src/reference/base-operators.mjs +40 -0
- package/src/reference/base-roman-labels.mjs +43 -0
- package/src/reference/consistency.ts +73 -2
- package/src/reference/diagrams-validate.ts +40 -0
- package/src/reference/equations.mjs +67 -14
- package/src/reference/gate-abbreviations.ts +128 -0
- package/src/reference/gate-math.ts +27 -7
- package/src/reference/gate-prose-notation.ts +224 -0
- package/src/reference/keyed-float-validate.ts +5 -5
- package/src/reference/keyed-jsx-floats.mjs +50 -25
- package/src/reference/knowledge-checks-validate.ts +130 -0
- package/src/reference/knowledge-checks.mjs +45 -0
- package/src/reference/lab-math-scope.ts +45 -3
- package/src/reference/math-glyphs.mjs +367 -0
- package/src/reference/mdx-attributes.mjs +38 -0
- package/src/reference/mixed-content.ts +69 -0
- package/src/reference/page-notation.ts +252 -0
- package/src/reference/raw-floats-validate.ts +103 -0
- package/src/reference/raw-floats.mjs +129 -0
- package/src/reference/rehype-heading-anchors.mjs +107 -1
- package/src/reference/rehype-table-header-labels.mjs +152 -0
- package/src/reference/remark-abbreviations.mjs +174 -0
- package/src/reference/remark-memo.mjs +339 -0
- package/src/reference/remark-notation.mjs +354 -42
- package/src/reference/remark-short-note.mjs +237 -0
- package/src/reference/types.ts +16 -0
- package/src/reference/units-vocab.ts +4 -0
- package/src/styles/global.css +996 -50
|
@@ -3,10 +3,14 @@ import { ConsistencyDiagnostic } from '../reference/consistency.js';
|
|
|
3
3
|
import { EquationLabelRecord, EquationDiagnostic } from '../reference/equations-validate.js';
|
|
4
4
|
import { TableLabelRecord, TableDiagnostic } from '../reference/tables-validate.js';
|
|
5
5
|
import { FigureLabelRecord, FigureDiagnostic } from '../reference/figures-validate.js';
|
|
6
|
+
import { DiagramLabelRecord, DiagramDiagnostic } from '../reference/diagrams-validate.js';
|
|
7
|
+
import { KnowledgeCheckLabelRecord, KnowledgeCheckDiagnostic } from '../reference/knowledge-checks-validate.js';
|
|
8
|
+
import { RawFloatDiagnostic } from '../reference/raw-floats-validate.js';
|
|
6
9
|
import { MathGateDiagnostic } from '../reference/gate-math.js';
|
|
10
|
+
import { ContentSegment } from '../reference/mixed-content.js';
|
|
7
11
|
import { GlyphScopeEntry } from '../reference/gloss.js';
|
|
8
12
|
import { NotationDefinitionRecord, NotationPageBundle, NotationBacklink, NotationDiagnostic, EditorialStatus, NotationGlossEntry } from '../reference/types.js';
|
|
9
|
-
import { CourseConfig } from './course-config.js';
|
|
13
|
+
import { NormalizedLessonExports, CourseConfig } from './course-config.js';
|
|
10
14
|
import { KnowledgeVersionDiagnostic } from './knowledge-version.js';
|
|
11
15
|
import { SidebarGroup } from './lesson-derivation.js';
|
|
12
16
|
import './collections.js';
|
|
@@ -51,7 +55,7 @@ import '../reference/keyed-float-validate.js';
|
|
|
51
55
|
* `lessons[].equations`, and `diagnostics.equations`.
|
|
52
56
|
* v4 (F-tables-figures): `tables`/`figures` (same shape as `equations`, for
|
|
53
57
|
* `<Table>`/`<Figure>`), `lessons[].tables`/`lessons[].figures`, and
|
|
54
|
-
* `diagnostics.tables`/`diagnostics.figures`.
|
|
58
|
+
* `diagnostics.tables`/`diagnostics.figures`/`diagnostics.diagrams`.
|
|
55
59
|
* v5 (about): `about` (engine identity from `explico`'s `package.json`, the
|
|
56
60
|
* course's reader-facing `about` block, and the knowledge version resolved
|
|
57
61
|
* against `content/CHANGELOG.md`) and `diagnostics.knowledge`.
|
|
@@ -61,8 +65,33 @@ import '../reference/keyed-float-validate.js';
|
|
|
61
65
|
* now the number before the dot), `lessons[].chapter` redefined as the
|
|
62
66
|
* lesson's ordinal *within its part*, and `lessons[].numbering` — the
|
|
63
67
|
* per-kind offsets that make `n` run continuously across a part.
|
|
68
|
+
* v8 (assessment math): `assessmentContent` — every assessment item's
|
|
69
|
+
* `prompt` / `explanation`, pre-split into text/math segments and resolved
|
|
70
|
+
* against the scope of the lesson that embeds it, so `AssessmentSet.astro`
|
|
71
|
+
* can render them through the same KaTeX pipeline as lesson body math instead
|
|
72
|
+
* of showing raw text.
|
|
73
|
+
* v9 (diagram identity): `diagrams` (the independent `<Diagram>` number and
|
|
74
|
+
* cross-page lookup), `lessons[].diagrams`, `lessons[].numbering.diagrams`,
|
|
75
|
+
* and `diagnostics.diagrams`.
|
|
76
|
+
* v10 (knowledge-check identity): `checks` (part-wide numbering and cross-page
|
|
77
|
+
* lookup), `lessons[].knowledgeChecks`, `lessons[].numbering.checks`, and
|
|
78
|
+
* `diagnostics.checks`.
|
|
79
|
+
* v11 (lesson exports): normalized standalone HTML and print build/UI settings.
|
|
80
|
+
* v12 (abbreviation hover cards): `manifest.abbreviations` — the
|
|
81
|
+
* `abbreviations` content collection (N14), flattened to plain
|
|
82
|
+
* `{key, abbr, expansion, aliases, domain?}` records sorted by key, the way
|
|
83
|
+
* `manifest.notation.raw` already carries notation frontmatter for
|
|
84
|
+
* `remarkNotation`. `remarkAbbreviations` reads it to wrap the first
|
|
85
|
+
* occurrence of a known abbreviation in a lesson's prose with a hover/click
|
|
86
|
+
* card.
|
|
87
|
+
* v13 (raw-float diagnostics, additive): `diagnostics.rawFloats` — a raw
|
|
88
|
+
* Markdown table, a raw HTML `<table>`, or an Explico `<Diagram>` that is
|
|
89
|
+
* unkeyed or nested outside `<Table>`/`<Figure>` never reaches keyed-float
|
|
90
|
+
* validation and can never get a stable number or `[[…]]` reference; this
|
|
91
|
+
* flags it (warning-only — the manifest shape a client already reads is
|
|
92
|
+
* unchanged).
|
|
64
93
|
*/
|
|
65
|
-
declare const MANIFEST_SCHEMA_VERSION =
|
|
94
|
+
declare const MANIFEST_SCHEMA_VERSION = 13;
|
|
66
95
|
declare const MANIFEST_PATH: string;
|
|
67
96
|
interface ManifestCitation {
|
|
68
97
|
readonly id: string;
|
|
@@ -114,8 +143,9 @@ interface ManifestLesson {
|
|
|
114
143
|
/**
|
|
115
144
|
* The 1-based ordinal of the **part** this lesson sits in — its sidebar
|
|
116
145
|
* group's position in `courseConfig.parts`. It is the number before the dot
|
|
117
|
-
* in every equation, table, and
|
|
118
|
-
* first equation of part 2. See
|
|
146
|
+
* in every equation, table, figure, diagram, and knowledge-check number on
|
|
147
|
+
* the page: `(2.1)` is the first equation of part 2. See
|
|
148
|
+
* `docs/authoring/structure.md`.
|
|
119
149
|
*/
|
|
120
150
|
readonly part: number;
|
|
121
151
|
/**
|
|
@@ -133,6 +163,8 @@ interface ManifestLesson {
|
|
|
133
163
|
readonly equations: number;
|
|
134
164
|
readonly tables: number;
|
|
135
165
|
readonly figures: number;
|
|
166
|
+
readonly diagrams: number;
|
|
167
|
+
readonly checks: number;
|
|
136
168
|
};
|
|
137
169
|
readonly file: string;
|
|
138
170
|
readonly title: string;
|
|
@@ -143,6 +175,11 @@ interface ManifestLesson {
|
|
|
143
175
|
readonly requires: readonly string[];
|
|
144
176
|
readonly assumptions: readonly string[];
|
|
145
177
|
readonly assessments: readonly string[];
|
|
178
|
+
/** Numbered knowledge checks from `assessments`, in `.checks.yml` order. */
|
|
179
|
+
readonly knowledgeChecks: readonly {
|
|
180
|
+
readonly key: string;
|
|
181
|
+
readonly number: string;
|
|
182
|
+
}[];
|
|
146
183
|
readonly sources: readonly string[];
|
|
147
184
|
readonly citations: readonly ManifestCitation[];
|
|
148
185
|
/** Competency prerequisite edges this lesson introduces. */
|
|
@@ -162,6 +199,11 @@ interface ManifestLesson {
|
|
|
162
199
|
readonly key: string;
|
|
163
200
|
readonly number: string;
|
|
164
201
|
}[];
|
|
202
|
+
/** Keyed `<Diagram>` elements in appearance order. */
|
|
203
|
+
readonly diagrams: readonly {
|
|
204
|
+
readonly key: string;
|
|
205
|
+
readonly number: string;
|
|
206
|
+
}[];
|
|
165
207
|
readonly notation: {
|
|
166
208
|
readonly bindings: readonly {
|
|
167
209
|
readonly key: string;
|
|
@@ -202,8 +244,18 @@ interface ManifestAbout {
|
|
|
202
244
|
readonly disclaimer: string;
|
|
203
245
|
readonly changelogHref?: string;
|
|
204
246
|
}
|
|
247
|
+
/** One assessment item's pre-rendered `prompt` / `explanation` (v8). */
|
|
248
|
+
interface ManifestAssessmentItemContent {
|
|
249
|
+
readonly lessonId: string;
|
|
250
|
+
readonly assessmentId: string;
|
|
251
|
+
readonly itemId: string;
|
|
252
|
+
readonly promptSegments: readonly ContentSegment[];
|
|
253
|
+
readonly explanationSegments: readonly ContentSegment[];
|
|
254
|
+
}
|
|
205
255
|
interface Manifest {
|
|
206
256
|
readonly schemaVersion: number;
|
|
257
|
+
/** Normalized build/UI settings for opt-in per-lesson exports. */
|
|
258
|
+
readonly lessonExports: NormalizedLessonExports;
|
|
207
259
|
/** Reader-facing identity + versions (the `[?]` About panel). */
|
|
208
260
|
readonly about: ManifestAbout;
|
|
209
261
|
readonly notation: {
|
|
@@ -217,6 +269,8 @@ interface Manifest {
|
|
|
217
269
|
readonly competencies: readonly Record<string, unknown>[];
|
|
218
270
|
readonly sources: readonly Record<string, unknown>[];
|
|
219
271
|
readonly tracks: readonly Record<string, unknown>[];
|
|
272
|
+
/** Abbreviations table (N14), for `remarkAbbreviations`. Ordered by key. */
|
|
273
|
+
readonly abbreviations: readonly Record<string, unknown>[];
|
|
220
274
|
readonly sidebar: readonly SidebarGroup[];
|
|
221
275
|
readonly lessons: readonly ManifestLesson[];
|
|
222
276
|
/** Full competency prerequisite graph. */
|
|
@@ -237,6 +291,26 @@ interface Manifest {
|
|
|
237
291
|
readonly labels: readonly FigureLabelRecord[];
|
|
238
292
|
readonly numbersBySlug: Record<string, Record<string, string>>;
|
|
239
293
|
};
|
|
294
|
+
/** Keyed-float identity for `<Diagram>` — independent of figure numbering. */
|
|
295
|
+
readonly diagrams: {
|
|
296
|
+
readonly labels: readonly DiagramLabelRecord[];
|
|
297
|
+
readonly numbersBySlug: Record<string, Record<string, string>>;
|
|
298
|
+
};
|
|
299
|
+
/** Knowledge-check identity, derived from each lesson's `.checks.yml`. */
|
|
300
|
+
readonly checks: {
|
|
301
|
+
readonly labels: readonly KnowledgeCheckLabelRecord[];
|
|
302
|
+
readonly numbersBySlug: Record<string, Record<string, string>>;
|
|
303
|
+
};
|
|
304
|
+
/**
|
|
305
|
+
* Every assessment item's `prompt` / `explanation`, pre-split into
|
|
306
|
+
* text/math segments (v8). `AssessmentSet.astro` filters this by
|
|
307
|
+
* `lessonId` + `assessmentId` and renders each `math` segment's `latex`
|
|
308
|
+
* through `renderNotationMath` before handing the result to
|
|
309
|
+
* `AssessmentRunner`. An assessment embedded in more than one lesson (via
|
|
310
|
+
* more than one `checks.yml`) appears once per lesson here, since each
|
|
311
|
+
* lesson's scope can resolve its glyphs differently.
|
|
312
|
+
*/
|
|
313
|
+
readonly assessmentContent: readonly ManifestAssessmentItemContent[];
|
|
240
314
|
readonly diagnostics: {
|
|
241
315
|
readonly curriculum: readonly CurriculumIssue[];
|
|
242
316
|
readonly notation: readonly NotationDiagnostic[];
|
|
@@ -252,6 +326,16 @@ interface Manifest {
|
|
|
252
326
|
readonly tables: readonly TableDiagnostic[];
|
|
253
327
|
/** `<Figure>` identity checks (F-tables-figures) — same codes, `fig-` prefixed. */
|
|
254
328
|
readonly figures: readonly FigureDiagnostic[];
|
|
329
|
+
/** `<Diagram>` identity checks — same codes, `dia-` prefixed. */
|
|
330
|
+
readonly diagrams: readonly DiagramDiagnostic[];
|
|
331
|
+
/** Knowledge-check identity and `[[check-…]]` reference checks. */
|
|
332
|
+
readonly checks: readonly KnowledgeCheckDiagnostic[];
|
|
333
|
+
/**
|
|
334
|
+
* A raw Markdown table, a raw HTML `<table>`, or an Explico `<Diagram>`
|
|
335
|
+
* that is unkeyed or nested outside `<Table>`/`<Figure>` — invisible to
|
|
336
|
+
* keyed-float validation above. Warnings only.
|
|
337
|
+
*/
|
|
338
|
+
readonly rawFloats: readonly RawFloatDiagnostic[];
|
|
255
339
|
};
|
|
256
340
|
readonly hashes: {
|
|
257
341
|
/** `sha256` of every content source file, keyed by repo-relative path. */
|
|
@@ -280,4 +364,4 @@ declare function readManifestSync(): Manifest;
|
|
|
280
364
|
*/
|
|
281
365
|
declare function loadManifest(courseConfig?: CourseConfig): Promise<Manifest>;
|
|
282
366
|
|
|
283
|
-
export { MANIFEST_PATH, MANIFEST_SCHEMA_VERSION, type Manifest, type ManifestAbout, type ManifestCitation, type ManifestLesson, type ManifestLessonNotation, type ManifestNotationResolution, type PrereqEdge, compileManifest, loadManifest, readManifestSync, serializeManifest, writeManifest };
|
|
367
|
+
export { MANIFEST_PATH, MANIFEST_SCHEMA_VERSION, type Manifest, type ManifestAbout, type ManifestAssessmentItemContent, type ManifestCitation, type ManifestLesson, type ManifestLessonNotation, type ManifestNotationResolution, type PrereqEdge, compileManifest, loadManifest, readManifestSync, serializeManifest, writeManifest };
|
|
@@ -28,17 +28,39 @@ import {
|
|
|
28
28
|
validateFigures
|
|
29
29
|
} from "../reference/figures-validate.js";
|
|
30
30
|
import {
|
|
31
|
-
|
|
31
|
+
validateDiagrams
|
|
32
|
+
} from "../reference/diagrams-validate.js";
|
|
33
|
+
import {
|
|
34
|
+
validateKnowledgeChecks
|
|
35
|
+
} from "../reference/knowledge-checks-validate.js";
|
|
36
|
+
import {
|
|
37
|
+
validateRawFloats
|
|
38
|
+
} from "../reference/raw-floats-validate.js";
|
|
39
|
+
import {
|
|
40
|
+
gateContentMath,
|
|
41
|
+
pageScope
|
|
32
42
|
} from "../reference/gate-math.js";
|
|
43
|
+
import {
|
|
44
|
+
gateProseNotation,
|
|
45
|
+
gateProseNotationInAssessments
|
|
46
|
+
} from "../reference/gate-prose-notation.js";
|
|
47
|
+
import { gateAbbreviations } from "../reference/gate-abbreviations.js";
|
|
48
|
+
import {
|
|
49
|
+
splitMixedContent
|
|
50
|
+
} from "../reference/mixed-content.js";
|
|
33
51
|
import { loadLintIgnore } from "../reference/lint-ignore.js";
|
|
34
52
|
import { buildNotationRegistry } from "../reference/registry.js";
|
|
35
53
|
import { formulaGlyphScope } from "../reference/gloss.js";
|
|
36
54
|
import { resolveReferenceId } from "../reference/references.js";
|
|
37
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
coursePartsOf,
|
|
57
|
+
normalizeLessonExports
|
|
58
|
+
} from "./course-config.js";
|
|
38
59
|
import {
|
|
39
60
|
resolveKnowledgeVersion
|
|
40
61
|
} from "./knowledge-version.js";
|
|
41
62
|
import {
|
|
63
|
+
loadAbbreviationRegistryInput,
|
|
42
64
|
loadCurriculumCatalog,
|
|
43
65
|
loadNotationDefinitions,
|
|
44
66
|
loadNotationRegistryInput,
|
|
@@ -51,7 +73,7 @@ import {
|
|
|
51
73
|
isLessonSlug,
|
|
52
74
|
lessonIdFromSlug
|
|
53
75
|
} from "./lesson-derivation.js";
|
|
54
|
-
const MANIFEST_SCHEMA_VERSION =
|
|
76
|
+
const MANIFEST_SCHEMA_VERSION = 13;
|
|
55
77
|
const REPOSITORY_ROOT = process.cwd();
|
|
56
78
|
const CONTENT_ROOT = join(REPOSITORY_ROOT, "content");
|
|
57
79
|
const MANIFEST_PATH = join(REPOSITORY_ROOT, "build", "manifest.json");
|
|
@@ -184,9 +206,10 @@ async function compileManifest(courseConfig) {
|
|
|
184
206
|
"course.config.ts is missing a complete `about` block (required since explico 0.3.0): `about: { version, authors: [{ name }], disclaimer, materialName?, summary?, changelogHref? }`. See docs/authoring/migrating.md (\xA7 0.2.x \u2192 0.3.0) in the installed package."
|
|
185
207
|
);
|
|
186
208
|
}
|
|
187
|
-
const [catalog, notationInput] = await Promise.all([
|
|
209
|
+
const [catalog, notationInput, abbreviationsInput] = await Promise.all([
|
|
188
210
|
loadCurriculumCatalog(),
|
|
189
|
-
loadNotationRegistryInput()
|
|
211
|
+
loadNotationRegistryInput(),
|
|
212
|
+
loadAbbreviationRegistryInput()
|
|
190
213
|
]);
|
|
191
214
|
const registry = buildNotationRegistry(notationInput);
|
|
192
215
|
const cardsByKey = new Map(
|
|
@@ -202,16 +225,53 @@ async function compileManifest(courseConfig) {
|
|
|
202
225
|
const bundlesByLesson = new Map(
|
|
203
226
|
registry.bundles.map((bundle) => [bundle.lessonId, bundle])
|
|
204
227
|
);
|
|
228
|
+
const assessmentsInput = catalog.assessments;
|
|
205
229
|
const curriculumIssues = validateCurriculum(catalog);
|
|
206
230
|
const alignmentIssues = validateNotationAlignment(registry, catalog);
|
|
207
|
-
const mathIssues =
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
231
|
+
const mathIssues = [
|
|
232
|
+
...gateContentMath({
|
|
233
|
+
notationInput,
|
|
234
|
+
assessments: assessmentsInput,
|
|
235
|
+
lessonAssessments: catalog.lessons.map((lesson) => ({
|
|
236
|
+
lessonId: lesson.id,
|
|
237
|
+
assessmentIds: lesson.assessments
|
|
238
|
+
}))
|
|
239
|
+
}),
|
|
240
|
+
...gateProseNotation(notationInput.lessons),
|
|
241
|
+
...gateProseNotationInAssessments(assessmentsInput),
|
|
242
|
+
...gateAbbreviations({
|
|
243
|
+
notationInput,
|
|
244
|
+
abbreviations: abbreviationsInput,
|
|
245
|
+
courseAbbreviations: courseConfig.abbreviations
|
|
246
|
+
})
|
|
247
|
+
];
|
|
248
|
+
const notationLessonById = new Map(
|
|
249
|
+
notationInput.lessons.map((lesson) => [lesson.lessonId, lesson])
|
|
250
|
+
);
|
|
251
|
+
const assessmentInputById = new Map(
|
|
252
|
+
assessmentsInput.map((assessment) => [assessment.id, assessment])
|
|
253
|
+
);
|
|
254
|
+
const assessmentContent = [];
|
|
255
|
+
for (const lesson of catalog.lessons) {
|
|
256
|
+
if (lesson.assessments.length === 0) continue;
|
|
257
|
+
const lessonInput = notationLessonById.get(lesson.id);
|
|
258
|
+
if (!lessonInput) continue;
|
|
259
|
+
const scope = pageScope(lessonInput, cardsByKey);
|
|
260
|
+
for (const assessmentId of lesson.assessments) {
|
|
261
|
+
const assessment = assessmentInputById.get(assessmentId);
|
|
262
|
+
if (!assessment?.items) continue;
|
|
263
|
+
for (const item of assessment.items) {
|
|
264
|
+
if (!item.id) continue;
|
|
265
|
+
assessmentContent.push({
|
|
266
|
+
lessonId: lesson.id,
|
|
267
|
+
assessmentId,
|
|
268
|
+
itemId: item.id,
|
|
269
|
+
promptSegments: splitMixedContent(item.prompt ?? "", scope),
|
|
270
|
+
explanationSegments: splitMixedContent(item.explanation ?? "", scope)
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
215
275
|
const prerequisitesById = new Map(
|
|
216
276
|
catalog.competencies.map((competency) => [
|
|
217
277
|
competency.id,
|
|
@@ -245,7 +305,13 @@ async function compileManifest(courseConfig) {
|
|
|
245
305
|
const lessonIds = group.items.filter((item) => typeof item === "string").map(lessonIdFromSlug);
|
|
246
306
|
if (lessonIds.length === 0) continue;
|
|
247
307
|
partCursor += 1;
|
|
248
|
-
const used = {
|
|
308
|
+
const used = {
|
|
309
|
+
equations: 0,
|
|
310
|
+
tables: 0,
|
|
311
|
+
figures: 0,
|
|
312
|
+
diagrams: 0,
|
|
313
|
+
checks: 0
|
|
314
|
+
};
|
|
249
315
|
let chapterCursor = 0;
|
|
250
316
|
for (const lessonId of lessonIds) {
|
|
251
317
|
const body = bodyByLessonId.get(lessonId) ?? "";
|
|
@@ -257,6 +323,8 @@ async function compileManifest(courseConfig) {
|
|
|
257
323
|
used.equations += countDisplayEquations(body);
|
|
258
324
|
used.tables += countKeyedJsxFloats(body, { tagName: "Table" });
|
|
259
325
|
used.figures += countKeyedJsxFloats(body, { tagName: "Figure" });
|
|
326
|
+
used.diagrams += countKeyedJsxFloats(body, { tagName: "Diagram" });
|
|
327
|
+
used.checks += lessonMetaById.get(lessonId)?.assessments.length ?? 0;
|
|
260
328
|
}
|
|
261
329
|
}
|
|
262
330
|
const floatInputs = (kind) => notationInput.lessons.map((lesson) => {
|
|
@@ -295,6 +363,45 @@ async function compileManifest(courseConfig) {
|
|
|
295
363
|
Object.entries(table).map(([key, number]) => ({ key, number }))
|
|
296
364
|
])
|
|
297
365
|
);
|
|
366
|
+
const diagramValidation = validateDiagrams(floatInputs("diagrams"));
|
|
367
|
+
const diagramsBySlug = new Map(
|
|
368
|
+
Object.entries(diagramValidation.numbersBySlug).map(([slug, table]) => [
|
|
369
|
+
slug,
|
|
370
|
+
Object.entries(table).map(([key, number]) => ({ key, number }))
|
|
371
|
+
])
|
|
372
|
+
);
|
|
373
|
+
const checkValidation = validateKnowledgeChecks(
|
|
374
|
+
notationInput.lessons.map((lesson) => {
|
|
375
|
+
const placement = placementByLessonId.get(lesson.lessonId);
|
|
376
|
+
return {
|
|
377
|
+
lessonId: lesson.lessonId,
|
|
378
|
+
slug: lesson.lessonId.replace(/\./g, "/"),
|
|
379
|
+
file: lesson.source.file,
|
|
380
|
+
body: lesson.body,
|
|
381
|
+
assessmentIds: lessonMetaById.get(lesson.lessonId)?.assessments ?? [],
|
|
382
|
+
...placement ? {
|
|
383
|
+
numbering: {
|
|
384
|
+
prefix: placement.part,
|
|
385
|
+
offset: placement.numbering.checks
|
|
386
|
+
}
|
|
387
|
+
} : {}
|
|
388
|
+
};
|
|
389
|
+
})
|
|
390
|
+
);
|
|
391
|
+
const checksBySlug = new Map(
|
|
392
|
+
Object.entries(checkValidation.numbersBySlug).map(([slug, table]) => [
|
|
393
|
+
slug,
|
|
394
|
+
Object.entries(table).map(([key, number]) => ({ key, number }))
|
|
395
|
+
])
|
|
396
|
+
);
|
|
397
|
+
const rawFloatDiagnostics = validateRawFloats(
|
|
398
|
+
notationInput.lessons.map((lesson) => ({
|
|
399
|
+
lessonId: lesson.lessonId,
|
|
400
|
+
slug: lesson.lessonId.replace(/\./g, "/"),
|
|
401
|
+
file: lesson.source.file,
|
|
402
|
+
body: lesson.body
|
|
403
|
+
}))
|
|
404
|
+
);
|
|
298
405
|
const lessons = [];
|
|
299
406
|
for (const notationLesson of notationInput.lessons) {
|
|
300
407
|
const id = notationLesson.lessonId;
|
|
@@ -316,7 +423,9 @@ async function compileManifest(courseConfig) {
|
|
|
316
423
|
numbering: placementByLessonId.get(id)?.numbering ?? {
|
|
317
424
|
equations: 0,
|
|
318
425
|
tables: 0,
|
|
319
|
-
figures: 0
|
|
426
|
+
figures: 0,
|
|
427
|
+
diagrams: 0,
|
|
428
|
+
checks: 0
|
|
320
429
|
},
|
|
321
430
|
file: notationLesson.source.file,
|
|
322
431
|
title: frontmatter.title,
|
|
@@ -326,11 +435,13 @@ async function compileManifest(courseConfig) {
|
|
|
326
435
|
requires: [...meta.requires],
|
|
327
436
|
assumptions: [...meta.assumptions],
|
|
328
437
|
assessments: [...meta.assessments],
|
|
438
|
+
knowledgeChecks: checksBySlug.get(id.replace(/\./g, "/")) ?? [],
|
|
329
439
|
sources: deriveSources(notationLesson.body),
|
|
330
440
|
citations: lessonCitations(notationLesson.body),
|
|
331
441
|
equations: equationsBySlug.get(id.replace(/\./g, "/")) ?? [],
|
|
332
442
|
tables: tablesBySlug.get(id.replace(/\./g, "/")) ?? [],
|
|
333
443
|
figures: figuresBySlug.get(id.replace(/\./g, "/")) ?? [],
|
|
444
|
+
diagrams: diagramsBySlug.get(id.replace(/\./g, "/")) ?? [],
|
|
334
445
|
prereqEdges: sortEdges(
|
|
335
446
|
teaches.flatMap(
|
|
336
447
|
(to) => (prerequisitesById.get(to) ?? []).filter((from) => !teaches.includes(from)).map((from) => ({ from, to }))
|
|
@@ -356,7 +467,8 @@ async function compileManifest(courseConfig) {
|
|
|
356
467
|
catalog,
|
|
357
468
|
lintIgnore: loadLintIgnore(),
|
|
358
469
|
conventions: courseConfig.conventions,
|
|
359
|
-
...courseConfig.operators === void 0 ? {} : { operators: courseConfig.operators }
|
|
470
|
+
...courseConfig.operators === void 0 ? {} : { operators: courseConfig.operators },
|
|
471
|
+
...courseConfig.romanLabels === void 0 ? {} : { romanLabels: courseConfig.romanLabels }
|
|
360
472
|
});
|
|
361
473
|
const rawNotation = [...loadNotationDefinitions()].sort(
|
|
362
474
|
(a, b) => String(a.key).localeCompare(String(b.key))
|
|
@@ -364,6 +476,13 @@ async function compileManifest(courseConfig) {
|
|
|
364
476
|
const competencies = catalog.competencies.map((entry) => ({ ...entry })).sort(byId);
|
|
365
477
|
const sources = [...loadSourceRecords()].sort(byId);
|
|
366
478
|
const tracks = catalog.tracks.map((entry) => ({ ...entry })).sort(byId);
|
|
479
|
+
const abbreviations = abbreviationsInput.map((entry) => ({
|
|
480
|
+
key: entry.key,
|
|
481
|
+
abbr: entry.abbr,
|
|
482
|
+
expansion: entry.expansion,
|
|
483
|
+
aliases: entry.aliases,
|
|
484
|
+
...entry.domain === void 0 ? {} : { domain: entry.domain }
|
|
485
|
+
})).sort((a, b) => a.key.localeCompare(b.key));
|
|
367
486
|
const hashes = contentHashes();
|
|
368
487
|
const knowledgeChangelogPath = join(CONTENT_ROOT, "CHANGELOG.md");
|
|
369
488
|
const knowledge = resolveKnowledgeVersion({
|
|
@@ -397,6 +516,7 @@ async function compileManifest(courseConfig) {
|
|
|
397
516
|
};
|
|
398
517
|
return {
|
|
399
518
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
519
|
+
lessonExports: normalizeLessonExports(courseConfig),
|
|
400
520
|
about,
|
|
401
521
|
notation: {
|
|
402
522
|
definitions: registry.definitions,
|
|
@@ -408,6 +528,7 @@ async function compileManifest(courseConfig) {
|
|
|
408
528
|
competencies,
|
|
409
529
|
sources,
|
|
410
530
|
tracks,
|
|
531
|
+
abbreviations,
|
|
411
532
|
sidebar,
|
|
412
533
|
lessons,
|
|
413
534
|
prereqEdges,
|
|
@@ -423,6 +544,15 @@ async function compileManifest(courseConfig) {
|
|
|
423
544
|
labels: figureValidation.labels,
|
|
424
545
|
numbersBySlug: figureValidation.numbersBySlug
|
|
425
546
|
},
|
|
547
|
+
diagrams: {
|
|
548
|
+
labels: diagramValidation.labels,
|
|
549
|
+
numbersBySlug: diagramValidation.numbersBySlug
|
|
550
|
+
},
|
|
551
|
+
checks: {
|
|
552
|
+
labels: checkValidation.labels,
|
|
553
|
+
numbersBySlug: checkValidation.numbersBySlug
|
|
554
|
+
},
|
|
555
|
+
assessmentContent,
|
|
426
556
|
diagnostics: {
|
|
427
557
|
curriculum: curriculumIssues,
|
|
428
558
|
notation: registry.diagnostics,
|
|
@@ -432,7 +562,10 @@ async function compileManifest(courseConfig) {
|
|
|
432
562
|
equations: equationValidation.diagnostics,
|
|
433
563
|
tables: tableValidation.diagnostics,
|
|
434
564
|
figures: figureValidation.diagnostics,
|
|
435
|
-
|
|
565
|
+
diagrams: diagramValidation.diagnostics,
|
|
566
|
+
checks: checkValidation.diagnostics,
|
|
567
|
+
knowledge: knowledge.diagnostics,
|
|
568
|
+
rawFloats: rawFloatDiagnostics
|
|
436
569
|
},
|
|
437
570
|
hashes
|
|
438
571
|
};
|
|
@@ -9,7 +9,11 @@ import '../reference/equations-validate.js';
|
|
|
9
9
|
import '../reference/tables-validate.js';
|
|
10
10
|
import '../reference/keyed-float-validate.js';
|
|
11
11
|
import '../reference/figures-validate.js';
|
|
12
|
+
import '../reference/diagrams-validate.js';
|
|
13
|
+
import '../reference/knowledge-checks-validate.js';
|
|
14
|
+
import '../reference/raw-floats-validate.js';
|
|
12
15
|
import '../reference/gate-math.js';
|
|
16
|
+
import '../reference/mixed-content.js';
|
|
13
17
|
import '../reference/gloss.js';
|
|
14
18
|
import './knowledge-version.js';
|
|
15
19
|
import './lesson-derivation.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The abbreviations a course treats as common, given its `course.config.ts`
|
|
3
|
+
* `abbreviations` block: the shipped baseline, plus `allow`, minus `deny`.
|
|
4
|
+
*
|
|
5
|
+
* @param {{ allow?: readonly string[], deny?: readonly string[] } | undefined} abbreviations
|
|
6
|
+
* @returns {Set<string>}
|
|
7
|
+
*/
|
|
8
|
+
export function effectiveAbbreviationAllowlist(abbreviations: {
|
|
9
|
+
allow?: readonly string[];
|
|
10
|
+
deny?: readonly string[];
|
|
11
|
+
} | undefined): Set<string>;
|
|
12
|
+
/** True when `token` needs no abbreviations-table entry for this course. */
|
|
13
|
+
export function isBaseAbbreviation(token: any, abbreviations: any): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The base abbreviation baseline: acronyms and dotted abbreviations every
|
|
16
|
+
* reader is assumed to know, so a lesson never has to introduce them with an
|
|
17
|
+
* abbreviations-table entry. The `\operatorname{…}` / `\mathrm{…}` twins are
|
|
18
|
+
* `base-operators.mjs` (rule N8) / `base-roman-labels.mjs` (rule N10); this is
|
|
19
|
+
* the plain-prose equivalent for rule N14.
|
|
20
|
+
*
|
|
21
|
+
* Kept intentionally small, same rationale as `BASE_ROMAN_LABELS`: a
|
|
22
|
+
* course-specific acronym (`OLS`, `SSR`, `MSE`) is exactly the thing a reader
|
|
23
|
+
* benefits from having spelled out, so it belongs in the course's own
|
|
24
|
+
* `content/abbreviations/*.md` table, not here. This baseline only holds
|
|
25
|
+
* abbreviations so common in ordinary English/academic writing that spelling
|
|
26
|
+
* them out on every course would be noise, not help. A course adds a real
|
|
27
|
+
* one via `abbreviations.allow` in `course.config.ts`, the same shape as
|
|
28
|
+
* `operators.allow` / `romanLabels.allow`.
|
|
29
|
+
*/
|
|
30
|
+
export const BASE_ABBREVIATIONS: Readonly<Set<string>>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base abbreviation baseline: acronyms and dotted abbreviations every
|
|
3
|
+
* reader is assumed to know, so a lesson never has to introduce them with an
|
|
4
|
+
* abbreviations-table entry. The `\operatorname{…}` / `\mathrm{…}` twins are
|
|
5
|
+
* `base-operators.mjs` (rule N8) / `base-roman-labels.mjs` (rule N10); this is
|
|
6
|
+
* the plain-prose equivalent for rule N14.
|
|
7
|
+
*
|
|
8
|
+
* Kept intentionally small, same rationale as `BASE_ROMAN_LABELS`: a
|
|
9
|
+
* course-specific acronym (`OLS`, `SSR`, `MSE`) is exactly the thing a reader
|
|
10
|
+
* benefits from having spelled out, so it belongs in the course's own
|
|
11
|
+
* `content/abbreviations/*.md` table, not here. This baseline only holds
|
|
12
|
+
* abbreviations so common in ordinary English/academic writing that spelling
|
|
13
|
+
* them out on every course would be noise, not help. A course adds a real
|
|
14
|
+
* one via `abbreviations.allow` in `course.config.ts`, the same shape as
|
|
15
|
+
* `operators.allow` / `romanLabels.allow`.
|
|
16
|
+
*/
|
|
17
|
+
export const BASE_ABBREVIATIONS = Object.freeze(
|
|
18
|
+
new Set([
|
|
19
|
+
// dotted Latin/English abbreviations
|
|
20
|
+
'e.g.',
|
|
21
|
+
'i.e.',
|
|
22
|
+
'etc.',
|
|
23
|
+
'cf.',
|
|
24
|
+
'vs.',
|
|
25
|
+
'a.m.',
|
|
26
|
+
'p.m.',
|
|
27
|
+
'a.k.a.',
|
|
28
|
+
'et al.',
|
|
29
|
+
// generic acronyms with no domain-specific meaning in this engine
|
|
30
|
+
'AI',
|
|
31
|
+
'ID',
|
|
32
|
+
'OK',
|
|
33
|
+
'URL',
|
|
34
|
+
'FAQ',
|
|
35
|
+
'US',
|
|
36
|
+
'UK',
|
|
37
|
+
'EU',
|
|
38
|
+
]),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The abbreviations a course treats as common, given its `course.config.ts`
|
|
43
|
+
* `abbreviations` block: the shipped baseline, plus `allow`, minus `deny`.
|
|
44
|
+
*
|
|
45
|
+
* @param {{ allow?: readonly string[], deny?: readonly string[] } | undefined} abbreviations
|
|
46
|
+
* @returns {Set<string>}
|
|
47
|
+
*/
|
|
48
|
+
export function effectiveAbbreviationAllowlist(abbreviations) {
|
|
49
|
+
const allow = abbreviations?.allow ?? [];
|
|
50
|
+
const deny = new Set(abbreviations?.deny ?? []);
|
|
51
|
+
const effective = new Set(BASE_ABBREVIATIONS);
|
|
52
|
+
for (const name of allow) effective.add(name);
|
|
53
|
+
for (const name of deny) effective.delete(name);
|
|
54
|
+
return effective;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True when `token` needs no abbreviations-table entry for this course. */
|
|
58
|
+
export function isBaseAbbreviation(token, abbreviations) {
|
|
59
|
+
return effectiveAbbreviationAllowlist(abbreviations).has(token);
|
|
60
|
+
}
|
|
@@ -36,3 +36,18 @@ export function isBaseOperator(name: any, operators: any): boolean;
|
|
|
36
36
|
* Matching is case-sensitive.
|
|
37
37
|
*/
|
|
38
38
|
export const BASE_OPERATORS: Readonly<Set<string>>;
|
|
39
|
+
/**
|
|
40
|
+
* The subset of {@link BASE_OPERATORS} that must never appear with a bare
|
|
41
|
+
* (unparenthesized) argument: every trigonometric, inverse-trigonometric, and
|
|
42
|
+
* hyperbolic function, plus the exponential and logarithms (N13). `\sin x`
|
|
43
|
+
* leaves how far the argument extends ambiguous the moment anything follows
|
|
44
|
+
* it (`\sin x + 1` — is the `+1` inside or outside the sine?); `\sin(x)`
|
|
45
|
+
* never does, even for a single-symbol argument. Kept separate from
|
|
46
|
+
* `BASE_OPERATORS`: this is a formatting rule layered on top of the "does it
|
|
47
|
+
* need a notation card" question that set answers, so an operator can be
|
|
48
|
+
* universal (N8) and still owe a parenthesized argument. Enforced by
|
|
49
|
+
* `resolveMathGlyphs` in `math-glyphs.mjs`, which every rendered-math context
|
|
50
|
+
* (lesson body, notation `formula`, assessments, `Diagram` nodes, lab math)
|
|
51
|
+
* already calls.
|
|
52
|
+
*/
|
|
53
|
+
export const PARENTHESIZED_FUNCTIONS: Readonly<Set<string>>;
|
|
@@ -81,6 +81,46 @@ export const BASE_OPERATORS = Object.freeze(
|
|
|
81
81
|
]),
|
|
82
82
|
);
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* The subset of {@link BASE_OPERATORS} that must never appear with a bare
|
|
86
|
+
* (unparenthesized) argument: every trigonometric, inverse-trigonometric, and
|
|
87
|
+
* hyperbolic function, plus the exponential and logarithms (N13). `\sin x`
|
|
88
|
+
* leaves how far the argument extends ambiguous the moment anything follows
|
|
89
|
+
* it (`\sin x + 1` — is the `+1` inside or outside the sine?); `\sin(x)`
|
|
90
|
+
* never does, even for a single-symbol argument. Kept separate from
|
|
91
|
+
* `BASE_OPERATORS`: this is a formatting rule layered on top of the "does it
|
|
92
|
+
* need a notation card" question that set answers, so an operator can be
|
|
93
|
+
* universal (N8) and still owe a parenthesized argument. Enforced by
|
|
94
|
+
* `resolveMathGlyphs` in `math-glyphs.mjs`, which every rendered-math context
|
|
95
|
+
* (lesson body, notation `formula`, assessments, `Diagram` nodes, lab math)
|
|
96
|
+
* already calls.
|
|
97
|
+
*/
|
|
98
|
+
export const PARENTHESIZED_FUNCTIONS = Object.freeze(
|
|
99
|
+
new Set([
|
|
100
|
+
// exponential / logarithms
|
|
101
|
+
'exp',
|
|
102
|
+
'log',
|
|
103
|
+
'ln',
|
|
104
|
+
'lg',
|
|
105
|
+
// trigonometric
|
|
106
|
+
'sin',
|
|
107
|
+
'cos',
|
|
108
|
+
'tan',
|
|
109
|
+
'cot',
|
|
110
|
+
'sec',
|
|
111
|
+
'csc',
|
|
112
|
+
// inverse trigonometric
|
|
113
|
+
'arcsin',
|
|
114
|
+
'arccos',
|
|
115
|
+
'arctan',
|
|
116
|
+
// hyperbolic
|
|
117
|
+
'sinh',
|
|
118
|
+
'cosh',
|
|
119
|
+
'tanh',
|
|
120
|
+
'coth',
|
|
121
|
+
]),
|
|
122
|
+
);
|
|
123
|
+
|
|
84
124
|
/**
|
|
85
125
|
* The operators a course treats as common, given its `course.config.ts`
|
|
86
126
|
* `operators` block: the shipped baseline, plus `allow`, minus `deny`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The roman labels a course treats as common, given its `course.config.ts`
|
|
3
|
+
* `romanLabels` block: the shipped baseline, plus `allow`, minus `deny`.
|
|
4
|
+
*
|
|
5
|
+
* @param {{ allow?: readonly string[], deny?: readonly string[] } | undefined} romanLabels
|
|
6
|
+
* @returns {Set<string>}
|
|
7
|
+
*/
|
|
8
|
+
export function effectiveRomanLabelAllowlist(romanLabels: {
|
|
9
|
+
allow?: readonly string[];
|
|
10
|
+
deny?: readonly string[];
|
|
11
|
+
} | undefined): Set<string>;
|
|
12
|
+
/** True when `name` needs no notation entry for this course. */
|
|
13
|
+
export function isBaseRomanLabel(name: any, romanLabels: any): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The base roman-label baseline: `\mathrm{…}` multi-letter labels every
|
|
16
|
+
* reader is assumed to know, so a lesson never has to introduce them with a
|
|
17
|
+
* notation entry. The `\operatorname{…}` counterpart is `base-operators.mjs`
|
|
18
|
+
* (rule N8); this is its `\mathrm{…}` twin (rule N10).
|
|
19
|
+
*
|
|
20
|
+
* Rationale: the completeness gate has no opinion about `\mathrm{…}` bodies —
|
|
21
|
+
* they are a typographic label to KaTeX, not a bindable symbol, and N3
|
|
22
|
+
* requires the format without asking whether the label is ever explained.
|
|
23
|
+
* The `roman-label-explained` consistency check fills that gap: a label a
|
|
24
|
+
* lesson uses is either on this list (or the course's additions to it) or it
|
|
25
|
+
* carries a notation entry the reader can hover.
|
|
26
|
+
*
|
|
27
|
+
* Kept intentionally small — unlike `sin`/`exp`, an upright label is almost
|
|
28
|
+
* always a course-specific named quantity (`KE`, `PV`, `Var`-as-a-label) that
|
|
29
|
+
* genuinely benefits from a hover card, so the shipped baseline holds only
|
|
30
|
+
* the qualifiers that function like an operator's extremum subscript
|
|
31
|
+
* (`x_{\mathrm{opt}}`) rather than naming a quantity of their own. A course
|
|
32
|
+
* adds a real one via `romanLabels.allow` in `course.config.ts`, the same
|
|
33
|
+
* shape as `operators.allow`.
|
|
34
|
+
*/
|
|
35
|
+
export const BASE_ROMAN_LABELS: Readonly<Set<string>>;
|