@lernapps/app-templates 0.0.1 → 0.1.1
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/LICENSE +22 -0
- package/README.md +195 -2
- package/dist/appname-Bh23cUuz.mjs +12 -0
- package/dist/assessment-Dy359O1O.mjs +1696 -0
- package/dist/block-BK_ohsH1.mjs +82 -0
- package/dist/blocks-CxtCPAa5.mjs +149 -0
- package/dist/blocks.mjs +4 -0
- package/dist/check-CteIFN96.mjs +254 -0
- package/dist/content-DO6oEJxj.mjs +140 -0
- package/dist/contract-PONpxJtd.mjs +52 -0
- package/dist/e2e-CU0n_unV.mjs +89 -0
- package/dist/engine-CArxqizW.mjs +136 -0
- package/dist/explainer-e2e.mjs +1311 -0
- package/dist/explainer-islands.mjs +197 -0
- package/dist/explainer-plugin.mjs +2132 -0
- package/dist/explainer.mjs +1246 -0
- package/dist/html-mffkHGHh.mjs +89 -0
- package/dist/image-CspJVfyQ.mjs +21 -0
- package/dist/interactive-e2e.mjs +140 -0
- package/dist/interactive-plugin.mjs +242 -0
- package/dist/interactive.mjs +75 -0
- package/dist/load-RosvaPZf.mjs +16976 -0
- package/dist/needs-BzEahJ6X.mjs +97 -0
- package/dist/pages-9RaaomoO.mjs +81 -0
- package/dist/questions-e2e.mjs +1 -0
- package/dist/questions-engine.mjs +3 -0
- package/dist/questions.mjs +6 -0
- package/dist/quiz-DnW-xtCh.mjs +70 -0
- package/dist/quiz-e2e.mjs +174 -0
- package/dist/quiz-plugin.mjs +266 -0
- package/dist/quiz.mjs +246 -0
- package/dist/render-D5kwkNt1.mjs +507 -0
- package/dist/render-DqHOJyHK.mjs +146 -0
- package/dist/render-GS1Htlu8.mjs +545 -0
- package/dist/result-D_mmCVwN.mjs +180 -0
- package/dist/tasks-DADUYy52.mjs +74 -0
- package/dist/validate-BDwL7Su3.mjs +1076 -0
- package/dist/validate-Bxy9NfB8.mjs +146 -0
- package/dist/vue-DO1m6q1R.mjs +40 -0
- package/dist/vue-code-BkJjW_I_.mjs +320 -0
- package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
- package/docs/arc42/02-constraints.arc42.md +228 -0
- package/docs/arc42/03-system-context.arc42.md +118 -0
- package/docs/arc42/04-solution-strategy.arc42.md +47 -0
- package/docs/arc42/05-building-blocks.arc42.md +307 -0
- package/docs/arc42/06-runtime-view.arc42.md +98 -0
- package/docs/arc42/07-deployment-view.arc42.md +160 -0
- package/docs/arc42/08-concepts.arc42.md +123 -0
- package/docs/arc42/09-decisions.arc42.md +246 -0
- package/docs/arc42/10-quality-requirements.arc42.md +155 -0
- package/docs/arc42/11-risks.arc42.md +113 -0
- package/docs/arc42/12-glossary.arc42.md +162 -0
- package/docs/arc42/architecture-evidence.md +395 -0
- package/explainer/.arc42ignore +3 -0
- package/explainer/README.md +54 -0
- package/explainer/_gitignore +5 -0
- package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
- package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
- package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
- package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
- package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
- package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
- package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
- package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
- package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
- package/explainer/e2e/explainer.e2e.ts +3 -0
- package/explainer/index.html +11 -0
- package/explainer/package.json +18 -0
- package/explainer/playwright.config.ts +1 -0
- package/explainer/src/app.yaml +20 -0
- package/explainer/src/components/ProzentFeld.test.ts +30 -0
- package/explainer/src/components/ProzentFeld.ts +121 -0
- package/explainer/src/components/ProzentFeld.vue +84 -0
- package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
- package/explainer/src/main.ts +4 -0
- package/explainer/src/prozent/chapter.yaml +18 -0
- package/explainer/src/prozent/grundwert.yaml +115 -0
- package/explainer/src/prozent/prozentsatz.yaml +99 -0
- package/explainer/src/prozent/prozentwert.yaml +119 -0
- package/explainer/tsconfig.json +1 -0
- package/explainer/vite.config.ts +4 -0
- package/interactive/.arc42ignore +5 -0
- package/interactive/README.md +28 -0
- package/interactive/_gitignore +4 -0
- package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
- package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
- package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
- package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
- package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
- package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
- package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
- package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
- package/interactive/e2e/interactive.e2e.ts +3 -0
- package/interactive/index.html +11 -0
- package/interactive/package.json +18 -0
- package/interactive/playwright.config.ts +1 -0
- package/interactive/src/app.yaml +28 -0
- package/interactive/src/core/index.ts +101 -0
- package/interactive/src/data/lessons.json +4 -0
- package/interactive/src/env.d.ts +6 -0
- package/interactive/src/main.ts +6 -0
- package/interactive/src/messages/de.json +12 -0
- package/interactive/src/playthroughs/grundreihe.yaml +33 -0
- package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
- package/interactive/src/ui/App.vue +85 -0
- package/interactive/tsconfig.json +1 -0
- package/interactive/vite.config.ts +4 -0
- package/package.json +143 -4
- package/quiz/README.md +31 -0
- package/quiz/_gitignore +5 -0
- package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
- package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
- package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
- package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
- package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
- package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
- package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
- package/quiz/e2e/quiz.e2e.ts +3 -0
- package/quiz/index.html +11 -0
- package/quiz/package.json +18 -0
- package/quiz/playwright.config.ts +1 -0
- package/quiz/src/images/berge-ordnen.jpg +0 -0
- package/quiz/src/images/everest-hoehe.jpg +0 -0
- package/quiz/src/images/galapagos.jpg +0 -0
- package/quiz/src/images/grand-canyon.jpg +0 -0
- package/quiz/src/images/totes-meer.jpg +0 -0
- package/quiz/src/images/uluru.jpg +0 -0
- package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
- package/quiz/src/main.ts +4 -0
- package/quiz/src/quiz.json +312 -0
- package/quiz/tsconfig.json +1 -0
- package/quiz/vite.config.ts +4 -0
- package/runtime/explainer/assessment-client.ts +478 -0
- package/runtime/explainer/assessment-page.ts +448 -0
- package/runtime/explainer/assessment.ts +393 -0
- package/runtime/explainer/check-page.ts +520 -0
- package/runtime/explainer/components/exercise.ts +409 -0
- package/runtime/explainer/components/props.ts +230 -0
- package/runtime/explainer/components/read.ts +428 -0
- package/runtime/explainer/content.ts +277 -0
- package/runtime/explainer/e2e.ts +1488 -0
- package/runtime/explainer/exercises.ts +326 -0
- package/runtime/explainer/explainer.css +1283 -0
- package/runtime/explainer/explainer.ts +838 -0
- package/runtime/explainer/explainer.v1.schema.json +1165 -0
- package/runtime/explainer/expression.ts +407 -0
- package/runtime/explainer/fraction.ts +107 -0
- package/runtime/explainer/generated/comparator.ts +31 -0
- package/runtime/explainer/generated/question.ts +165 -0
- package/runtime/explainer/generated/soundness.ts +280 -0
- package/runtime/explainer/generated/texts.ts +257 -0
- package/runtime/explainer/generated/types.ts +103 -0
- package/runtime/explainer/generated/values.ts +136 -0
- package/runtime/explainer/islands.ts +281 -0
- package/runtime/explainer/load.ts +457 -0
- package/runtime/explainer/messages/de.json +200 -0
- package/runtime/explainer/messages/en.json +200 -0
- package/runtime/explainer/messages.ts +13 -0
- package/runtime/explainer/needs.ts +122 -0
- package/runtime/explainer/open-task.ts +235 -0
- package/runtime/explainer/outline.ts +306 -0
- package/runtime/explainer/plugin.ts +488 -0
- package/runtime/explainer/position.ts +62 -0
- package/runtime/explainer/prompt.ts +75 -0
- package/runtime/explainer/render.ts +686 -0
- package/runtime/explainer/result.ts +238 -0
- package/runtime/explainer/routes.ts +119 -0
- package/runtime/explainer/schema.ts +140 -0
- package/runtime/explainer/scope.ts +87 -0
- package/runtime/explainer/stuck.ts +57 -0
- package/runtime/explainer/tasks.ts +109 -0
- package/runtime/explainer/tutor.ts +469 -0
- package/runtime/explainer/tutorpage.ts +669 -0
- package/runtime/explainer/video.ts +123 -0
- package/runtime/interactive/contract.ts +121 -0
- package/runtime/interactive/e2e.ts +190 -0
- package/runtime/interactive/interactive.css +82 -0
- package/runtime/interactive/interactive.ts +115 -0
- package/runtime/interactive/interactive.v1.schema.json +146 -0
- package/runtime/interactive/load.ts +188 -0
- package/runtime/interactive/messages/de.json +14 -0
- package/runtime/interactive/messages/en.json +14 -0
- package/runtime/interactive/messages.ts +11 -0
- package/runtime/interactive/playthrough.v1.schema.json +143 -0
- package/runtime/interactive/plugin.ts +266 -0
- package/runtime/interactive/render.ts +126 -0
- package/runtime/quiz/e2e.ts +233 -0
- package/runtime/quiz/engine.ts +242 -0
- package/runtime/quiz/messages/de.json +23 -0
- package/runtime/quiz/messages/en.json +23 -0
- package/runtime/quiz/plugin.ts +150 -0
- package/runtime/quiz/quiz.css +154 -0
- package/runtime/quiz/quiz.ts +56 -0
- package/runtime/quiz/quiz.v1.schema.json +72 -0
- package/runtime/quiz/render.ts +173 -0
- package/runtime/quiz/validate.ts +108 -0
- package/runtime/shared/appname.ts +16 -0
- package/runtime/shared/blocks/block.ts +162 -0
- package/runtime/shared/blocks/blocks.css +190 -0
- package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
- package/runtime/shared/blocks/code.ts +26 -0
- package/runtime/shared/blocks/figures.ts +49 -0
- package/runtime/shared/blocks/image.ts +25 -0
- package/runtime/shared/blocks/index.ts +13 -0
- package/runtime/shared/blocks/messages/de.json +4 -0
- package/runtime/shared/blocks/messages/en.json +4 -0
- package/runtime/shared/blocks/render.ts +134 -0
- package/runtime/shared/blocks/validate.ts +165 -0
- package/runtime/shared/content.ts +197 -0
- package/runtime/shared/examples.ts +20 -0
- package/runtime/shared/html.ts +10 -0
- package/runtime/shared/languages.ts +94 -0
- package/runtime/shared/page.css +101 -0
- package/runtime/shared/pages.ts +114 -0
- package/runtime/shared/questions/e2e.ts +115 -0
- package/runtime/shared/questions/engine.ts +209 -0
- package/runtime/shared/questions/index.ts +39 -0
- package/runtime/shared/questions/messages/de.json +26 -0
- package/runtime/shared/questions/messages/en.json +26 -0
- package/runtime/shared/questions/question.ts +433 -0
- package/runtime/shared/questions/question.v1.schema.json +346 -0
- package/runtime/shared/questions/questions.css +192 -0
- package/runtime/shared/questions/render.ts +255 -0
- package/runtime/shared/questions/validate.ts +518 -0
- package/runtime/shared/schema.ts +44 -0
- package/runtime/shared/text/check.ts +68 -0
- package/runtime/shared/text/formula.ts +69 -0
- package/runtime/shared/text/markdown.ts +185 -0
- package/runtime/shared/text/speech.ts +39 -0
- package/runtime/shared/text/text.v1.schema.json +34 -0
- package/runtime/shared/vue-code.ts +395 -0
- package/runtime/shared/vue.ts +38 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// What the pages of an explainer must show, from its content in src/ (not from the rendered pages), for its end-to-end
|
|
2
|
+
// tests: per language, the content pages in order with their headings by nesting (page h1, section h2, subsection h3,
|
|
3
|
+
// a box one level below the heading it is under), their sections with their anchors, the number of formulas and the
|
|
4
|
+
// name of every figure, its videos, its exercises with what each must accept, and its components with their nojs text; and the
|
|
5
|
+
// other pages (start, chapters, glossary, self-assessments) with their titles.
|
|
6
|
+
import { questionIn, type Question } from "../shared/questions/question.ts";
|
|
7
|
+
import { answerText } from "../shared/questions/render.ts";
|
|
8
|
+
import { inLanguage, timelineEvents, type Block, type ComponentExample, type Site, type Text } from "./content.ts";
|
|
9
|
+
import { dataOf, renderExercise, templatesOf, workedTasks } from "./exercises.ts";
|
|
10
|
+
import { kindOf } from "./generated/comparator.ts";
|
|
11
|
+
import { renderWithFormulas } from "../shared/text/markdown.ts";
|
|
12
|
+
import { plainText } from "./generated/texts.ts";
|
|
13
|
+
import { type Data, type Generated, type Templates } from "./generated/types.ts";
|
|
14
|
+
import { loadSite } from "./load.ts";
|
|
15
|
+
import { inspect, renderMarkdown } from "../shared/text/markdown.ts";
|
|
16
|
+
import { routes } from "./routes.ts";
|
|
17
|
+
import { assessments, titleOf } from "./assessment.ts";
|
|
18
|
+
|
|
19
|
+
export interface PageOutline {
|
|
20
|
+
/** What page it is: the start page, a chapter, a content page, the glossary, a self-assessment. */
|
|
21
|
+
kind: "start" | "chapter" | "page" | "glossary" | "assessment";
|
|
22
|
+
/** Where the page is, from the app's root: "prozent/prozentwert/", "en/prozent/prozentwert/". */
|
|
23
|
+
url: string;
|
|
24
|
+
lang: string;
|
|
25
|
+
title: string;
|
|
26
|
+
headings: { level: number; text: string }[];
|
|
27
|
+
sections: { id: string; title: string }[];
|
|
28
|
+
formulas: number;
|
|
29
|
+
figures: string[];
|
|
30
|
+
/** The videos, in order: each shows its title, channel and link without JavaScript, its player only after a click. */
|
|
31
|
+
videos: { youtube: string; title: string; channel: string }[];
|
|
32
|
+
exercises: ExerciseOutline[];
|
|
33
|
+
/** The vue-component blocks, in order. */
|
|
34
|
+
components: ComponentOutline[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A vue-component block of a page, in the page's language. */
|
|
38
|
+
export interface ComponentOutline {
|
|
39
|
+
name: string;
|
|
40
|
+
/** Its anchor, for an exercise component. */
|
|
41
|
+
id?: string;
|
|
42
|
+
/** Its own nojs text, as plain text; empty when it has none (an exercise component's no-JS task comes from describe). */
|
|
43
|
+
nojs: string;
|
|
44
|
+
/** Whether it emits answer, an exercise. */
|
|
45
|
+
exercise: boolean;
|
|
46
|
+
/** Whether it keeps its nojs text, folded as a text description, once it runs. */
|
|
47
|
+
caption: boolean;
|
|
48
|
+
/** For an exercise component: its block's first accepted and first rejected example, for "Prüfen". */
|
|
49
|
+
examples?: { accepted?: ComponentExample; rejected?: ComponentExample };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A learner text of a question as the page shows it, as text: its formulas $…$ rendered (a formula has no space the
|
|
54
|
+
* tests could rely on in a browser's text, see squash in e2e.ts), the rest as written.
|
|
55
|
+
*/
|
|
56
|
+
export const shownText = (text: string): string => plainText(renderWithFormulas(text));
|
|
57
|
+
|
|
58
|
+
/** An exercise of a page, in the page's language: what it shows and what it accepts. */
|
|
59
|
+
export type ExerciseOutline =
|
|
60
|
+
| {
|
|
61
|
+
kind: "question";
|
|
62
|
+
id: string;
|
|
63
|
+
/** The exercise's type, one per kind of controls: the question type. */
|
|
64
|
+
type: string;
|
|
65
|
+
question: Question;
|
|
66
|
+
/** The right answer as its "Lösung" states it: each right option, or the answer. */
|
|
67
|
+
answers: string[];
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
kind: "generated";
|
|
71
|
+
id: string;
|
|
72
|
+
/** generated, with the comparator's kind: generated:number, generated:order, … */
|
|
73
|
+
type: string;
|
|
74
|
+
spec: Generated;
|
|
75
|
+
data: Data;
|
|
76
|
+
templates: Templates;
|
|
77
|
+
/** The worked tasks without JavaScript: the task's text and the right answer as its "Lösung" states it. */
|
|
78
|
+
worked: { task: string; answer: string }[];
|
|
79
|
+
}
|
|
80
|
+
| {
|
|
81
|
+
kind: "open";
|
|
82
|
+
id: string;
|
|
83
|
+
type: "open-task";
|
|
84
|
+
/** The task as plain text. */
|
|
85
|
+
task: string;
|
|
86
|
+
/** How the learner may answer. */
|
|
87
|
+
answer: readonly ("text" | "photo")[];
|
|
88
|
+
/** The points of a good answer, as plain text, and whether each has a source to read up. */
|
|
89
|
+
points: { text: string; source: boolean }[];
|
|
90
|
+
/** The model answer as plain text, in the pieces between its formulas (which a reader reads otherwise). */
|
|
91
|
+
solution: string[];
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** A self-assessment (assessment.ts), in German: where it is offered, and its exercises by the content pages' outline. */
|
|
95
|
+
export interface AssessmentOutline {
|
|
96
|
+
/** Its page and the page that offers it, from the app's root: "einschaetzung/" and "", "formen/einschaetzung/" and "formen/". */
|
|
97
|
+
url: string;
|
|
98
|
+
offer: string;
|
|
99
|
+
/** The key its last result is kept under on the device, without the app's prefix. */
|
|
100
|
+
key: string;
|
|
101
|
+
steps: number;
|
|
102
|
+
/** Its exercises in order: the key, its page of the self-assessment, the content page and the exercise's id there. */
|
|
103
|
+
items: { key: string; step: number; page: string; id: string }[];
|
|
104
|
+
/** The content pages it says something about, in order, each with its title and how many of its exercises it asks. */
|
|
105
|
+
pages: { url: string; title: string; asked: number }[];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface Outline {
|
|
109
|
+
languages: readonly string[];
|
|
110
|
+
/** The content pages of each language, in the order of the lists. */
|
|
111
|
+
pages: Readonly<Record<string, PageOutline[]>>;
|
|
112
|
+
/** The start page, the chapter pages, the glossary and the self-assessments of each language. */
|
|
113
|
+
others: Readonly<Record<string, PageOutline[]>>;
|
|
114
|
+
/** The self-assessments, in German. */
|
|
115
|
+
assessments: AssessmentOutline[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** The headings, sections, formulas and figures of `blocks` in `lang`, under a heading of level `level`. */
|
|
119
|
+
function walk(
|
|
120
|
+
site: Site,
|
|
121
|
+
blocks: readonly Block[],
|
|
122
|
+
lang: string,
|
|
123
|
+
level: number,
|
|
124
|
+
anchor: string[],
|
|
125
|
+
into: PageOutline,
|
|
126
|
+
): void {
|
|
127
|
+
const text = (value: Text) => inLanguage(value, lang);
|
|
128
|
+
const formulas = (value: Text | undefined) => {
|
|
129
|
+
if (value !== undefined) into.formulas += inspect(text(value)).formulas.length;
|
|
130
|
+
};
|
|
131
|
+
for (const block of blocks) {
|
|
132
|
+
switch (block.type) {
|
|
133
|
+
case "section": {
|
|
134
|
+
const id = [...anchor, block.id].join("/");
|
|
135
|
+
into.headings.push({ level: level + 1, text: text(block.title) });
|
|
136
|
+
into.sections.push({ id, title: text(block.title) });
|
|
137
|
+
walk(site, block.blocks, lang, level + 1, [...anchor, block.id], into);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "example":
|
|
141
|
+
case "note":
|
|
142
|
+
into.headings.push({ level: level + 1, text: text(block.title) });
|
|
143
|
+
walk(site, block.blocks, lang, level + 1, anchor, into);
|
|
144
|
+
break;
|
|
145
|
+
case "text":
|
|
146
|
+
formulas(block.text);
|
|
147
|
+
break;
|
|
148
|
+
case "formula":
|
|
149
|
+
into.formulas += 1;
|
|
150
|
+
break;
|
|
151
|
+
case "figure":
|
|
152
|
+
into.figures.push(text(block.alt));
|
|
153
|
+
formulas(block.caption);
|
|
154
|
+
break;
|
|
155
|
+
case "labelled-figure":
|
|
156
|
+
into.figures.push(text(block.alt));
|
|
157
|
+
formulas(block.caption);
|
|
158
|
+
break;
|
|
159
|
+
case "table":
|
|
160
|
+
for (const cell of [...(block.header ?? []), ...block.rows.flat()]) formulas(cell);
|
|
161
|
+
break;
|
|
162
|
+
case "timeline":
|
|
163
|
+
for (const event of timelineEvents(site, block)) formulas(event.text);
|
|
164
|
+
break;
|
|
165
|
+
case "definition":
|
|
166
|
+
formulas(block.explanation);
|
|
167
|
+
break;
|
|
168
|
+
case "quote":
|
|
169
|
+
formulas(block.text);
|
|
170
|
+
break;
|
|
171
|
+
case "code":
|
|
172
|
+
break;
|
|
173
|
+
case "video":
|
|
174
|
+
into.videos.push({ youtube: block.youtube, title: block.title, channel: block.channel });
|
|
175
|
+
break;
|
|
176
|
+
case "vue-component": {
|
|
177
|
+
const use = site.components.find((candidate) => candidate.block === block);
|
|
178
|
+
const nojs = block.nojs === undefined ? "" : text(block.nojs);
|
|
179
|
+
into.formulas += inspect(nojs).formulas.length;
|
|
180
|
+
into.components.push({
|
|
181
|
+
name: block.component,
|
|
182
|
+
...(use?.id === undefined ? {} : { id: use.id }),
|
|
183
|
+
nojs: plainText(renderMarkdown(nojs, (href) => href)),
|
|
184
|
+
exercise: use?.component.exercise ?? false,
|
|
185
|
+
caption: use?.component.caption ?? false,
|
|
186
|
+
...(use?.component.exercise && block.examples !== undefined
|
|
187
|
+
? {
|
|
188
|
+
examples: {
|
|
189
|
+
...(block.examples.accepted?.[0] === undefined ? {} : { accepted: block.examples.accepted[0] }),
|
|
190
|
+
...(block.examples.rejected?.[0] === undefined ? {} : { rejected: block.examples.rejected[0] }),
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
: {}),
|
|
194
|
+
});
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case "generated": {
|
|
198
|
+
const data = dataOf(block, site.data);
|
|
199
|
+
const templates = templatesOf(block, [lang]);
|
|
200
|
+
const worked = workedTasks(block, data, templates, lang);
|
|
201
|
+
for (const item of worked) {
|
|
202
|
+
for (const html of [item.task, item.hint ?? "", ...item.steps])
|
|
203
|
+
into.formulas += html.split("<math").length - 1;
|
|
204
|
+
}
|
|
205
|
+
into.exercises.push({
|
|
206
|
+
kind: "generated",
|
|
207
|
+
id: block.id,
|
|
208
|
+
type: `generated:${kindOf(block.answer.compare).kind}`,
|
|
209
|
+
spec: block,
|
|
210
|
+
data,
|
|
211
|
+
templates,
|
|
212
|
+
worked: worked.map((item) => ({ task: plainText(item.task), answer: plainText(item.answer) })),
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "open-task": {
|
|
217
|
+
// the formulas of its task, hint and model answer, as the page renders them
|
|
218
|
+
const html = renderExercise(block, lang, site.data, (href) => href, { lang, href: (image) => image });
|
|
219
|
+
into.formulas += (html.split('<script type="application/json"')[0] ?? "").split("<math").length - 1;
|
|
220
|
+
into.exercises.push({
|
|
221
|
+
kind: "open",
|
|
222
|
+
id: block.id,
|
|
223
|
+
type: "open-task",
|
|
224
|
+
task: plainText(renderMarkdown(inLanguage(block.task, lang), (href) => href)),
|
|
225
|
+
answer: block.answer ?? ["text", "photo"],
|
|
226
|
+
points: block.points.map((point) => ({
|
|
227
|
+
text: inLanguage(point.text, lang),
|
|
228
|
+
source: point.source !== undefined,
|
|
229
|
+
})),
|
|
230
|
+
solution: inLanguage(block.solution, lang)
|
|
231
|
+
.split(/\$[^$]+\$/)
|
|
232
|
+
.map((piece) =>
|
|
233
|
+
plainText(renderMarkdown(piece, (href) => href))
|
|
234
|
+
.replace(/\s+/g, " ")
|
|
235
|
+
.trim(),
|
|
236
|
+
)
|
|
237
|
+
.filter((piece) => piece !== ""),
|
|
238
|
+
});
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
default: {
|
|
242
|
+
// the formulas in the texts of a question (question, options, background, explanation) are rendered, and the
|
|
243
|
+
// page shows some of them more than once: count what the renderer writes, not the texts
|
|
244
|
+
const html = renderExercise(block, lang, site.data, (href) => href, { lang, href: (image) => image });
|
|
245
|
+
into.formulas += (html.split('<script type="application/json"')[0] ?? "").split("<math").length - 1;
|
|
246
|
+
const question = questionIn(block, lang);
|
|
247
|
+
into.exercises.push({
|
|
248
|
+
kind: "question",
|
|
249
|
+
id: block.id,
|
|
250
|
+
type: block.type,
|
|
251
|
+
question,
|
|
252
|
+
answers:
|
|
253
|
+
question.type === "single-choice" || question.type === "multiple-choice"
|
|
254
|
+
? question.options.filter((option) => option.correct).map((option) => shownText(option.text))
|
|
255
|
+
: [plainText(answerText(question, lang))],
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** The outline of the explainer whose content is in `root`/src. */
|
|
263
|
+
export function outline(root = "."): Outline {
|
|
264
|
+
// the build has run the property tests of the generated exercises
|
|
265
|
+
const site = loadSite(root, 0);
|
|
266
|
+
const pages: Record<string, PageOutline[]> = {};
|
|
267
|
+
const others: Record<string, PageOutline[]> = {};
|
|
268
|
+
for (const route of routes(site)) {
|
|
269
|
+
const item: PageOutline = {
|
|
270
|
+
kind: route.kind,
|
|
271
|
+
url: route.path,
|
|
272
|
+
lang: route.lang,
|
|
273
|
+
title: route.title,
|
|
274
|
+
headings: [{ level: 1, text: route.title }],
|
|
275
|
+
sections: [],
|
|
276
|
+
formulas: 0,
|
|
277
|
+
figures: [],
|
|
278
|
+
videos: [],
|
|
279
|
+
exercises: [],
|
|
280
|
+
components: [],
|
|
281
|
+
};
|
|
282
|
+
if (route.page === undefined) (others[route.lang] ??= []).push(item);
|
|
283
|
+
else {
|
|
284
|
+
walk(site, route.page.blocks, route.lang, 1, [], item);
|
|
285
|
+
(pages[route.lang] ??= []).push(item);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const asked = assessments(site).map((assessment) => ({
|
|
289
|
+
url: assessment.local,
|
|
290
|
+
offer: assessment.chapter === undefined ? "" : `${assessment.chapter.id}/`,
|
|
291
|
+
key: assessment.key,
|
|
292
|
+
steps: assessment.steps,
|
|
293
|
+
items: assessment.items.map((item) => ({
|
|
294
|
+
key: item.key,
|
|
295
|
+
step: item.step,
|
|
296
|
+
page: `${item.page.chapter}/${item.page.id}/`,
|
|
297
|
+
id: item.exercise,
|
|
298
|
+
})),
|
|
299
|
+
pages: assessment.pages.map((page) => ({
|
|
300
|
+
url: `${page.chapter}/${page.id}/`,
|
|
301
|
+
title: titleOf(page, "de"),
|
|
302
|
+
asked: assessment.items.filter((item) => item.page === page).length,
|
|
303
|
+
})),
|
|
304
|
+
}));
|
|
305
|
+
return { languages: site.app.languages, pages, others, assessments: asked };
|
|
306
|
+
}
|