explico 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +879 -1
- package/README.md +200 -30
- package/dist/compiler/astro.d.ts +15 -2
- package/dist/compiler/astro.js +40 -11
- package/dist/compiler/cli-main.d.ts +43 -0
- package/dist/compiler/cli-main.js +392 -0
- package/dist/compiler/cli.d.ts +424 -9
- package/dist/compiler/cli.js +1289 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +105 -1
- package/dist/compiler/decks.d.ts +161 -0
- package/dist/compiler/decks.js +235 -0
- package/dist/compiler/exports/combined-html.d.ts +5 -1
- package/dist/compiler/exports/deck-fit.d.ts +55 -0
- package/dist/compiler/exports/deck-fit.js +90 -0
- package/dist/compiler/exports/export-chapters.d.ts +37 -6
- package/dist/compiler/exports/export-chapters.js +64 -5
- package/dist/compiler/exports/export-pages.d.ts +30 -3
- package/dist/compiler/exports/export-pages.js +24 -1
- package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/dist/compiler/exports/latex/cache.d.ts +78 -0
- package/dist/compiler/exports/latex/cache.js +129 -0
- package/dist/compiler/exports/latex/capture.d.ts +10 -1
- package/dist/compiler/exports/latex/capture.js +3 -1
- package/dist/compiler/exports/latex/compile.d.ts +13 -2
- package/dist/compiler/exports/latex/compile.js +12 -1
- package/dist/compiler/exports/latex/deck.d.ts +92 -0
- package/dist/compiler/exports/latex/deck.js +349 -0
- package/dist/compiler/exports/latex/document.d.ts +51 -6
- package/dist/compiler/exports/latex/document.js +71 -12
- package/dist/compiler/exports/latex/explico-common.sty +198 -0
- package/dist/compiler/exports/latex/explico.cls +13 -183
- package/dist/compiler/exports/latex/serialize.d.ts +60 -4
- package/dist/compiler/exports/latex/serialize.js +4 -2
- package/dist/compiler/exports/latex-export.d.ts +24 -2
- package/dist/compiler/exports/latex-export.js +107 -26
- package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
- package/dist/compiler/exports/markdown/serialize.js +85 -8
- package/dist/compiler/exports/markdown-export.d.ts +6 -1
- package/dist/compiler/exports/markdown-export.js +50 -11
- package/dist/compiler/exports/standalone-html.d.ts +10 -5
- package/dist/compiler/exports/standalone-html.js +3 -3
- package/dist/compiler/exports/static-tree.d.ts +38 -1
- package/dist/compiler/exports/static-tree.js +120 -4
- package/dist/compiler/knowledge-version.d.ts +26 -2
- package/dist/compiler/knowledge-version.js +27 -17
- package/dist/compiler/lesson-derivation.d.ts +143 -6
- package/dist/compiler/lesson-derivation.js +145 -13
- package/dist/compiler/manifest.d.ts +133 -4
- package/dist/compiler/manifest.js +359 -58
- package/dist/compiler/page-versions.d.ts +160 -0
- package/dist/compiler/page-versions.js +198 -0
- package/dist/compiler/render-diagnostics.d.ts +5 -1
- package/dist/compiler/resolution-report.d.ts +24 -6
- package/dist/compiler/resolution-report.js +22 -4
- package/dist/compiler/validate-content.d.ts +7 -0
- package/dist/compiler/validate-content.js +160 -0
- package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
- package/dist/curriculum/competency-graph.d.ts +54 -0
- package/dist/curriculum/competency-graph.js +41 -0
- package/dist/reference/base-library.d.mts +8 -0
- package/dist/reference/base-library.mjs +19 -0
- package/dist/reference/consistency.d.ts +8 -4
- package/dist/reference/consistency.js +76 -26
- package/dist/reference/deck-remark.d.mts +123 -0
- package/dist/reference/deck-remark.mjs +600 -0
- package/dist/reference/deck-source.d.ts +107 -0
- package/dist/reference/deck-source.js +140 -0
- package/dist/reference/decks-validate.d.ts +133 -0
- package/dist/reference/decks-validate.js +359 -0
- package/dist/reference/derived-entries.d.ts +5 -1
- package/dist/reference/diagram-fit.d.ts +1 -1
- package/dist/reference/figure-symbols.d.ts +23 -6
- package/dist/reference/figure-symbols.js +51 -15
- package/dist/reference/float-name.d.ts +43 -0
- package/dist/reference/float-name.js +58 -0
- package/dist/reference/folds-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-indices.js +5 -4
- package/dist/reference/gate-math.d.ts +29 -2
- package/dist/reference/gate-math.js +99 -18
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/lab-katex-validate.d.ts +10 -6
- package/dist/reference/lab-katex-validate.js +17 -9
- package/dist/reference/lab-math-scope.js +29 -4
- package/dist/reference/math-glyphs.d.mts +25 -0
- package/dist/reference/math-glyphs.mjs +189 -25
- package/dist/reference/page-notation.d.ts +22 -3
- package/dist/reference/page-notation.js +32 -10
- package/dist/reference/references.d.ts +14 -1
- package/dist/reference/references.js +13 -0
- package/dist/reference/registry-scope.d.mts +33 -0
- package/dist/reference/registry-scope.mjs +34 -0
- package/dist/reference/registry.js +29 -10
- package/dist/reference/rehype-deck.d.mts +6 -0
- package/dist/reference/rehype-deck.mjs +286 -0
- package/dist/reference/rehype-heading-anchors.d.mts +20 -0
- package/dist/reference/rehype-heading-anchors.mjs +48 -6
- package/dist/reference/remark-notation.mjs +249 -40
- package/dist/reference/source-lines.d.mts +12 -0
- package/dist/reference/source-lines.mjs +65 -0
- package/dist/reference/types.d.ts +28 -0
- package/dist/rules/catalog.d.ts +21 -4
- package/dist/rules/catalog.js +221 -2
- package/dist/rules/course-rules.d.ts +5 -1
- package/dist/rules/course-rules.js +17 -3
- package/dist/rules/course-rules.schema.json +12 -0
- package/dist/rules/in-effect.d.ts +13 -3
- package/dist/rules/in-effect.js +30 -7
- package/dist/rules/rules.schema.json +259 -1
- package/dist/rules/settings.d.ts +1 -1
- package/dist/session/PreferenceStore.d.ts +6 -0
- package/dist/session/PreferenceStore.js +18 -1
- package/dist/session/deck-memory.d.ts +116 -0
- package/dist/session/deck-memory.js +143 -0
- package/dist/session/reading-memory.d.ts +96 -0
- package/dist/session/reading-memory.js +133 -0
- package/docs/VERSIONING.md +21 -18
- package/docs/authoring/README.md +29 -9
- package/docs/authoring/agents.md +63 -16
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +588 -0
- package/docs/authoring/migrating.md +1045 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +54 -2
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +37 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
- package/docs/course-agent/skills/release-content/SKILL.md +24 -0
- package/docs/diagram-scaling.md +148 -0
- package/docs/privacy.md +59 -0
- package/package.json +8 -2
- package/src/compiler/astro.ts +60 -21
- package/src/compiler/cli-main.ts +469 -0
- package/src/compiler/cli.ts +1905 -16
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/course-config.ts +267 -0
- package/src/compiler/decks.ts +455 -0
- package/src/compiler/exports/deck-fit.ts +127 -0
- package/src/compiler/exports/export-chapters.ts +105 -6
- package/src/compiler/exports/export-pages.ts +46 -2
- package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/src/compiler/exports/latex/cache.ts +183 -0
- package/src/compiler/exports/latex/capture.ts +5 -2
- package/src/compiler/exports/latex/compile.ts +18 -0
- package/src/compiler/exports/latex/deck.ts +419 -0
- package/src/compiler/exports/latex/document.ts +117 -21
- package/src/compiler/exports/latex/explico-common.sty +198 -0
- package/src/compiler/exports/latex/explico.cls +13 -183
- package/src/compiler/exports/latex/serialize.ts +25 -21
- package/src/compiler/exports/latex/texlive-packages.txt +6 -2
- package/src/compiler/exports/latex-export.ts +187 -45
- package/src/compiler/exports/markdown/serialize.ts +118 -9
- package/src/compiler/exports/markdown-export.ts +56 -11
- package/src/compiler/exports/standalone-html.ts +8 -7
- package/src/compiler/exports/static-tree.ts +175 -3
- package/src/compiler/knowledge-version.ts +56 -21
- package/src/compiler/lesson-derivation.ts +282 -16
- package/src/compiler/manifest.ts +558 -63
- package/src/compiler/page-versions.ts +359 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +212 -0
- package/src/components/CourseContents.astro +124 -6
- package/src/components/CurriculumMap.astro +49 -1
- package/src/components/FloatIndex.astro +1 -1
- package/src/components/PartOverview.astro +51 -5
- package/src/components/assessments/AssessmentSet.astro +41 -15
- package/src/components/block-heading.ts +15 -6
- package/src/components/card-carry.ts +7 -4
- package/src/components/card-manager.ts +14 -2
- package/src/components/card-memory.ts +13 -9
- package/src/components/deck/DeckEnhancer.astro +13 -0
- package/src/components/deck/deck-context.ts +104 -0
- package/src/components/deck/deck-controller.ts +1287 -0
- package/src/components/deck/deck-map.ts +91 -0
- package/src/components/deck-lane.ts +163 -0
- package/src/components/diagram/Diagram.astro +131 -86
- package/src/components/disclosure/persisted-disclosure.ts +9 -1
- package/src/components/figure/Figure.astro +7 -2
- package/src/components/figure/FloatCaption.astro +5 -3
- package/src/components/fold/Fold.astro +2 -2
- package/src/components/notation/NotationFormula.astro +81 -11
- package/src/components/notation/NotationGlossary.astro +132 -1
- package/src/components/notation/NotationLayer.astro +15 -7
- package/src/components/starlight/AboutPanel.astro +186 -3
- package/src/components/starlight/CollapsibleSections.astro +24 -3
- package/src/components/starlight/DiagramEnhancer.astro +5 -1
- package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
- package/src/components/starlight/LayoutHeader.astro +17 -0
- package/src/components/starlight/LayoutPageTitle.astro +110 -0
- package/src/components/starlight/LayoutSidebar.astro +807 -21
- package/src/components/starlight/LayoutSocialIcons.astro +62 -6
- package/src/components/starlight/LessonExportActions.astro +27 -9
- package/src/components/starlight/LessonFooter.astro +59 -0
- package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
- package/src/components/starlight/TextSizeControl.astro +24 -13
- package/src/components/starlight/page-marks.ts +139 -0
- package/src/components/starlight/section-summary.ts +1 -1
- package/src/components/starlight/sidebar-editions.ts +245 -0
- package/src/components/table/Table.astro +15 -7
- package/src/content-config.ts +87 -1
- package/src/curriculum/competency-graph.ts +95 -0
- package/src/reference/base-library.mjs +19 -0
- package/src/reference/consistency.ts +126 -39
- package/src/reference/deck-remark.mjs +600 -0
- package/src/reference/deck-source.ts +273 -0
- package/src/reference/decks-validate.ts +604 -0
- package/src/reference/diagram-layout.ts +3 -1
- package/src/reference/figure-symbols.ts +108 -31
- package/src/reference/folds-validate.ts +1 -1
- package/src/reference/gate-indices.ts +5 -3
- package/src/reference/gate-math.ts +169 -25
- package/src/reference/lab-katex-validate.ts +30 -15
- package/src/reference/lab-math-scope.ts +34 -3
- package/src/reference/math-glyphs.mjs +189 -25
- package/src/reference/page-notation.ts +69 -15
- package/src/reference/references.ts +28 -0
- package/src/reference/registry-scope.mjs +34 -0
- package/src/reference/registry.ts +41 -11
- package/src/reference/rehype-deck.mjs +286 -0
- package/src/reference/rehype-heading-anchors.mjs +48 -6
- package/src/reference/remark-notation.mjs +249 -40
- package/src/reference/source-lines.mjs +65 -0
- package/src/reference/types.ts +28 -0
- package/src/rules/catalog.ts +257 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +54 -8
- package/src/session/PreferenceStore.ts +23 -0
- package/src/session/deck-memory.ts +263 -0
- package/src/session/reading-memory.ts +243 -0
- package/src/styles/deck.css +1150 -0
- package/src/styles/global.css +958 -27
- package/src/styles/zones.css +277 -0
- /package/src/{components → reference}/float-name.ts +0 -0
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
* snapshot. Nothing here changes content. A finding is silenced only by a
|
|
10
10
|
* reviewed line in `lint-ignore.yml` (see `./lint-ignore`).
|
|
11
11
|
*
|
|
12
|
-
* (a) glyph-unique-in-corpus one rendered glyph → one meaning
|
|
12
|
+
* (a) glyph-unique-in-corpus one rendered glyph → one shared meaning; a
|
|
13
|
+
* local card or a gloss may reuse a letter
|
|
14
|
+
* (a') definition-repeated one local key declared in two lessons
|
|
15
|
+
* (a'') meaning-repeated one symbol and name defined at two sites, any tier
|
|
13
16
|
* (b) notation-units / units-vocab every entry has units or `dimensionless`,
|
|
14
17
|
* unit strings drawn from a controlled vocab
|
|
15
18
|
* (f) weak-local a `notation.local` symbol used only in its
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
* `src/content/resolution-report.ts`.
|
|
36
39
|
*/
|
|
37
40
|
|
|
41
|
+
import type { LocalNotationDefinitionInput } from './types';
|
|
38
42
|
import type {
|
|
39
43
|
CourseAccents,
|
|
40
44
|
CourseOperators,
|
|
@@ -70,7 +74,8 @@ export type ConsistencyCode =
|
|
|
70
74
|
| 'units-vocab'
|
|
71
75
|
| 'weak-local'
|
|
72
76
|
| 'notation-source-locator'
|
|
73
|
-
| '
|
|
77
|
+
| 'definition-repeated'
|
|
78
|
+
| 'meaning-repeated'
|
|
74
79
|
| 'card-wants-demoting'
|
|
75
80
|
| 'gloss-name-shape'
|
|
76
81
|
| 'operator-explained'
|
|
@@ -142,7 +147,7 @@ function mathSpans(body: string): MathSpan[] {
|
|
|
142
147
|
|
|
143
148
|
// --- glyph regex for weak-local --------------------------------------
|
|
144
149
|
|
|
145
|
-
function glyphMatcher(latex: string): RegExp | undefined {
|
|
150
|
+
export function glyphMatcher(latex: string): RegExp | undefined {
|
|
146
151
|
const trimmed = latex.trim();
|
|
147
152
|
if (trimmed === '') return undefined;
|
|
148
153
|
if (/^[A-Za-z]$/.test(trimmed)) {
|
|
@@ -175,15 +180,19 @@ function checkGlyphUniqueness(
|
|
|
175
180
|
glyphs.set(trimmed, keys);
|
|
176
181
|
};
|
|
177
182
|
|
|
183
|
+
// Shared cards only: a vocabulary glyph has one meaning across the course.
|
|
184
|
+
// A `notation.local` entry or a gloss that reuses a letter is the declared
|
|
185
|
+
// exception — the tier exists for that — so it is never recorded here;
|
|
186
|
+
// `definition-repeated` and `meaning-repeated` watch those for copies.
|
|
178
187
|
for (const definition of input.registry.definitions) {
|
|
179
|
-
if (definition.kind === '
|
|
180
|
-
record(definition.notation, definition.key,
|
|
188
|
+
if (definition.kind === 'shared') {
|
|
189
|
+
record(definition.notation, definition.key, '');
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
192
|
for (const bundle of input.registry.bundles) {
|
|
184
193
|
for (const binding of bundle.bindings) {
|
|
185
194
|
const definition = byId.get(binding.definitionId);
|
|
186
|
-
if (definition) record(definition.notation, binding.key, bundle.lessonId);
|
|
195
|
+
if (definition?.kind === 'shared') record(definition.notation, binding.key, bundle.lessonId);
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
198
|
|
|
@@ -194,13 +203,16 @@ function checkGlyphUniqueness(
|
|
|
194
203
|
if (input.lintIgnore.matches('glyph-unique-in-corpus', glyph)) continue;
|
|
195
204
|
const detail = [...keys]
|
|
196
205
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
197
|
-
.map(([key, lessons]) =>
|
|
206
|
+
.map(([key, lessons]) => {
|
|
207
|
+
const bound = [...lessons].filter((lesson) => lesson !== '').sort();
|
|
208
|
+
return `${key} (${bound.length > 0 ? bound.join(', ') : 'no lesson binds it'})`;
|
|
209
|
+
})
|
|
198
210
|
.join('; ');
|
|
199
211
|
out.push({
|
|
200
212
|
code: 'glyph-unique-in-corpus',
|
|
201
213
|
severity: 'warning',
|
|
202
214
|
glyph,
|
|
203
|
-
message: `glyph ${JSON.stringify(glyph)}
|
|
215
|
+
message: `glyph ${JSON.stringify(glyph)} is ${keys.size} shared cards: ${detail}; course vocabulary gives a glyph one meaning — keep one card, or make the page-bound one a notation.local entry`,
|
|
204
216
|
});
|
|
205
217
|
}
|
|
206
218
|
}
|
|
@@ -286,50 +298,123 @@ function checkNotationSourceLocator(
|
|
|
286
298
|
}
|
|
287
299
|
|
|
288
300
|
/**
|
|
289
|
-
* The
|
|
301
|
+
* The tier model needs both directions kept honest (D15). A meaning is
|
|
302
|
+
* declared once: a shared card unless the letter already means something
|
|
303
|
+
* else in the course, and only then `notation.local` or a gloss. The sign
|
|
304
|
+
* that a meaning is not page-bound is that it got defined a second time —
|
|
305
|
+
* so the lints watch for copies, never for how often a symbol is used.
|
|
290
306
|
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
307
|
+
* `definition-repeated`: one local key declared in two or more lessons. Either
|
|
308
|
+
* it is one meaning, so it belongs in `content/notation/<key>.md` (every
|
|
309
|
+
* `[[key]]` keeps working), or it is two, so one needs another key. A deck
|
|
310
|
+
* inherits its chapters' entries rather than redeclaring them, so decks never
|
|
311
|
+
* count.
|
|
295
312
|
*/
|
|
296
|
-
|
|
313
|
+
function checkDefinitionRepeated(
|
|
314
|
+
input: ConsistencyInput,
|
|
315
|
+
out: ConsistencyDiagnostic[],
|
|
316
|
+
): void {
|
|
317
|
+
const byKey = new Map<string, { lessonId: string; file: string; definition: LocalNotationDefinitionInput }[]>();
|
|
318
|
+
// A deck resolves in its chapters' scopes (`scopeLessonIds`) and is no
|
|
319
|
+
// declaration site of its own, whatever its frontmatter repeats.
|
|
320
|
+
const chapters = input.notationInput.lessons.filter((lesson) => lesson.scopeLessonIds === undefined);
|
|
321
|
+
for (const lesson of [...chapters].sort((a, b) => a.lessonId.localeCompare(b.lessonId))) {
|
|
322
|
+
for (const definition of lesson.localDefinitions) {
|
|
323
|
+
const list = byKey.get(definition.key) ?? [];
|
|
324
|
+
if (!list.some((entry) => entry.lessonId === lesson.lessonId)) {
|
|
325
|
+
list.push({ lessonId: lesson.lessonId, file: lesson.source.file, definition });
|
|
326
|
+
}
|
|
327
|
+
byKey.set(definition.key, list);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
for (const [key, copies] of [...byKey].sort(([a], [b]) => a.localeCompare(b))) {
|
|
331
|
+
if (copies.length < 2) continue;
|
|
332
|
+
if (input.lintIgnore.matches('definition-repeated', key)) continue;
|
|
333
|
+
const first = copies[0]!;
|
|
334
|
+
const differing = (['notation', 'label', 'summary', 'units', 'sources'] as const).filter((field) =>
|
|
335
|
+
copies.some((copy) => JSON.stringify(copy.definition[field] ?? null) !== JSON.stringify(first.definition[field] ?? null)),
|
|
336
|
+
);
|
|
337
|
+
const lessons = copies.map((copy) => copy.lessonId).sort();
|
|
338
|
+
out.push({
|
|
339
|
+
code: 'definition-repeated',
|
|
340
|
+
severity: 'warning',
|
|
341
|
+
key,
|
|
342
|
+
lessonId: first.lessonId,
|
|
343
|
+
file: first.file,
|
|
344
|
+
count: copies.length,
|
|
345
|
+
message:
|
|
346
|
+
`local entry ${key} (${first.definition.notation}) is declared in ${copies.length} lessons (${lessons.join(', ')}); ` +
|
|
347
|
+
(differing.length === 0
|
|
348
|
+
? 'the copies agree'
|
|
349
|
+
: `the copies differ in ${differing.join(', ')}`) +
|
|
350
|
+
` — move one copy to content/notation/${key}.md and delete the others: every [[${key}]] and \\explain{${key}} keeps working; if they are two meanings, give one another key`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
297
354
|
|
|
298
|
-
|
|
355
|
+
/**
|
|
356
|
+
* `meaning-repeated`: one symbol with one name defined at two or more sites,
|
|
357
|
+
* in any tier — a local card and a gloss, two glosses, a local card beside a
|
|
358
|
+
* shared card that already says it. A second definition of the same meaning
|
|
359
|
+
* is the signal that it is vocabulary; a shared card serves every site, and
|
|
360
|
+
* where one exists already the page should bind it instead.
|
|
361
|
+
*/
|
|
362
|
+
function checkMeaningRepeated(
|
|
299
363
|
input: ConsistencyInput,
|
|
300
364
|
out: ConsistencyDiagnostic[],
|
|
301
365
|
): void {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
366
|
+
interface Site {
|
|
367
|
+
readonly tier: 'shared' | 'local' | 'gloss';
|
|
368
|
+
readonly key: string;
|
|
369
|
+
readonly where: string;
|
|
370
|
+
}
|
|
371
|
+
const normalize = (label: string) => label.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
372
|
+
const groups = new Map<string, { notation: string; label: string; sites: Site[] }>();
|
|
373
|
+
const record = (notation: string, label: string, site: Site) => {
|
|
374
|
+
const id = `${notation.trim()}\u0000${normalize(label)}`;
|
|
375
|
+
const group = groups.get(id) ?? { notation: notation.trim(), label, sites: [] };
|
|
376
|
+
if (!group.sites.some((known) => known.tier === site.tier && known.key === site.key && known.where === site.where)) {
|
|
377
|
+
group.sites.push(site);
|
|
378
|
+
}
|
|
379
|
+
groups.set(id, group);
|
|
311
380
|
};
|
|
312
|
-
|
|
313
381
|
for (const definition of input.notationInput.sharedDefinitions) {
|
|
314
|
-
|
|
382
|
+
record(definition.notation, definition.label, { tier: 'shared', key: definition.key, where: `card ${definition.key}` });
|
|
383
|
+
for (const gloss of definition.glosses) {
|
|
384
|
+
record(gloss.notation, gloss.label, { tier: 'gloss', key: gloss.key, where: `gloss on ${definition.key}` });
|
|
385
|
+
}
|
|
315
386
|
}
|
|
316
387
|
for (const lesson of input.notationInput.lessons) {
|
|
388
|
+
if (lesson.scopeLessonIds !== undefined) continue; // a deck declares nothing of its own
|
|
317
389
|
for (const definition of lesson.localDefinitions) {
|
|
318
|
-
|
|
390
|
+
record(definition.notation, definition.label, {
|
|
391
|
+
tier: 'local',
|
|
392
|
+
key: definition.key,
|
|
393
|
+
where: `local ${definition.key} on ${lesson.lessonId}`,
|
|
394
|
+
});
|
|
395
|
+
for (const gloss of definition.glosses) {
|
|
396
|
+
record(gloss.notation, gloss.label, { tier: 'gloss', key: gloss.key, where: `gloss on ${definition.key} (${lesson.lessonId})` });
|
|
397
|
+
}
|
|
319
398
|
}
|
|
320
399
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if (
|
|
326
|
-
const
|
|
327
|
-
if (input.lintIgnore.matches('gloss-wants-promoting', glyph)) continue;
|
|
400
|
+
for (const [, group] of [...groups].sort(([a], [b]) => a.localeCompare(b))) {
|
|
401
|
+
if (group.sites.length < 2) continue;
|
|
402
|
+
// One local key copied across lessons is `definition-repeated`'s finding.
|
|
403
|
+
if (group.sites.every((site) => site.tier === 'local' && site.key === group.sites[0]!.key)) continue;
|
|
404
|
+
if (input.lintIgnore.matches('meaning-repeated', group.notation)) continue;
|
|
405
|
+
const shared = group.sites.find((site) => site.tier === 'shared');
|
|
328
406
|
out.push({
|
|
329
|
-
code: '
|
|
407
|
+
code: 'meaning-repeated',
|
|
330
408
|
severity: 'info',
|
|
331
|
-
glyph,
|
|
332
|
-
|
|
409
|
+
glyph: group.notation,
|
|
410
|
+
count: group.sites.length,
|
|
411
|
+
message:
|
|
412
|
+
`${group.notation} as ${JSON.stringify(group.label)} is defined ${group.sites.length} times: ${group.sites
|
|
413
|
+
.map((site) => site.where)
|
|
414
|
+
.join('; ')}` +
|
|
415
|
+
(shared
|
|
416
|
+
? ` — ${shared.key} is the shared card; bind it with [[${shared.key}]] (or \\explain{${shared.key}}{${group.notation}} in a formula) instead of declaring it again`
|
|
417
|
+
: ' — one shared card would serve every site; promote it and reference it'),
|
|
333
418
|
});
|
|
334
419
|
}
|
|
335
420
|
}
|
|
@@ -726,7 +811,8 @@ const CHECKS: ((
|
|
|
726
811
|
checkNotationUnits,
|
|
727
812
|
checkWeakLocal,
|
|
728
813
|
checkNotationSourceLocator,
|
|
729
|
-
|
|
814
|
+
checkDefinitionRepeated,
|
|
815
|
+
checkMeaningRepeated,
|
|
730
816
|
checkCardWantsDemoting,
|
|
731
817
|
checkGlossNameShape,
|
|
732
818
|
checkOperatorExplained,
|
|
@@ -765,7 +851,8 @@ export function consistencyCounts(
|
|
|
765
851
|
'units-vocab': 0,
|
|
766
852
|
'weak-local': 0,
|
|
767
853
|
'notation-source-locator': 0,
|
|
768
|
-
'
|
|
854
|
+
'definition-repeated': 0,
|
|
855
|
+
'meaning-repeated': 0,
|
|
769
856
|
'card-wants-demoting': 0,
|
|
770
857
|
'gloss-name-shape': 0,
|
|
771
858
|
'operator-explained': 0,
|