explico 0.13.1 → 0.15.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 +990 -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 +100 -0
- package/dist/compiler/cli-main.js +433 -0
- package/dist/compiler/cli-reference.d.ts +50 -0
- package/dist/compiler/cli-reference.js +213 -0
- package/dist/compiler/cli-verbs.d.ts +45 -0
- package/dist/compiler/cli-verbs.js +224 -0
- package/dist/compiler/cli-verify.d.ts +51 -0
- package/dist/compiler/cli-verify.js +151 -0
- package/dist/compiler/cli.d.ts +408 -24
- package/dist/compiler/cli.js +1328 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/content-release.d.ts +49 -0
- package/dist/compiler/content-release.js +63 -0
- package/dist/compiler/content-schemas.d.ts +2 -2
- 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 +364 -58
- package/dist/compiler/page-versions.d.ts +184 -0
- package/dist/compiler/page-versions.js +217 -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 +82 -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 +6 -2
- package/dist/reference/diagram-fit.js +5 -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 +237 -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 +34 -10
- package/dist/rules/rules.schema.json +280 -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 +31 -9
- package/docs/authoring/agents.md +72 -18
- package/docs/authoring/cli-reference.json +2172 -0
- package/docs/authoring/cli.md +887 -0
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +612 -0
- package/docs/authoring/migrating.md +1195 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +56 -3
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +40 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +38 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +32 -0
- package/docs/course-agent/skills/release-content/SKILL.md +26 -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 +557 -0
- package/src/compiler/cli-reference.ts +285 -0
- package/src/compiler/cli-verbs.ts +270 -0
- package/src/compiler/cli-verify.ts +241 -0
- package/src/compiler/cli.ts +2119 -170
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/content-release.ts +91 -0
- 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 +568 -63
- package/src/compiler/page-versions.ts +401 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +215 -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 +137 -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-fit.ts +18 -4
- 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 +274 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +58 -11
- 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
|
@@ -6,6 +6,265 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"properties": {
|
|
9
|
+
"D1": {
|
|
10
|
+
"title": "D1 — A deck is sections of frames: `##` a section, `###` a frame",
|
|
11
|
+
"description": "In a `<lesson>.deck.mdx`, `##` opens a section, a divider frame that shows only its title, and `###` is a frame whose title is the heading. Write every line of content inside a `###` frame: no `#`, no `####` or deeper, nothing before the first heading and nothing between a `##` and its first `###`. Locked — a frame is the unit the deck page, Present mode and the PDF are built from — content outside one has no frame to show in.",
|
|
12
|
+
"x-element": "slide",
|
|
13
|
+
"x-elements": [
|
|
14
|
+
"slide",
|
|
15
|
+
"heading"
|
|
16
|
+
],
|
|
17
|
+
"x-enforcement": "locked",
|
|
18
|
+
"x-doc": "docs/authoring/deck.md#d1",
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"properties": {}
|
|
22
|
+
},
|
|
23
|
+
"D2": {
|
|
24
|
+
"title": "D2 — A frame fits its canvas in every step",
|
|
25
|
+
"description": "Everything a frame shows — title, body, legend line, at its last step — fits the course’s canvas (`deck.aspectRatio`). `content check` warns when a frame passes `maxWords` words or `maxBullets` list items. A frame that does not fit is two frames; never shrink its type. Not checked by the build: the paper: a frame that fits its canvas on the web can still run over in the PDF, which the export reports as a warning naming the frame.",
|
|
26
|
+
"x-element": "slide",
|
|
27
|
+
"x-elements": [
|
|
28
|
+
"slide"
|
|
29
|
+
],
|
|
30
|
+
"x-enforcement": "partial",
|
|
31
|
+
"x-doc": "docs/authoring/deck.md#d2",
|
|
32
|
+
"type": "object",
|
|
33
|
+
"additionalProperties": false,
|
|
34
|
+
"properties": {
|
|
35
|
+
"enabled": {
|
|
36
|
+
"title": "Enabled",
|
|
37
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
38
|
+
"type": "boolean",
|
|
39
|
+
"default": true
|
|
40
|
+
},
|
|
41
|
+
"maxWords": {
|
|
42
|
+
"title": "Most words on a frame",
|
|
43
|
+
"description": "Words a frame may show (its prose, not its math or notes) before `content check` warns.",
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"minimum": 10,
|
|
46
|
+
"default": 70
|
|
47
|
+
},
|
|
48
|
+
"maxBullets": {
|
|
49
|
+
"title": "Most list items on a frame",
|
|
50
|
+
"description": "List items a frame may show before `content check` warns.",
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"minimum": 1,
|
|
53
|
+
"default": 7
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"D3": {
|
|
58
|
+
"title": "D3 — A frame makes one claim, and its title states it",
|
|
59
|
+
"description": "Title a frame with the sentence it shows to be true — “Range is largest at a 45° launch angle”, not “Range”. Everything on the frame serves that one claim; a second claim is a second frame.",
|
|
60
|
+
"x-element": "slide",
|
|
61
|
+
"x-elements": [
|
|
62
|
+
"slide",
|
|
63
|
+
"prose"
|
|
64
|
+
],
|
|
65
|
+
"x-enforcement": "guide",
|
|
66
|
+
"x-doc": "docs/authoring/deck.md#d3",
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"properties": {
|
|
70
|
+
"enabled": {
|
|
71
|
+
"title": "Enabled",
|
|
72
|
+
"description": "Off: the rule leaves the rules-in-effect page and an agent neither applies it nor flags it in review.",
|
|
73
|
+
"type": "boolean",
|
|
74
|
+
"default": true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"D4": {
|
|
79
|
+
"title": "D4 — A frame with text carries speaker notes",
|
|
80
|
+
"description": "A `###` frame whose body has words carries a `<Notes>…</Notes>` block with what the speaker says: the reasoning, the transitions, the question to ask the room. A frame that shows only a picture, an equation or a question needs none. The prose rules hold for the notes.",
|
|
81
|
+
"x-element": "slide",
|
|
82
|
+
"x-elements": [
|
|
83
|
+
"slide",
|
|
84
|
+
"prose"
|
|
85
|
+
],
|
|
86
|
+
"x-enforcement": "script",
|
|
87
|
+
"x-doc": "docs/authoring/deck.md#d4",
|
|
88
|
+
"type": "object",
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"properties": {
|
|
91
|
+
"enabled": {
|
|
92
|
+
"title": "Enabled",
|
|
93
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
94
|
+
"type": "boolean",
|
|
95
|
+
"default": true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"D5": {
|
|
100
|
+
"title": "D5 — A frame title fits one line",
|
|
101
|
+
"description": "A `##` or `###` heading in a deck runs to at most `maxLength` characters as the reader sees it (math as it reads, a `[[key]]` term as its label), so it stays on one line of the canvas. Move the rest into the frame.",
|
|
102
|
+
"x-element": "slide",
|
|
103
|
+
"x-elements": [
|
|
104
|
+
"slide",
|
|
105
|
+
"heading"
|
|
106
|
+
],
|
|
107
|
+
"x-enforcement": "script",
|
|
108
|
+
"x-doc": "docs/authoring/deck.md#d5",
|
|
109
|
+
"type": "object",
|
|
110
|
+
"additionalProperties": false,
|
|
111
|
+
"properties": {
|
|
112
|
+
"enabled": {
|
|
113
|
+
"title": "Enabled",
|
|
114
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
115
|
+
"type": "boolean",
|
|
116
|
+
"default": true
|
|
117
|
+
},
|
|
118
|
+
"maxLength": {
|
|
119
|
+
"title": "Longest frame title",
|
|
120
|
+
"description": "Characters a frame or section title may run to.",
|
|
121
|
+
"type": "integer",
|
|
122
|
+
"minimum": 10,
|
|
123
|
+
"default": 50
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"D6": {
|
|
128
|
+
"title": "D6 — A frame shows in at most `maxSteps` steps, each adding to the last",
|
|
129
|
+
"description": "`<Pause />` is the one step mark: what follows it appears on the next key press, and nothing shown earlier changes or goes, so the last step is the whole frame — what the scroll view, the print and the PDF show. Keep to `maxSteps` steps; more is a second frame. Not checked by the build: that a later step contradicts nothing already shown.",
|
|
130
|
+
"x-element": "slide",
|
|
131
|
+
"x-elements": [
|
|
132
|
+
"slide"
|
|
133
|
+
],
|
|
134
|
+
"x-enforcement": "partial",
|
|
135
|
+
"x-doc": "docs/authoring/deck.md#d6",
|
|
136
|
+
"type": "object",
|
|
137
|
+
"additionalProperties": false,
|
|
138
|
+
"properties": {
|
|
139
|
+
"enabled": {
|
|
140
|
+
"title": "Enabled",
|
|
141
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
142
|
+
"type": "boolean",
|
|
143
|
+
"default": true
|
|
144
|
+
},
|
|
145
|
+
"maxSteps": {
|
|
146
|
+
"title": "Most steps in a frame",
|
|
147
|
+
"description": "Steps a frame may show in (one more than its `<Pause />` marks).",
|
|
148
|
+
"type": "integer",
|
|
149
|
+
"minimum": 1,
|
|
150
|
+
"default": 4
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"D7": {
|
|
155
|
+
"title": "D7 — A frame holds one figure, table or diagram",
|
|
156
|
+
"description": "One `<Figure>`, `<Table>`, `<Diagram>` or recalled float per frame, laid out at the canvas width; a lab’s controls are the frame’s tools, live in Present mode. A second picture is a second frame.",
|
|
157
|
+
"x-element": "slide",
|
|
158
|
+
"x-elements": [
|
|
159
|
+
"slide",
|
|
160
|
+
"plot",
|
|
161
|
+
"table",
|
|
162
|
+
"diagram"
|
|
163
|
+
],
|
|
164
|
+
"x-enforcement": "script",
|
|
165
|
+
"x-doc": "docs/authoring/deck.md#d7",
|
|
166
|
+
"type": "object",
|
|
167
|
+
"additionalProperties": false,
|
|
168
|
+
"properties": {
|
|
169
|
+
"enabled": {
|
|
170
|
+
"title": "Enabled",
|
|
171
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
172
|
+
"type": "boolean",
|
|
173
|
+
"default": true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
"D8": {
|
|
178
|
+
"title": "D8 — Recall a chapter’s result; never retype it",
|
|
179
|
+
"description": "Show the chapter’s equation, figure, table or diagram with `<Recall ref=\"eq-range\" />` (`fig-`, `tab-`, `dia-`): it renders as in the chapter, with the chapter’s number, and links back to it. A display equation retyped from the chapter is a warning. An equation the deck labels itself numbers (1), (2) within the deck; the deck’s figures, tables and diagrams are unnumbered.",
|
|
180
|
+
"x-element": "slide",
|
|
181
|
+
"x-elements": [
|
|
182
|
+
"slide",
|
|
183
|
+
"equation"
|
|
184
|
+
],
|
|
185
|
+
"x-enforcement": "script",
|
|
186
|
+
"x-doc": "docs/authoring/deck.md#d8",
|
|
187
|
+
"type": "object",
|
|
188
|
+
"additionalProperties": false,
|
|
189
|
+
"properties": {
|
|
190
|
+
"enabled": {
|
|
191
|
+
"title": "Enabled",
|
|
192
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
193
|
+
"type": "boolean",
|
|
194
|
+
"default": true
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"D9": {
|
|
199
|
+
"title": "D9 — A frame introduces at most `maxNewSymbols` symbols",
|
|
200
|
+
"description": "The room reads a frame once. Count the symbols it shows for the first time in the deck and keep them to `maxNewSymbols`; the legend line under the frame names them. More than that is a frame of its own.",
|
|
201
|
+
"x-element": "slide",
|
|
202
|
+
"x-elements": [
|
|
203
|
+
"slide",
|
|
204
|
+
"math",
|
|
205
|
+
"notation"
|
|
206
|
+
],
|
|
207
|
+
"x-enforcement": "script",
|
|
208
|
+
"x-doc": "docs/authoring/deck.md#d9",
|
|
209
|
+
"type": "object",
|
|
210
|
+
"additionalProperties": false,
|
|
211
|
+
"properties": {
|
|
212
|
+
"enabled": {
|
|
213
|
+
"title": "Enabled",
|
|
214
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
215
|
+
"type": "boolean",
|
|
216
|
+
"default": true
|
|
217
|
+
},
|
|
218
|
+
"maxNewSymbols": {
|
|
219
|
+
"title": "Most new symbols on a frame",
|
|
220
|
+
"description": "Symbols a frame may show for the first time in its deck.",
|
|
221
|
+
"type": "integer",
|
|
222
|
+
"minimum": 1,
|
|
223
|
+
"default": 4
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"D10": {
|
|
228
|
+
"title": "D10 — A deck opens on its title and closes on what the student can now do",
|
|
229
|
+
"description": "The title frame (the lesson, the course, its authors and version) and the closing frame (the outcomes of the competencies the lesson teaches, `deck.outcomesFrame`) are generated: do not write them. With `deck.outcomesFrame` off, end on a `###` frame that says what the student can now do.",
|
|
230
|
+
"x-element": "slide",
|
|
231
|
+
"x-elements": [
|
|
232
|
+
"slide"
|
|
233
|
+
],
|
|
234
|
+
"x-enforcement": "guide",
|
|
235
|
+
"x-doc": "docs/authoring/deck.md#d10",
|
|
236
|
+
"type": "object",
|
|
237
|
+
"additionalProperties": false,
|
|
238
|
+
"properties": {
|
|
239
|
+
"enabled": {
|
|
240
|
+
"title": "Enabled",
|
|
241
|
+
"description": "Off: the rule leaves the rules-in-effect page and an agent neither applies it nor flags it in review.",
|
|
242
|
+
"type": "boolean",
|
|
243
|
+
"default": true
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
"D11": {
|
|
248
|
+
"title": "D11 — A deck is flagged when its chapter changed after it did",
|
|
249
|
+
"description": "No authoring action by itself: two files mean the chapter and the deck can drift apart with nothing to notice it. `deck-stale` is an info diagnostic naming a lesson’s own deck whose chapter’s rule C5 version is newer than the deck’s; read the chapter’s change and judge whether the deck needs it too. Scoped to a lesson’s own deck — a part’s deck covers more than one chapter, so it has none to compare against.",
|
|
250
|
+
"x-element": "slide",
|
|
251
|
+
"x-elements": [
|
|
252
|
+
"slide",
|
|
253
|
+
"changelog"
|
|
254
|
+
],
|
|
255
|
+
"x-enforcement": "script",
|
|
256
|
+
"x-doc": "docs/authoring/deck.md#d11",
|
|
257
|
+
"type": "object",
|
|
258
|
+
"additionalProperties": false,
|
|
259
|
+
"properties": {
|
|
260
|
+
"enabled": {
|
|
261
|
+
"title": "Enabled",
|
|
262
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
263
|
+
"type": "boolean",
|
|
264
|
+
"default": true
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
},
|
|
9
268
|
"N9": {
|
|
10
269
|
"title": "N9 — A quantity/unit/operator is typeset in `$…$`, never as plain text",
|
|
11
270
|
"description": "Never write `45 m/s`, `t (s)`, `vx` or `KE/m` as plain text, and never spell a stated quantity's unit out: \"4 seconds\", \"2 meters per second squared\", \"30 degrees\", \"$x = 3$ meters\" are `$4\\ \\text{s}$`, `$2\\ \\text{m/s}^2$`, `$30^{\\circ}$`, `$x = 3\\ \\text{m}$`. A unit inside math is `\\text{}`-wrapped, short form, in the same span as its number or symbol. A unit named on its own (\"measured in meters\") stays a word; a sentence that defines a unit is waived. JSX prop strings (`caption=\"…\"`) render no math, so N9 does not apply there; nor does it apply to an assessment choice label, which may still hold math (`$30^{\\circ}$`).",
|
|
@@ -324,7 +583,7 @@
|
|
|
324
583
|
},
|
|
325
584
|
"N4": {
|
|
326
585
|
"title": "N4 — One meaning per glyph; define once; `[[key]]` before first math",
|
|
327
|
-
"description": "Every glyph in rendered math resolves to exactly one notation entry on the page: introduce it with `[[key]]` in prose before its first `$…$`, define a page-local one in `notation.local`, or bind a compound with `\\explain{key}{latex}`. Do not reuse a glyph for a second meaning on the same page. Locked — the notation layer is this rule — an unresolved glyph has no hover card and the render path needs every glyph bound.",
|
|
586
|
+
"description": "Every glyph in rendered math resolves to exactly one notation entry on the page: introduce it with `[[key]]` in prose before its first `$…$`, define a page-local one in `notation.local`, or bind a compound with `\\explain{key}{latex}`. Do not reuse a glyph for a second meaning on the same page. Declare a meaning once — a shared card unless the letter already means something else in the course, and only then `notation.local` or a gloss — and reference it everywhere else. Locked — the notation layer is this rule — an unresolved glyph has no hover card and the render path needs every glyph bound.",
|
|
328
587
|
"x-element": "math",
|
|
329
588
|
"x-elements": [
|
|
330
589
|
"math",
|
|
@@ -1140,6 +1399,26 @@
|
|
|
1140
1399
|
"default": true
|
|
1141
1400
|
}
|
|
1142
1401
|
}
|
|
1402
|
+
},
|
|
1403
|
+
"C5": {
|
|
1404
|
+
"title": "C5 — Each chapter and part page carries the release its content last changed in; `content/versions.json` is generated and committed",
|
|
1405
|
+
"description": "A page’s PDF, Markdown and `[?]` panel say \"unchanged since version 0.2.0\", the release its content last changed in, or \"with changes after version 0.4.0, not yet released\" while `## [Unreleased]` holds its change. The record is `content/versions.json`: `validate:content` works it out from the committed file and the content, writes it on a developer’s machine, and in CI fails when the committed file is not the one it would write. Never edit it by hand; commit what `validate:content` wrote with the content change, and with a release. Not checked by the build: which bullet of `## [Unreleased]` belongs to which page — every page changed while there is any bullet counts as not yet released; and a change to a lab, `content/domain/` or a part’s label, which changes the page’s PDF without changing its version.",
|
|
1406
|
+
"x-element": "changelog",
|
|
1407
|
+
"x-elements": [
|
|
1408
|
+
"changelog"
|
|
1409
|
+
],
|
|
1410
|
+
"x-enforcement": "partial",
|
|
1411
|
+
"x-doc": "docs/authoring/versioning.md#c5",
|
|
1412
|
+
"type": "object",
|
|
1413
|
+
"additionalProperties": false,
|
|
1414
|
+
"properties": {
|
|
1415
|
+
"enabled": {
|
|
1416
|
+
"title": "Enabled",
|
|
1417
|
+
"description": "Off: the check does not run, and the rule leaves the rules-in-effect page.",
|
|
1418
|
+
"type": "boolean",
|
|
1419
|
+
"default": true
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1143
1422
|
}
|
|
1144
1423
|
}
|
|
1145
1424
|
}
|
package/dist/rules/settings.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import './catalog.js';
|
|
2
2
|
import './course-rules.js';
|
|
3
|
-
export {
|
|
3
|
+
export { h as ConfigDiagnostic, n as CourseRulesConfig, M as ManifestRules, o as ResolvedRules, p as RuleSettingsInput, q as catalogIds, r as disabledCodes, s as dropDisabled, t as partPageLimits, u as resolveRules, v as rulesJsonSchema, w as rulesSnapshot } from '../course-config-BLtIdkei.js';
|
|
@@ -22,6 +22,12 @@ interface PreferenceStore {
|
|
|
22
22
|
* fits; a caller without it writes an empty value instead.
|
|
23
23
|
*/
|
|
24
24
|
remove?(key: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Every key the store holds. Optional like `remove`; the reading-memory
|
|
27
|
+
* question (`reading-memory.ts`) uses it to forget a course's per-page
|
|
28
|
+
* entries, whose names it cannot list otherwise.
|
|
29
|
+
*/
|
|
30
|
+
keys?(): string[];
|
|
25
31
|
}
|
|
26
32
|
/**
|
|
27
33
|
* A `localStorage`-backed store. Every call is wrapped: storage can be absent
|
|
@@ -18,6 +18,14 @@ function createBrowserPreferenceStore() {
|
|
|
18
18
|
window.localStorage.removeItem(key);
|
|
19
19
|
} catch {
|
|
20
20
|
}
|
|
21
|
+
},
|
|
22
|
+
keys() {
|
|
23
|
+
try {
|
|
24
|
+
const storage = window.localStorage;
|
|
25
|
+
return Array.from({ length: storage.length }, (_, index) => storage.key(index) ?? "").filter(Boolean);
|
|
26
|
+
} catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
21
29
|
}
|
|
22
30
|
};
|
|
23
31
|
}
|
|
@@ -41,6 +49,14 @@ function createSessionPreferenceStore() {
|
|
|
41
49
|
window.sessionStorage.removeItem(key);
|
|
42
50
|
} catch {
|
|
43
51
|
}
|
|
52
|
+
},
|
|
53
|
+
keys() {
|
|
54
|
+
try {
|
|
55
|
+
const storage = window.sessionStorage;
|
|
56
|
+
return Array.from({ length: storage.length }, (_, index) => storage.key(index) ?? "").filter(Boolean);
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
44
60
|
}
|
|
45
61
|
};
|
|
46
62
|
}
|
|
@@ -56,7 +72,8 @@ function createMemoryPreferenceStore() {
|
|
|
56
72
|
},
|
|
57
73
|
remove: (key) => {
|
|
58
74
|
map.delete(key);
|
|
59
|
-
}
|
|
75
|
+
},
|
|
76
|
+
keys: () => [...map.keys()]
|
|
60
77
|
};
|
|
61
78
|
}
|
|
62
79
|
export {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a reader's decks remember (`docs/authoring/deck.md`, "Present mode and
|
|
3
|
+
* the study page"): for each deck, the frame and the step Present mode last
|
|
4
|
+
* stood on, and every frame it showed them, as it was. A frame's content is
|
|
5
|
+
* named by its id (`ManifestDeckFrame.id`, 12 hex digits of a hash over what
|
|
6
|
+
* it shows), so a frame that changed since the reader was shown it is told
|
|
7
|
+
* from one they were never shown, as `page-marks.ts` tells pages apart.
|
|
8
|
+
*
|
|
9
|
+
* One small JSON map per course,
|
|
10
|
+
* `{ "v": 2, "decks": { slug: { at, step, seen } } }`, kept through the
|
|
11
|
+
* `PreferenceStore` under `deckPositionsKey(base)`. It is reading memory
|
|
12
|
+
* (`reading-memory.ts`): with the reader's yes it is kept
|
|
13
|
+
* across visits; before an answer it is kept for the tab, as kept cards are;
|
|
14
|
+
* after a no, only where each deck stopped is, for the tab. Version 1,
|
|
15
|
+
* `{ slug: number }`, held the stopping place alone, and reads as version 2
|
|
16
|
+
* with no frame shown.
|
|
17
|
+
*
|
|
18
|
+
* Pure: `components/deck/deck-controller.ts` does the DOM and the storage on
|
|
19
|
+
* a deck's page, the sidebar's script (`LayoutSidebar.astro`) its two
|
|
20
|
+
* actions, which cover every deck, `reading-memory.ts` what the reader's
|
|
21
|
+
* answer does to the tab's record, and `tests/unit/deck-memory.test.ts`
|
|
22
|
+
* checks this in Node.
|
|
23
|
+
*/
|
|
24
|
+
/** A frame as the page knows it: its number in the deck, and its content's id. */
|
|
25
|
+
interface DeckFrameId {
|
|
26
|
+
readonly number: number;
|
|
27
|
+
readonly id: string;
|
|
28
|
+
}
|
|
29
|
+
/** A frame as the study page knows it, with the steps it has (`data-steps`). */
|
|
30
|
+
interface DeckFrameSteps extends DeckFrameId {
|
|
31
|
+
readonly steps: number;
|
|
32
|
+
}
|
|
33
|
+
/** A deck as the sidebar's two actions need it. */
|
|
34
|
+
interface DeckFrames {
|
|
35
|
+
/** Its route, as `.deck[data-deck]` names it: `motion/position-and-coordinates/slides`. */
|
|
36
|
+
readonly slug: string;
|
|
37
|
+
readonly frames: readonly DeckFrameId[];
|
|
38
|
+
}
|
|
39
|
+
/** What one deck remembers. */
|
|
40
|
+
interface DeckRecord {
|
|
41
|
+
/** The frame Present mode last stood on, by number. */
|
|
42
|
+
readonly at?: number;
|
|
43
|
+
/** The step of that frame it stood on: none in a record kept before steps were. */
|
|
44
|
+
readonly step?: number;
|
|
45
|
+
/** The frames Present mode showed, by number: the id each had then. */
|
|
46
|
+
readonly seen: ReadonlyMap<number, string>;
|
|
47
|
+
}
|
|
48
|
+
/** Where "Continue" presents from (`resumeAt`). */
|
|
49
|
+
interface Resume {
|
|
50
|
+
/** The frame, by its number now; the first frame for "Present again". */
|
|
51
|
+
readonly number: number;
|
|
52
|
+
/** The reader was shown every step of the deck's last frame: "Present again". */
|
|
53
|
+
readonly again: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** Every deck's record, by its slug. */
|
|
56
|
+
type DeckMemory = ReadonlyMap<string, DeckRecord>;
|
|
57
|
+
/** A frame's mark on the study page: not shown in Present mode yet, or changed since it was. */
|
|
58
|
+
type FrameMark = 'unseen' | 'changed';
|
|
59
|
+
/**
|
|
60
|
+
* Told on a page after deck memory was written there, so the deck's page and
|
|
61
|
+
* the sidebar read it again; another tab hears the `storage` event.
|
|
62
|
+
*/
|
|
63
|
+
declare const DECK_MEMORY_EVENT = "explico:deck-memory";
|
|
64
|
+
/**
|
|
65
|
+
* Every deck's record, from the stored text. Version 1 becomes version 2,
|
|
66
|
+
* each deck's place kept and no frame shown. Anything else, and any entry
|
|
67
|
+
* that is not a frame number or a frame's id, is dropped, never trusted.
|
|
68
|
+
*/
|
|
69
|
+
declare function decodeDeckMemory(raw: string | null): DeckMemory;
|
|
70
|
+
/** The stored text: decks sorted by slug, frames by number, so the same state is always the same string. */
|
|
71
|
+
declare function encodeDeckMemory(memory: DeckMemory): string;
|
|
72
|
+
/**
|
|
73
|
+
* The record after Present mode stood on step `step` of frame `number` of
|
|
74
|
+
* `slug`, while the frames shown are not kept: the place alone, the frames
|
|
75
|
+
* shown left as they were.
|
|
76
|
+
*/
|
|
77
|
+
declare function withPosition(memory: DeckMemory, slug: string, number: number, step: number): Map<string, DeckRecord>;
|
|
78
|
+
/**
|
|
79
|
+
* The record after Present mode showed `frame` of `slug` at step `step`, in
|
|
80
|
+
* the room's window or the presenter's (D8): the reader stands there, and has
|
|
81
|
+
* seen the frame as it is now, whichever of its steps they saw.
|
|
82
|
+
*/
|
|
83
|
+
declare function withShown(memory: DeckMemory, slug: string, frame: DeckFrameId, step: number): Map<string, DeckRecord>;
|
|
84
|
+
/** "Mark all as seen" on a deck's page: every frame of `slug` seen as it is now. Where it stopped stays. */
|
|
85
|
+
declare function withAllSeen(memory: DeckMemory, slug: string, frames: readonly DeckFrameId[]): Map<string, DeckRecord>;
|
|
86
|
+
/** "Mark all as unseen" on a deck's page: no frame of `slug` seen. Where it stopped stays. */
|
|
87
|
+
declare function withNoneSeen(memory: DeckMemory, slug: string): Map<string, DeckRecord>;
|
|
88
|
+
/**
|
|
89
|
+
* Two records as one, for the reader's yes (`reading-memory.ts`): what the
|
|
90
|
+
* tab kept before it (`newer`) joins what the browser kept from an earlier
|
|
91
|
+
* visit (`older`). Each deck stops where `newer` says, when it says; a frame
|
|
92
|
+
* shown in both is as `newer` saw it.
|
|
93
|
+
*/
|
|
94
|
+
declare function mergeDeckMemory(older: DeckMemory, newer: DeckMemory): Map<string, DeckRecord>;
|
|
95
|
+
/** The sidebar's "Mark all as seen" (D9): every frame of every deck seen as it is now. */
|
|
96
|
+
declare function withEveryDeckSeen(memory: DeckMemory, decks: readonly DeckFrames[]): Map<string, DeckRecord>;
|
|
97
|
+
/** The sidebar's "Mark all as unseen" (D9): no frame of any deck seen. Where each stopped stays. */
|
|
98
|
+
declare function withEveryDeckUnseen(memory: DeckMemory): Map<string, DeckRecord>;
|
|
99
|
+
/**
|
|
100
|
+
* A frame's mark for a reader whose record of its deck is `record`: none
|
|
101
|
+
* when they were shown it as it is now, whatever its number was then (a
|
|
102
|
+
* frame added before it moves it, and it is still the frame they saw);
|
|
103
|
+
* `changed` when its place showed them something else; else `unseen`.
|
|
104
|
+
*/
|
|
105
|
+
declare function frameMark(frame: DeckFrameId, record: DeckRecord | undefined): FrameMark | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Where "Continue at slide N" presents from (D7): the frame the reader
|
|
108
|
+
* stopped at, unless they were shown its every step, then the frame after it
|
|
109
|
+
* — or, after the last frame, "Present again" from the first. The frame is
|
|
110
|
+
* followed to its number now when frames were added or taken out before it,
|
|
111
|
+
* by the id it had. None when nothing is remembered or the deck no longer
|
|
112
|
+
* has that frame. A record kept before steps were counts as stopped partway.
|
|
113
|
+
*/
|
|
114
|
+
declare function resumeAt(record: DeckRecord | undefined, frames: readonly DeckFrameSteps[]): Resume | undefined;
|
|
115
|
+
|
|
116
|
+
export { DECK_MEMORY_EVENT, type DeckFrameId, type DeckFrameSteps, type DeckFrames, type DeckMemory, type DeckRecord, type FrameMark, type Resume, decodeDeckMemory, encodeDeckMemory, frameMark, mergeDeckMemory, resumeAt, withAllSeen, withEveryDeckSeen, withEveryDeckUnseen, withNoneSeen, withPosition, withShown };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const DECK_MEMORY_EVENT = "explico:deck-memory";
|
|
2
|
+
const VERSION = 2;
|
|
3
|
+
const ID = /^[0-9a-f]{12}$/u;
|
|
4
|
+
const NUMBER = /^[1-9][0-9]*$/u;
|
|
5
|
+
function isFrameNumber(value) {
|
|
6
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
|
|
7
|
+
}
|
|
8
|
+
function place(at, step) {
|
|
9
|
+
if (at === void 0) return {};
|
|
10
|
+
return step === void 0 ? { at } : { at, step };
|
|
11
|
+
}
|
|
12
|
+
function byText(a, b) {
|
|
13
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
14
|
+
}
|
|
15
|
+
function readRecord(value) {
|
|
16
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
17
|
+
const { at, step, seen } = value;
|
|
18
|
+
const frames = /* @__PURE__ */ new Map();
|
|
19
|
+
if (seen && typeof seen === "object" && !Array.isArray(seen)) {
|
|
20
|
+
for (const [number, id] of Object.entries(seen)) {
|
|
21
|
+
if (NUMBER.test(number) && isFrameNumber(Number(number)) && typeof id === "string" && ID.test(id)) {
|
|
22
|
+
frames.set(Number(number), id);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!isFrameNumber(at) && frames.size === 0) return void 0;
|
|
27
|
+
return { ...isFrameNumber(at) ? place(at, isFrameNumber(step) ? step : void 0) : {}, seen: frames };
|
|
28
|
+
}
|
|
29
|
+
function decodeDeckMemory(raw) {
|
|
30
|
+
const memory = /* @__PURE__ */ new Map();
|
|
31
|
+
if (!raw) return memory;
|
|
32
|
+
let parsed;
|
|
33
|
+
try {
|
|
34
|
+
parsed = JSON.parse(raw);
|
|
35
|
+
} catch {
|
|
36
|
+
return memory;
|
|
37
|
+
}
|
|
38
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return memory;
|
|
39
|
+
const stored = parsed;
|
|
40
|
+
if (!("v" in stored)) {
|
|
41
|
+
for (const [slug, at] of Object.entries(stored)) {
|
|
42
|
+
if (slug.length > 0 && isFrameNumber(at)) memory.set(slug, { at, seen: /* @__PURE__ */ new Map() });
|
|
43
|
+
}
|
|
44
|
+
return memory;
|
|
45
|
+
}
|
|
46
|
+
const { v, decks } = stored;
|
|
47
|
+
if (v !== VERSION || !decks || typeof decks !== "object" || Array.isArray(decks)) return memory;
|
|
48
|
+
for (const [slug, value] of Object.entries(decks)) {
|
|
49
|
+
const record = slug.length > 0 ? readRecord(value) : void 0;
|
|
50
|
+
if (record) memory.set(slug, record);
|
|
51
|
+
}
|
|
52
|
+
return memory;
|
|
53
|
+
}
|
|
54
|
+
function encodeDeckMemory(memory) {
|
|
55
|
+
const decks = [...memory].sort(([a], [b]) => byText(a, b)).map(([slug, record]) => [
|
|
56
|
+
slug,
|
|
57
|
+
{
|
|
58
|
+
...place(record.at, record.step),
|
|
59
|
+
seen: Object.fromEntries([...record.seen].sort(([a], [b]) => a - b).map(([number, id]) => [String(number), id]))
|
|
60
|
+
}
|
|
61
|
+
]);
|
|
62
|
+
return JSON.stringify({ v: VERSION, decks: Object.fromEntries(decks) });
|
|
63
|
+
}
|
|
64
|
+
function withRecord(memory, slug, record) {
|
|
65
|
+
const next = new Map(memory);
|
|
66
|
+
if (record && (record.at !== void 0 || record.seen.size > 0)) next.set(slug, record);
|
|
67
|
+
else next.delete(slug);
|
|
68
|
+
return next;
|
|
69
|
+
}
|
|
70
|
+
function withPosition(memory, slug, number, step) {
|
|
71
|
+
return withRecord(memory, slug, { ...place(number, step), seen: memory.get(slug)?.seen ?? /* @__PURE__ */ new Map() });
|
|
72
|
+
}
|
|
73
|
+
function withShown(memory, slug, frame, step) {
|
|
74
|
+
const seen = new Map(memory.get(slug)?.seen);
|
|
75
|
+
seen.set(frame.number, frame.id);
|
|
76
|
+
return withRecord(memory, slug, { ...place(frame.number, step), seen });
|
|
77
|
+
}
|
|
78
|
+
function withAllSeen(memory, slug, frames) {
|
|
79
|
+
const record = memory.get(slug);
|
|
80
|
+
return withRecord(memory, slug, {
|
|
81
|
+
...place(record?.at, record?.step),
|
|
82
|
+
seen: new Map(frames.map((frame) => [frame.number, frame.id]))
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function withNoneSeen(memory, slug) {
|
|
86
|
+
const record = memory.get(slug);
|
|
87
|
+
return withRecord(memory, slug, record?.at === void 0 ? void 0 : { ...place(record.at, record.step), seen: /* @__PURE__ */ new Map() });
|
|
88
|
+
}
|
|
89
|
+
function mergeDeckMemory(older, newer) {
|
|
90
|
+
const merged = new Map(older);
|
|
91
|
+
for (const [slug, record] of newer) {
|
|
92
|
+
const before = older.get(slug);
|
|
93
|
+
const at = record.at ?? before?.at;
|
|
94
|
+
merged.set(slug, {
|
|
95
|
+
...place(at, record.at === void 0 ? before?.step : record.step),
|
|
96
|
+
seen: new Map([...before?.seen ?? [], ...record.seen])
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return merged;
|
|
100
|
+
}
|
|
101
|
+
function withEveryDeckSeen(memory, decks) {
|
|
102
|
+
let next = new Map(memory);
|
|
103
|
+
for (const deck of decks) next = withAllSeen(next, deck.slug, deck.frames);
|
|
104
|
+
return next;
|
|
105
|
+
}
|
|
106
|
+
function withEveryDeckUnseen(memory) {
|
|
107
|
+
let next = new Map(memory);
|
|
108
|
+
for (const slug of memory.keys()) next = withNoneSeen(next, slug);
|
|
109
|
+
return next;
|
|
110
|
+
}
|
|
111
|
+
function frameMark(frame, record) {
|
|
112
|
+
const seen = record?.seen;
|
|
113
|
+
if (!seen || seen.size === 0) return "unseen";
|
|
114
|
+
if (seen.get(frame.number) === frame.id) return void 0;
|
|
115
|
+
for (const id of seen.values()) if (id === frame.id) return void 0;
|
|
116
|
+
return seen.has(frame.number) ? "changed" : "unseen";
|
|
117
|
+
}
|
|
118
|
+
function resumeAt(record, frames) {
|
|
119
|
+
const at = record?.at;
|
|
120
|
+
if (at === void 0) return void 0;
|
|
121
|
+
const id = record?.seen.get(at);
|
|
122
|
+
const there = frames.find((frame) => frame.number === at);
|
|
123
|
+
const moved = id === void 0 || there?.id === id ? void 0 : frames.find((frame) => frame.id === id);
|
|
124
|
+
const stopped = moved ?? there;
|
|
125
|
+
if (!stopped) return void 0;
|
|
126
|
+
if (record?.step === void 0 || record.step < stopped.steps) return { number: stopped.number, again: false };
|
|
127
|
+
const after = frames[frames.indexOf(stopped) + 1];
|
|
128
|
+
return after ? { number: after.number, again: false } : { number: frames[0].number, again: true };
|
|
129
|
+
}
|
|
130
|
+
export {
|
|
131
|
+
DECK_MEMORY_EVENT,
|
|
132
|
+
decodeDeckMemory,
|
|
133
|
+
encodeDeckMemory,
|
|
134
|
+
frameMark,
|
|
135
|
+
mergeDeckMemory,
|
|
136
|
+
resumeAt,
|
|
137
|
+
withAllSeen,
|
|
138
|
+
withEveryDeckSeen,
|
|
139
|
+
withEveryDeckUnseen,
|
|
140
|
+
withNoneSeen,
|
|
141
|
+
withPosition,
|
|
142
|
+
withShown
|
|
143
|
+
};
|