explico 0.11.1 → 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 +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- 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 +15 -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 +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -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 +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- 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/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -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-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -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-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- 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 +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- 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 +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- 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 +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- 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 +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- 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 +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- 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/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -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 +66 -8
- 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 +14 -22
- 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 +8 -10
- 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/figure-symbols.ts +117 -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-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- 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-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- 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 +275 -23
- package/src/reference/render-lab-math.ts +40 -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 +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ScopeEntry } from './gate-math.js';
|
|
2
|
-
import './types.js';
|
|
2
|
+
import { DerivedUse } from './types.js';
|
|
3
3
|
|
|
4
4
|
type ContentSegment = {
|
|
5
5
|
readonly type: 'text';
|
|
@@ -10,8 +10,13 @@ type ContentSegment = {
|
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* Split `text` into ordered segments, resolving each math span's glyphs
|
|
13
|
-
* against `scope`. Never throws.
|
|
13
|
+
* against `scope`. Never throws. With `derive` (an assessment, which is page
|
|
14
|
+
* math), an indexed symbol takes its derived card (rule N23), and each one
|
|
15
|
+
* used is added to `derived`.
|
|
14
16
|
*/
|
|
15
|
-
declare function splitMixedContent(text: string, scope: readonly ScopeEntry[]
|
|
17
|
+
declare function splitMixedContent(text: string, scope: readonly ScopeEntry[], options?: {
|
|
18
|
+
readonly derive?: boolean;
|
|
19
|
+
readonly derived?: Map<string, DerivedUse>;
|
|
20
|
+
}): ContentSegment[];
|
|
16
21
|
|
|
17
22
|
export { type ContentSegment, splitMixedContent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveMathGlyphs } from "./math-glyphs.mjs";
|
|
2
2
|
const MATH_SPAN = /\$\$([\s\S]+?)\$\$|(?<![\\$])\$(?!\s)([^$\n]+?)(?<![\\\s])\$(?!\d)/g;
|
|
3
|
-
function splitMixedContent(text, scope) {
|
|
3
|
+
function splitMixedContent(text, scope, options = {}) {
|
|
4
4
|
const segments = [];
|
|
5
5
|
let cursor = 0;
|
|
6
6
|
const pattern = new RegExp(MATH_SPAN);
|
|
@@ -12,7 +12,9 @@ function splitMixedContent(text, scope) {
|
|
|
12
12
|
const raw = match[1] ?? match[2] ?? "";
|
|
13
13
|
let latex = raw;
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
const result = resolveMathGlyphs(raw, [...scope], { derive: options.derive === true });
|
|
16
|
+
latex = result.latex;
|
|
17
|
+
for (const use of result.derived) options.derived?.set(use.key, use);
|
|
16
18
|
} catch {
|
|
17
19
|
latex = raw;
|
|
18
20
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Manifest, ManifestLessonNotation } from '../compiler/manifest.js';
|
|
1
|
+
import { Manifest, ManifestDerivedNotation, ManifestLessonNotation } from '../compiler/manifest.js';
|
|
2
|
+
import { DerivedUse } from './types.js';
|
|
2
3
|
import '../curriculum/validation.js';
|
|
3
4
|
import './consistency.js';
|
|
4
|
-
import '../course-config-
|
|
5
|
+
import '../course-config-rRtME5UV.js';
|
|
5
6
|
import '../rules/catalog.js';
|
|
6
7
|
import '../rules/course-rules.js';
|
|
7
8
|
import '../compiler/collections.js';
|
|
8
|
-
import './
|
|
9
|
+
import './gate-retired-keys.js';
|
|
9
10
|
import './lint-ignore.js';
|
|
10
11
|
import './equations-validate.js';
|
|
11
12
|
import './tables-validate.js';
|
|
@@ -16,6 +17,7 @@ import './examples-validate.js';
|
|
|
16
17
|
import './folds-validate.js';
|
|
17
18
|
import './knowledge-checks-validate.js';
|
|
18
19
|
import './raw-floats-validate.js';
|
|
20
|
+
import './lab-katex-validate.js';
|
|
19
21
|
import './gate-math.js';
|
|
20
22
|
import './mixed-content.js';
|
|
21
23
|
import './gloss.js';
|
|
@@ -34,6 +36,27 @@ interface PageNotationDependency {
|
|
|
34
36
|
* between lessons and defeat page-local notation scope.
|
|
35
37
|
*/
|
|
36
38
|
declare function registerPageNotationDependencies(locals: object, keys: Iterable<string>, context: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Record the derived cards (rule N23) a nested server component's math uses —
|
|
41
|
+
* a lab's or a diagram's — so the page ships them with its own, and their
|
|
42
|
+
* base and index entries, which a derived card's formula opens. Keyed by
|
|
43
|
+
* `Astro.locals`, like {@link registerPageNotationDependencies}.
|
|
44
|
+
*/
|
|
45
|
+
declare function registerPageDerivedNotation(locals: object, uses: Iterable<DerivedUse>, context: string): void;
|
|
46
|
+
/** The page a glyph table was built for, and whether rule N23 is on there. */
|
|
47
|
+
interface ScopePage {
|
|
48
|
+
readonly locals: object;
|
|
49
|
+
readonly context: string;
|
|
50
|
+
readonly checkIndices: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Tie a lab's glyph table to the page it renders on (`labMathScope` does), so
|
|
54
|
+
* `renderLabMath` can give its indexed symbols derived cards and register
|
|
55
|
+
* them, and knows whether to hold them to rule N23. A table a course copies
|
|
56
|
+
* loses the tie: its math then composes no derived card.
|
|
57
|
+
*/
|
|
58
|
+
declare function bindScopeToPage(scope: object, page: ScopePage): void;
|
|
59
|
+
declare function pageOfScope(scope: object): ScopePage | undefined;
|
|
37
60
|
declare function pageNotationDependencies(locals: object): PageNotationDependency[];
|
|
38
61
|
/** Starlight's route id as exposed to nested Astro components. */
|
|
39
62
|
declare function routeIdFromLocals(locals: object): string | undefined;
|
|
@@ -44,14 +67,23 @@ declare function notationKeysInMathNodes(nodes: readonly {
|
|
|
44
67
|
readonly children?: readonly unknown[];
|
|
45
68
|
}[]): string[];
|
|
46
69
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
70
|
+
* The derived cards (rule N23) a page uses: the ones its body and assessment
|
|
71
|
+
* math use, as the manifest composed them, and the ones a lab or a diagram on
|
|
72
|
+
* it registered while rendering (`locals`), composed here the same way. They
|
|
73
|
+
* travel with the page as hidden sources; their base and index entries are
|
|
74
|
+
* in its payload already.
|
|
75
|
+
*/
|
|
76
|
+
declare function derivedNotationForPage(manifest: Manifest, pageId: string, locals?: object): readonly ManifestDerivedNotation[];
|
|
77
|
+
/**
|
|
78
|
+
* Extend one compiled page bundle — a lesson's, or a non-chapter page's
|
|
79
|
+
* (rule S10) — with only the definitions requested by components rendered on
|
|
80
|
+
* that page (plus those definitions' normal closure).
|
|
49
81
|
*/
|
|
50
|
-
declare function notationDefinitionsForRenderedPage(manifest: Manifest,
|
|
82
|
+
declare function notationDefinitionsForRenderedPage(manifest: Manifest, pageId: string, dependencies: readonly PageNotationDependency[]): ManifestLessonNotation[];
|
|
51
83
|
/**
|
|
52
84
|
* Structural backstop over final HTML: every trigger must have a source entry
|
|
53
85
|
* from which the popup enhancer can populate a card.
|
|
54
86
|
*/
|
|
55
87
|
declare function missingNotationPayloadKeys(html: string): string[];
|
|
56
88
|
|
|
57
|
-
export { type PageNotationDependency, missingNotationPayloadKeys, notationDefinitionsForRenderedPage, notationKeysInMathNodes, pageNotationDependencies, registerPageNotationDependencies, routeIdFromLocals };
|
|
89
|
+
export { type PageNotationDependency, type ScopePage, bindScopeToPage, derivedNotationForPage, missingNotationPayloadKeys, notationDefinitionsForRenderedPage, notationKeysInMathNodes, pageNotationDependencies, pageOfScope, registerPageDerivedNotation, registerPageNotationDependencies, routeIdFromLocals };
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
formulaGlyphScope
|
|
4
4
|
} from "./gloss.js";
|
|
5
5
|
import { resolveReferenceId } from "./references.js";
|
|
6
|
+
import { derivedNotationEntries } from "./derived-entries.js";
|
|
6
7
|
const dependenciesByLocals = /* @__PURE__ */ new WeakMap();
|
|
7
8
|
function registerPageNotationDependencies(locals, keys, context) {
|
|
8
9
|
let byKey = dependenciesByLocals.get(locals);
|
|
@@ -19,6 +20,27 @@ function registerPageNotationDependencies(locals, keys, context) {
|
|
|
19
20
|
contexts.add(context);
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
const derivedByLocals = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
function registerPageDerivedNotation(locals, uses, context) {
|
|
25
|
+
let byKey = derivedByLocals.get(locals);
|
|
26
|
+
if (!byKey) {
|
|
27
|
+
byKey = /* @__PURE__ */ new Map();
|
|
28
|
+
derivedByLocals.set(locals, byKey);
|
|
29
|
+
}
|
|
30
|
+
const entries = [];
|
|
31
|
+
for (const use of uses) {
|
|
32
|
+
byKey.set(use.key, use);
|
|
33
|
+
entries.push(use.base, use.index);
|
|
34
|
+
}
|
|
35
|
+
registerPageNotationDependencies(locals, entries, context);
|
|
36
|
+
}
|
|
37
|
+
const pageByScope = /* @__PURE__ */ new WeakMap();
|
|
38
|
+
function bindScopeToPage(scope, page) {
|
|
39
|
+
pageByScope.set(scope, page);
|
|
40
|
+
}
|
|
41
|
+
function pageOfScope(scope) {
|
|
42
|
+
return pageByScope.get(scope);
|
|
43
|
+
}
|
|
22
44
|
function pageNotationDependencies(locals) {
|
|
23
45
|
const byKey = dependenciesByLocals.get(locals);
|
|
24
46
|
if (!byKey) return [];
|
|
@@ -52,7 +74,6 @@ function manifestDefinition(definition, cardsByKey) {
|
|
|
52
74
|
notation: definition.notation,
|
|
53
75
|
label: definition.label,
|
|
54
76
|
summary: definition.summary,
|
|
55
|
-
editorialStatus: definition.status,
|
|
56
77
|
seeAlso: [...definition.seeAlso],
|
|
57
78
|
glosses: [...definition.glosses],
|
|
58
79
|
formulaScope: formulaGlyphScope({
|
|
@@ -63,17 +84,44 @@ function manifestDefinition(definition, cardsByKey) {
|
|
|
63
84
|
...definition.formula === void 0 ? {} : { formula: definition.formula }
|
|
64
85
|
}),
|
|
65
86
|
...definition.units === void 0 ? {} : { units: definition.units },
|
|
66
|
-
...definition.formula === void 0 ? {} : { formula: definition.formula }
|
|
87
|
+
...definition.formula === void 0 ? {} : { formula: definition.formula },
|
|
88
|
+
...definition.range === void 0 ? {} : { range: definition.range }
|
|
67
89
|
};
|
|
68
90
|
}
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
|
|
91
|
+
function derivedNotationForPage(manifest, pageId, locals) {
|
|
92
|
+
const page = manifest.lessons.find((entry) => entry.id === pageId) ?? manifest.pages.find((entry) => entry.id === pageId);
|
|
93
|
+
const compiled = page?.notation.derived ?? [];
|
|
94
|
+
const registered = [...(locals && derivedByLocals.get(locals)?.values()) ?? []].filter(
|
|
95
|
+
(use) => !compiled.some((entry) => entry.key === use.key)
|
|
96
|
+
);
|
|
97
|
+
if (registered.length === 0) return compiled;
|
|
98
|
+
const definitionsById = new Map(
|
|
99
|
+
manifest.notation.definitions.map((definition) => [definition.id, definition])
|
|
100
|
+
);
|
|
101
|
+
const availableIds = new Set(definitionsById.keys());
|
|
102
|
+
const records = /* @__PURE__ */ new Map();
|
|
103
|
+
for (const use of registered) {
|
|
104
|
+
for (const key of [use.base, use.index]) {
|
|
105
|
+
const id = resolveReferenceId(key, { kind: "page", lessonId: pageId }, availableIds);
|
|
106
|
+
const record = id === void 0 ? void 0 : definitionsById.get(id);
|
|
107
|
+
if (record) records.set(key, record);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const cardsByKey = new Map(
|
|
111
|
+
manifest.notation.definitions.filter((definition) => definition.kind === "shared").map((definition) => [definition.key, { key: definition.key, notation: definition.notation }])
|
|
112
|
+
);
|
|
113
|
+
return [...compiled, ...derivedNotationEntries(registered, records, cardsByKey)].sort(
|
|
114
|
+
(left, right) => left.key.localeCompare(right.key)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
function notationDefinitionsForRenderedPage(manifest, pageId, dependencies) {
|
|
118
|
+
const page = manifest.lessons.find((entry) => entry.id === pageId) ?? manifest.pages.find((entry) => entry.id === pageId);
|
|
119
|
+
if (!page) return [];
|
|
72
120
|
const definitionsById = new Map(
|
|
73
121
|
manifest.notation.definitions.map((definition) => [definition.id, definition])
|
|
74
122
|
);
|
|
75
123
|
const availableIds = new Set(definitionsById.keys());
|
|
76
|
-
const ids = new Set(
|
|
124
|
+
const ids = new Set(page.notation.definitionIds);
|
|
77
125
|
const contextsByKey = /* @__PURE__ */ new Map();
|
|
78
126
|
for (const dependency of dependencies) {
|
|
79
127
|
let contexts = contextsByKey.get(dependency.key);
|
|
@@ -84,12 +132,12 @@ function notationDefinitionsForRenderedPage(manifest, lessonId, dependencies) {
|
|
|
84
132
|
contexts.add(dependency.context);
|
|
85
133
|
const definitionId = resolveReferenceId(
|
|
86
134
|
dependency.key,
|
|
87
|
-
{ kind: "page", lessonId },
|
|
135
|
+
{ kind: "page", lessonId: pageId },
|
|
88
136
|
availableIds
|
|
89
137
|
);
|
|
90
138
|
if (!definitionId) {
|
|
91
139
|
throw new Error(
|
|
92
|
-
`Notation payload error
|
|
140
|
+
`Notation payload error on page "${pageId}": ${dependency.context} emitted data-notation-key="${dependency.key}", but that key is not defined on this page or in the shared notation registry.`
|
|
93
141
|
);
|
|
94
142
|
}
|
|
95
143
|
ids.add(definitionId);
|
|
@@ -124,7 +172,7 @@ function notationDefinitionsForRenderedPage(manifest, lessonId, dependencies) {
|
|
|
124
172
|
if (previous && previous !== id) {
|
|
125
173
|
const context = [...contextsByKey.get(definition.key) ?? []].join(", ");
|
|
126
174
|
throw new Error(
|
|
127
|
-
`Notation payload error
|
|
175
|
+
`Notation payload error on page "${pageId}": key "${definition.key}" would have two meanings (${previous} and ${id})` + (context ? ` after ${context} emitted it.` : ".")
|
|
128
176
|
);
|
|
129
177
|
}
|
|
130
178
|
definitionIdByKey.set(definition.key, id);
|
|
@@ -138,7 +186,7 @@ function notationDefinitionsForRenderedPage(manifest, lessonId, dependencies) {
|
|
|
138
186
|
});
|
|
139
187
|
}
|
|
140
188
|
const existingById = new Map(
|
|
141
|
-
|
|
189
|
+
page.notation.definitions.map((definition) => [definition.id, definition])
|
|
142
190
|
);
|
|
143
191
|
return [...ids].sort().flatMap((id) => {
|
|
144
192
|
const existing = existingById.get(id);
|
|
@@ -162,10 +210,14 @@ function missingNotationPayloadKeys(html) {
|
|
|
162
210
|
return [...triggers].filter((key) => !entries.has(key)).sort();
|
|
163
211
|
}
|
|
164
212
|
export {
|
|
213
|
+
bindScopeToPage,
|
|
214
|
+
derivedNotationForPage,
|
|
165
215
|
missingNotationPayloadKeys,
|
|
166
216
|
notationDefinitionsForRenderedPage,
|
|
167
217
|
notationKeysInMathNodes,
|
|
168
218
|
pageNotationDependencies,
|
|
219
|
+
pageOfScope,
|
|
220
|
+
registerPageDerivedNotation,
|
|
169
221
|
registerPageNotationDependencies,
|
|
170
222
|
routeIdFromLocals
|
|
171
223
|
};
|
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
* `keyed-jsx-floats.mjs`'s top-level-only scan entirely, so it never even
|
|
13
13
|
* reaches diagram numbering.
|
|
14
14
|
*
|
|
15
|
-
* A raw table
|
|
16
|
-
*
|
|
17
|
-
* `<
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* A raw table counts only where wrapping it would number it: at the top level
|
|
16
|
+
* of the lesson body or in a `TRANSPARENT_COMPONENTS` body (`<Memo>`,
|
|
17
|
+
* `<ShortNote>`, `<Fold>`), exactly where `keyed-jsx-floats.mjs` numbers a
|
|
18
|
+
* `<Table>`. A raw table in `<Table>`/`<Figure>` is the intended, wrapped
|
|
19
|
+
* case; one in any other component (a worked example's `<CompactExample>`,
|
|
20
|
+
* an `<Aside>`) is illustrative, like an equation there, and a `<Table>`
|
|
21
|
+
* there would get no number — so neither is flagged.
|
|
20
22
|
*
|
|
21
23
|
* `scanRawFloats` (raw Markdown, for the manifest builder) and
|
|
22
24
|
* `collectRawFloats` (mdast, for `remark-notation.mjs`) MUST agree on counts
|
|
@@ -24,7 +26,11 @@
|
|
|
24
26
|
* `keyed-jsx-floats.mjs` holds `scanKeyedJsxFloats`/`collectKeyedJsxFloats` to.
|
|
25
27
|
*/
|
|
26
28
|
|
|
27
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
stripFencedCode,
|
|
31
|
+
stripJsxComponents,
|
|
32
|
+
TRANSPARENT_COMPONENTS,
|
|
33
|
+
} from './equations.mjs';
|
|
28
34
|
import { collectKeyedJsxFloats, scanKeyedJsxFloats } from './keyed-jsx-floats.mjs';
|
|
29
35
|
|
|
30
36
|
/** Blank `<Table>…</Table>` and `<Figure>…</Figure>` bodies — legitimately wrapped, not raw. */
|
|
@@ -67,9 +73,16 @@ function findDiagramTags(text) {
|
|
|
67
73
|
export function scanRawFloats(markdown) {
|
|
68
74
|
const codeStripped = stripFencedCode(String(markdown));
|
|
69
75
|
const withoutWrappedFloats = blankFloatWrappers(codeStripped);
|
|
76
|
+
// Every component body but a transparent one is blanked — `<Table>` and
|
|
77
|
+
// `<Figure>` among them — so only the tables a `<Table>` would number remain.
|
|
78
|
+
const numberableText = stripJsxComponents(
|
|
79
|
+
codeStripped,
|
|
80
|
+
undefined,
|
|
81
|
+
TRANSPARENT_COMPONENTS,
|
|
82
|
+
);
|
|
70
83
|
|
|
71
|
-
const markdownTableCount = findMarkdownTableStarts(
|
|
72
|
-
const htmlTableCount = findHtmlTableTags(
|
|
84
|
+
const markdownTableCount = findMarkdownTableStarts(numberableText).length;
|
|
85
|
+
const htmlTableCount = findHtmlTableTags(numberableText).length;
|
|
73
86
|
|
|
74
87
|
const diagramsOutsideWrappers = findDiagramTags(withoutWrappedFloats).length;
|
|
75
88
|
const visibleDiagrams = scanKeyedJsxFloats(markdown, { tagName: 'Diagram' });
|
|
@@ -95,7 +108,10 @@ export function collectRawFloats(tree) {
|
|
|
95
108
|
const htmlTableNodes = [];
|
|
96
109
|
const allDiagramNodes = [];
|
|
97
110
|
|
|
98
|
-
|
|
111
|
+
// `numberable`: a `<Table>` here would be numbered — the top level, or a
|
|
112
|
+
// transparent component's body. Any other MDX component (a capitalized
|
|
113
|
+
// name, the ones `stripJsxComponents` blanks) ends it for its subtree.
|
|
114
|
+
const walk = (node, numberable) => {
|
|
99
115
|
if (!node || typeof node !== 'object') return;
|
|
100
116
|
if (
|
|
101
117
|
node.type === 'mdxJsxFlowElement' &&
|
|
@@ -103,18 +119,26 @@ export function collectRawFloats(tree) {
|
|
|
103
119
|
) {
|
|
104
120
|
return; // legitimately wrapped — don't descend
|
|
105
121
|
}
|
|
106
|
-
if (node.type === 'table') markdownTableNodes.push(node);
|
|
107
|
-
if (
|
|
122
|
+
if (numberable && node.type === 'table') markdownTableNodes.push(node);
|
|
123
|
+
if (
|
|
124
|
+
numberable &&
|
|
125
|
+
node.type === 'html' &&
|
|
126
|
+
/<table\b/i.test(String(node.value ?? ''))
|
|
127
|
+
) {
|
|
108
128
|
htmlTableNodes.push(node);
|
|
109
129
|
}
|
|
110
130
|
if (node.type === 'mdxJsxFlowElement' && node.name === 'Diagram') {
|
|
111
131
|
allDiagramNodes.push(node);
|
|
112
132
|
}
|
|
133
|
+
const component =
|
|
134
|
+
(node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') &&
|
|
135
|
+
/^[A-Z]/.test(String(node.name ?? '')) &&
|
|
136
|
+
!TRANSPARENT_COMPONENTS.includes(node.name);
|
|
113
137
|
if (Array.isArray(node.children)) {
|
|
114
|
-
for (const child of node.children) walk(child);
|
|
138
|
+
for (const child of node.children) walk(child, numberable && !component);
|
|
115
139
|
}
|
|
116
140
|
};
|
|
117
|
-
walk(tree);
|
|
141
|
+
walk(tree, true);
|
|
118
142
|
|
|
119
143
|
const visibleDiagrams = collectKeyedJsxFloats(tree, { tagName: 'Diagram' });
|
|
120
144
|
const visibleNodes = new Set(visibleDiagrams.map((diagram) => diagram.node));
|
|
@@ -2,6 +2,16 @@ import { NotationDiagnostic, SourceSpan, NotationDefinitionScope } from './types
|
|
|
2
2
|
|
|
3
3
|
declare const NOTATION_KEY_PATTERN: RegExp;
|
|
4
4
|
declare function isNotationKey(value: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* The `[[…]]` prefixes that name something other than a notation entry: an
|
|
7
|
+
* equation, a table, a figure, a diagram, a worked-example set, a knowledge
|
|
8
|
+
* check, a section, a memo. `remark-notation.mjs` and `remark-memo.mjs` route
|
|
9
|
+
* a reference by its prefix before notation keys are looked at, so a key
|
|
10
|
+
* that starts with one could never be reached.
|
|
11
|
+
*/
|
|
12
|
+
declare const RESERVED_KEY_PREFIXES: readonly ["eq-", "tab-", "fig-", "dia-", "ex-", "check-", "sec-", "memo-"];
|
|
13
|
+
/** The reserved prefix `key` starts with, if any. */
|
|
14
|
+
declare function reservedKeyPrefix(key: string): string | undefined;
|
|
5
15
|
declare function sharedDefinitionId(key: string): string;
|
|
6
16
|
declare function localDefinitionId(lessonId: string, key: string): string;
|
|
7
17
|
declare function definitionId(scope: NotationDefinitionScope, key: string): string;
|
|
@@ -14,4 +24,4 @@ declare function resolveReferenceId(key: string, scope: NotationDefinitionScope,
|
|
|
14
24
|
declare function compareSourceSpans(left: SourceSpan | undefined, right: SourceSpan | undefined): number;
|
|
15
25
|
declare function compareDiagnostics(left: NotationDiagnostic, right: NotationDiagnostic): number;
|
|
16
26
|
|
|
17
|
-
export { NOTATION_KEY_PATTERN, compareDiagnostics, compareSourceSpans, definitionId, isNotationKey, localDefinitionId, resolveReferenceId, sharedDefinitionId };
|
|
27
|
+
export { NOTATION_KEY_PATTERN, RESERVED_KEY_PREFIXES, compareDiagnostics, compareSourceSpans, definitionId, isNotationKey, localDefinitionId, reservedKeyPrefix, resolveReferenceId, sharedDefinitionId };
|
|
@@ -2,6 +2,10 @@ const NOTATION_KEY_PATTERN = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
|
|
|
2
2
|
function isNotationKey(value) {
|
|
3
3
|
return NOTATION_KEY_PATTERN.test(value);
|
|
4
4
|
}
|
|
5
|
+
const RESERVED_KEY_PREFIXES = ["eq-", "tab-", "fig-", "dia-", "ex-", "check-", "sec-", "memo-"];
|
|
6
|
+
function reservedKeyPrefix(key) {
|
|
7
|
+
return RESERVED_KEY_PREFIXES.find((prefix) => key.startsWith(prefix));
|
|
8
|
+
}
|
|
5
9
|
function sharedDefinitionId(key) {
|
|
6
10
|
return `shared:${key}`;
|
|
7
11
|
}
|
|
@@ -33,11 +37,13 @@ function severityRank(severity) {
|
|
|
33
37
|
}
|
|
34
38
|
export {
|
|
35
39
|
NOTATION_KEY_PATTERN,
|
|
40
|
+
RESERVED_KEY_PREFIXES,
|
|
36
41
|
compareDiagnostics,
|
|
37
42
|
compareSourceSpans,
|
|
38
43
|
definitionId,
|
|
39
44
|
isNotationKey,
|
|
40
45
|
localDefinitionId,
|
|
46
|
+
reservedKeyPrefix,
|
|
41
47
|
resolveReferenceId,
|
|
42
48
|
sharedDefinitionId
|
|
43
49
|
};
|
|
@@ -3,9 +3,12 @@ import {
|
|
|
3
3
|
compareSourceSpans,
|
|
4
4
|
isNotationKey,
|
|
5
5
|
localDefinitionId,
|
|
6
|
+
RESERVED_KEY_PREFIXES,
|
|
7
|
+
reservedKeyPrefix,
|
|
6
8
|
resolveReferenceId,
|
|
7
9
|
sharedDefinitionId
|
|
8
10
|
} from "./references.js";
|
|
11
|
+
import { lineOf, proseOnly } from "./gate-prose-notation.js";
|
|
9
12
|
function buildNotationRegistry(rawInput) {
|
|
10
13
|
const diagnostics = [];
|
|
11
14
|
const lessons = buildLessonIndex(rawInput.lessons, diagnostics);
|
|
@@ -105,7 +108,23 @@ function buildNotationRegistry(rawInput) {
|
|
|
105
108
|
)
|
|
106
109
|
);
|
|
107
110
|
}
|
|
108
|
-
|
|
111
|
+
const dependencyEdges = /* @__PURE__ */ new Map();
|
|
112
|
+
for (const candidate of definitions.values()) {
|
|
113
|
+
dependencyEdges.set(
|
|
114
|
+
candidate.id,
|
|
115
|
+
uniqueSorted(
|
|
116
|
+
candidate.resolvedReferences.filter((reference) => reference.kind !== "formula").map((reference) => reference.definitionId).filter((definitionId) => definitionId !== candidate.id)
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
detectCycles(definitions, dependencyEdges, diagnostics);
|
|
121
|
+
const localIdsByLesson = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const candidate of definitions.values()) {
|
|
123
|
+
if (candidate.kind !== "local") continue;
|
|
124
|
+
const ids = localIdsByLesson.get(candidate.lesson.lessonId) ?? [];
|
|
125
|
+
ids.push(candidate.id);
|
|
126
|
+
localIdsByLesson.set(candidate.lesson.lessonId, ids);
|
|
127
|
+
}
|
|
109
128
|
const bundles = [];
|
|
110
129
|
const backlinks = [];
|
|
111
130
|
const reachableDefinitions = /* @__PURE__ */ new Set();
|
|
@@ -114,7 +133,10 @@ function buildNotationRegistry(rawInput) {
|
|
|
114
133
|
const directIds = new Set(
|
|
115
134
|
references.map((reference) => reference.definitionId)
|
|
116
135
|
);
|
|
117
|
-
const definitionIds = transitiveClosure(
|
|
136
|
+
const definitionIds = transitiveClosure(
|
|
137
|
+
/* @__PURE__ */ new Set([...directIds, ...localIdsByLesson.get(lesson.lessonId) ?? []]),
|
|
138
|
+
edgeIndex
|
|
139
|
+
);
|
|
118
140
|
for (const id of definitionIds) reachableDefinitions.add(id);
|
|
119
141
|
const bindingByKey = /* @__PURE__ */ new Map();
|
|
120
142
|
for (const reference of references) {
|
|
@@ -122,7 +144,6 @@ function buildNotationRegistry(rawInput) {
|
|
|
122
144
|
}
|
|
123
145
|
bundles.push({
|
|
124
146
|
lessonId: lesson.lessonId,
|
|
125
|
-
status: lesson.status,
|
|
126
147
|
source: lesson.source,
|
|
127
148
|
bindings: [...bindingByKey].map(([key, definitionId]) => ({ key, definitionId })).sort(
|
|
128
149
|
(left, right) => left.key.localeCompare(right.key) || left.definitionId.localeCompare(right.definitionId)
|
|
@@ -140,6 +161,21 @@ function buildNotationRegistry(rawInput) {
|
|
|
140
161
|
});
|
|
141
162
|
}
|
|
142
163
|
}
|
|
164
|
+
for (const candidate of definitions.values()) {
|
|
165
|
+
if (candidate.kind !== "local") continue;
|
|
166
|
+
const shared = definitions.get(sharedDefinitionId(candidate.input.key));
|
|
167
|
+
if (shared === void 0) continue;
|
|
168
|
+
diagnostics.push({
|
|
169
|
+
code: "local-shadows-shared",
|
|
170
|
+
severity: "warning",
|
|
171
|
+
message: `${candidate.lesson.lessonId} defines notation.local ${JSON.stringify(candidate.input.key)}, which is also a shared entry (${shared.input.source.file}): on this page [[${candidate.input.key}]] means "${candidate.input.label}", everywhere else "${shared.input.label}". Give the local entry a key of its own, or use the shared one.`,
|
|
172
|
+
key: candidate.input.key,
|
|
173
|
+
lessonId: candidate.lesson.lessonId,
|
|
174
|
+
definitionId: candidate.id,
|
|
175
|
+
source: candidate.input.source,
|
|
176
|
+
relatedSources: [shared.input.source]
|
|
177
|
+
});
|
|
178
|
+
}
|
|
143
179
|
for (const candidate of definitions.values()) {
|
|
144
180
|
if (!reachableDefinitions.has(candidate.id)) {
|
|
145
181
|
diagnostics.push({
|
|
@@ -193,6 +229,7 @@ function buildLessonIndex(rawLessons, diagnostics) {
|
|
|
193
229
|
);
|
|
194
230
|
continue;
|
|
195
231
|
}
|
|
232
|
+
diagnostics.push(...malformedReferences(lesson));
|
|
196
233
|
const previous = lessons.get(lesson.lessonId);
|
|
197
234
|
if (previous !== void 0) {
|
|
198
235
|
diagnostics.push(
|
|
@@ -241,7 +278,21 @@ function buildDefinitionIndex(rawShared, lessons, diagnostics) {
|
|
|
241
278
|
diagnostics.push(
|
|
242
279
|
diagnostic({
|
|
243
280
|
code: "invalid-key",
|
|
244
|
-
message: `${candidate.id} has invalid notation key ${JSON.stringify(candidate.input.key)}`,
|
|
281
|
+
message: `${candidate.id} has invalid notation key ${JSON.stringify(candidate.input.key)}${keyHint(candidate.input.key)}`,
|
|
282
|
+
key: candidate.input.key,
|
|
283
|
+
lessonId: candidate.kind === "local" ? candidate.lesson.lessonId : void 0,
|
|
284
|
+
definitionId: candidate.id,
|
|
285
|
+
source: candidate.input.source
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const reserved = reservedKeyPrefix(candidate.input.key);
|
|
291
|
+
if (reserved !== void 0) {
|
|
292
|
+
diagnostics.push(
|
|
293
|
+
diagnostic({
|
|
294
|
+
code: "invalid-key",
|
|
295
|
+
message: `${candidate.id} has notation key ${JSON.stringify(candidate.input.key)}, which starts with the reserved \`${reserved}\`: [[${candidate.input.key}]] is read as a reference to that kind of float and never reaches this entry. Rename the key; none may start with ${RESERVED_KEY_PREFIXES.map((prefix) => `\`${prefix}\``).join(", ")}.`,
|
|
245
296
|
key: candidate.input.key,
|
|
246
297
|
lessonId: candidate.kind === "local" ? candidate.lesson.lessonId : void 0,
|
|
247
298
|
definitionId: candidate.id,
|
|
@@ -324,7 +375,7 @@ function validateReferenceKey(reference, owner, diagnostics) {
|
|
|
324
375
|
diagnostics.push(
|
|
325
376
|
diagnostic({
|
|
326
377
|
code: "invalid-key",
|
|
327
|
-
message: `${owner.id} references invalid notation key ${JSON.stringify(reference.key)}`,
|
|
378
|
+
message: `${owner.id} references invalid notation key ${JSON.stringify(reference.key)}${keyHint(reference.key)}`,
|
|
328
379
|
key: reference.key,
|
|
329
380
|
lessonId: owner.kind === "local" ? owner.lesson.lessonId : void 0,
|
|
330
381
|
definitionId: owner.id,
|
|
@@ -338,7 +389,7 @@ function validatePageReferenceKey(reference, lesson, diagnostics) {
|
|
|
338
389
|
diagnostics.push(
|
|
339
390
|
diagnostic({
|
|
340
391
|
code: "invalid-key",
|
|
341
|
-
message: `${lesson.lessonId} references invalid notation key ${JSON.stringify(reference.key)}`,
|
|
392
|
+
message: `${lesson.lessonId} references invalid notation key ${JSON.stringify(reference.key)}${keyHint(reference.key)}`,
|
|
342
393
|
key: reference.key,
|
|
343
394
|
lessonId: lesson.lessonId,
|
|
344
395
|
source: reference.source
|
|
@@ -389,14 +440,14 @@ function toDefinitionRecord(candidate) {
|
|
|
389
440
|
sources: input2.sources,
|
|
390
441
|
seeAlso: input2.seeAlso,
|
|
391
442
|
alignment: input2.alignment,
|
|
392
|
-
status: input2.status,
|
|
393
443
|
aiAssisted: input2.aiAssisted,
|
|
394
444
|
body: input2.body,
|
|
395
445
|
glosses: input2.glosses,
|
|
396
446
|
source: input2.source,
|
|
397
447
|
resolvedReferences: candidate.resolvedReferences,
|
|
398
448
|
...input2.formula === void 0 ? {} : { formula: input2.formula },
|
|
399
|
-
...input2.units === void 0 ? {} : { units: input2.units }
|
|
449
|
+
...input2.units === void 0 ? {} : { units: input2.units },
|
|
450
|
+
...indexRecordFields(input2)
|
|
400
451
|
};
|
|
401
452
|
return record2;
|
|
402
453
|
}
|
|
@@ -413,15 +464,23 @@ function toDefinitionRecord(candidate) {
|
|
|
413
464
|
sources: input.sources,
|
|
414
465
|
seeAlso: input.seeAlso,
|
|
415
466
|
alignment: input.alignment,
|
|
416
|
-
status: candidate.lesson.status,
|
|
417
467
|
glosses: input.glosses,
|
|
418
468
|
source: input.source,
|
|
419
469
|
resolvedReferences: candidate.resolvedReferences,
|
|
420
470
|
...input.formula === void 0 ? {} : { formula: input.formula },
|
|
421
|
-
...input.units === void 0 ? {} : { units: input.units }
|
|
471
|
+
...input.units === void 0 ? {} : { units: input.units },
|
|
472
|
+
...indexRecordFields(input)
|
|
422
473
|
};
|
|
423
474
|
return record;
|
|
424
475
|
}
|
|
476
|
+
function indexRecordFields(input) {
|
|
477
|
+
return {
|
|
478
|
+
...input.reads === void 0 ? {} : { reads: input.reads },
|
|
479
|
+
...input.range === void 0 ? {} : { range: input.range },
|
|
480
|
+
...input.fixedIndex === void 0 ? {} : { fixedIndex: input.fixedIndex },
|
|
481
|
+
...input.formulaTemplate === void 0 ? {} : { formulaTemplate: input.formulaTemplate }
|
|
482
|
+
};
|
|
483
|
+
}
|
|
425
484
|
function definitionFingerprint(candidate) {
|
|
426
485
|
const references = sortedReferences(candidate.input.references).map(
|
|
427
486
|
(reference) => ({
|
|
@@ -452,7 +511,6 @@ function definitionFingerprint(candidate) {
|
|
|
452
511
|
sources: [...input2.sources].sort(),
|
|
453
512
|
seeAlso: [...input2.seeAlso].sort(),
|
|
454
513
|
alignment,
|
|
455
|
-
status: input2.status,
|
|
456
514
|
aiAssisted: input2.aiAssisted,
|
|
457
515
|
body: normalizeText(input2.body),
|
|
458
516
|
glosses: input2.glosses,
|
|
@@ -564,6 +622,52 @@ function uniqueSorted(values) {
|
|
|
564
622
|
function sortedSources(values) {
|
|
565
623
|
return [...values].sort(compareSourceSpans);
|
|
566
624
|
}
|
|
625
|
+
function malformedReferences(lesson) {
|
|
626
|
+
if (!lesson.body?.includes("[[")) return [];
|
|
627
|
+
const prose = proseOnly(lesson.body, { keepReferences: true });
|
|
628
|
+
const found = [];
|
|
629
|
+
for (let at = prose.indexOf("[["); at !== -1; at = prose.indexOf("[[", at + 2)) {
|
|
630
|
+
if (lesson.body[at - 1] === "\\") continue;
|
|
631
|
+
const closed = /^\[\[[^[\]\n]*\]\]/.exec(prose.slice(at));
|
|
632
|
+
if (closed) {
|
|
633
|
+
at += closed[0].length - 2;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
const near = lesson.body.slice(at, at + 40).split("\n")[0];
|
|
637
|
+
const line = lineOf(lesson.body, at) + (lesson.bodyLine ?? 1) - 1;
|
|
638
|
+
found.push(
|
|
639
|
+
diagnostic({
|
|
640
|
+
code: "malformed-reference",
|
|
641
|
+
message: `${lesson.lessonId} opens a reference that never closes, near ${JSON.stringify(near)}: close it with ]], as [[semantic.key]], on the same line.`,
|
|
642
|
+
lessonId: lesson.lessonId,
|
|
643
|
+
source: { ...lesson.source, line }
|
|
644
|
+
})
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
return found;
|
|
648
|
+
}
|
|
649
|
+
const FLOAT_KINDS = {
|
|
650
|
+
"eq-": "an equation",
|
|
651
|
+
"tab-": "a table",
|
|
652
|
+
"fig-": "a figure",
|
|
653
|
+
"dia-": "a diagram",
|
|
654
|
+
"ex-": "a worked-example set",
|
|
655
|
+
"check-": "a knowledge check",
|
|
656
|
+
"sec-": "a section",
|
|
657
|
+
"memo-": "a memo"
|
|
658
|
+
};
|
|
659
|
+
function keyHint(key) {
|
|
660
|
+
const reserved = reservedKeyPrefix(key);
|
|
661
|
+
if (reserved !== void 0) {
|
|
662
|
+
return `: [[${reserved}\u2026]] names ${FLOAT_KINDS[reserved]}, whose id is lower-case words and digits joined by "-"; ${JSON.stringify(key.slice(reserved.length))} is not one.`;
|
|
663
|
+
}
|
|
664
|
+
const bar = key.indexOf("|");
|
|
665
|
+
if (bar > 0) {
|
|
666
|
+
const target = key.slice(0, bar).trim();
|
|
667
|
+
return `: a [[\u2026]] reference takes no link text of its own \u2014 it reads as the entry's label. Write [[${target}]], with the words around it.`;
|
|
668
|
+
}
|
|
669
|
+
return ': a key is lower-case words and digits joined by "-" or "." (motion.launch-speed).';
|
|
670
|
+
}
|
|
567
671
|
function diagnostic(input) {
|
|
568
672
|
return { ...input, severity: "error" };
|
|
569
673
|
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KaTeX writes each formula twice: as MathML, whose `<annotation>` holds the
|
|
3
|
+
* LaTeX source, for assistive technology, and as the visible glyphs. Mark the
|
|
4
|
+
* MathML copy `data-pagefind-ignore`, so the site search indexes a formula
|
|
5
|
+
* once, as it reads, and never its LaTeX (`\explain{…}{…}`, `\dfrac`).
|
|
6
|
+
*/
|
|
7
|
+
export function markMathmlForSearch(node: any): void;
|
|
1
8
|
/**
|
|
2
9
|
* rehype-katex reports parse failures as non-fatal VFile messages and renders
|
|
3
10
|
* a `.katex-error` fallback. Turn those recovered failures into compiler
|
|
4
11
|
* errors so Astro cannot successfully build a lesson containing broken math.
|
|
12
|
+
* The pass every course runs right after KaTeX, it also keeps the LaTeX
|
|
13
|
+
* annotations out of the site search (`markMathmlForSearch`).
|
|
5
14
|
*/
|
|
6
15
|
export default function rehypeFailKatexErrors(): (tree: any, file: any) => void;
|