@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,277 @@
|
|
|
1
|
+
// The content of an explainer, as the YAML files in src/ give it (explainer.v1.schema.json) and the build reads it
|
|
2
|
+
// (load.ts): the app, its chapters in order, their pages in order, the data files, the bundled images and the
|
|
3
|
+
// components (src/components/, components.ts) with the blocks that use them.
|
|
4
|
+
|
|
5
|
+
import type { Question } from "../shared/questions/question.ts";
|
|
6
|
+
import type { DataRecord, Generated } from "./generated/types.ts";
|
|
7
|
+
import type { Credit, Drawing, MaterialBlock } from "../shared/blocks/block.ts";
|
|
8
|
+
import { inLanguage, type Text } from "../shared/languages.ts";
|
|
9
|
+
|
|
10
|
+
export type { Credit, Drawing };
|
|
11
|
+
|
|
12
|
+
export { inLanguage, type Text };
|
|
13
|
+
|
|
14
|
+
/** An exercise of one of the question types, with the fields of a question; its texts may be maps by language. */
|
|
15
|
+
export type QuestionBlock = Question<Text>;
|
|
16
|
+
/** A point of a good answer to an open task: about the content, with its source, or about the form. */
|
|
17
|
+
export interface OpenTaskPoint {
|
|
18
|
+
text: Text;
|
|
19
|
+
kind?: "content" | "form";
|
|
20
|
+
/** Where its content is: /<chapter>/<page>/#<section>. */
|
|
21
|
+
source?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** An open task: answered in the learner's own words, then compared with the points of a good answer. */
|
|
25
|
+
export interface OpenTask {
|
|
26
|
+
type: "open-task";
|
|
27
|
+
id: string;
|
|
28
|
+
task: Text;
|
|
29
|
+
/** How the learner may answer; both when not given. */
|
|
30
|
+
answer?: readonly ("text" | "photo")[];
|
|
31
|
+
points: readonly OpenTaskPoint[];
|
|
32
|
+
/** The model answer. */
|
|
33
|
+
solution: Text;
|
|
34
|
+
hint?: Text;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** An exercise block: one of the question types, generated, or an open task. */
|
|
38
|
+
export type Exercise = QuestionBlock | Generated | OpenTask;
|
|
39
|
+
|
|
40
|
+
export interface Source {
|
|
41
|
+
title: Text;
|
|
42
|
+
url?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface App {
|
|
46
|
+
title: Text;
|
|
47
|
+
intro: Text;
|
|
48
|
+
languages: readonly string[];
|
|
49
|
+
chapters: readonly string[];
|
|
50
|
+
sources?: readonly Source[];
|
|
51
|
+
/** What the app adds for a KI tutor: its own rules (restricted Markdown), after the guide of each tutor page. */
|
|
52
|
+
tutor?: {
|
|
53
|
+
rules?: Text;
|
|
54
|
+
};
|
|
55
|
+
/** The scope for the tutor: what the app is about, and what does not belong to it (scope.ts). */
|
|
56
|
+
scope?: {
|
|
57
|
+
text?: Text;
|
|
58
|
+
out: readonly Text[];
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A self-assessment (assessment.ts): its pages in order, each with its exercises, each as /<chapter>/<page>/#<exercise>.
|
|
64
|
+
*/
|
|
65
|
+
export interface SelfAssessment {
|
|
66
|
+
pages: readonly { exercises: readonly string[] }[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface Event {
|
|
70
|
+
date: number | string;
|
|
71
|
+
label?: Text;
|
|
72
|
+
title: Text;
|
|
73
|
+
text?: Text;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type Block =
|
|
77
|
+
| MaterialBlock<Text>
|
|
78
|
+
| { type: "timeline"; events?: readonly Event[]; data?: string }
|
|
79
|
+
| { type: "definition"; term: Text; explanation: Text }
|
|
80
|
+
/** A YouTube video behind two clicks (video.ts): its id, and its title and channel as YouTube names them. */
|
|
81
|
+
| { type: "video"; youtube: string; title: string; channel: string }
|
|
82
|
+
| { type: "example" | "note"; title: Text; blocks: readonly Block[] }
|
|
83
|
+
| { type: "section"; id: string; title: Text; blocks: readonly Block[] }
|
|
84
|
+
| {
|
|
85
|
+
type: "vue-component";
|
|
86
|
+
/** Its anchor; an exercise component without one has its name in kebab case (assign-labels). */
|
|
87
|
+
id?: string;
|
|
88
|
+
component: string;
|
|
89
|
+
props?: Readonly<Record<string, unknown>>;
|
|
90
|
+
/** Required for a component that is no exercise; an exercise component's no-JS text is generated from describe. */
|
|
91
|
+
nojs?: Text;
|
|
92
|
+
examples?: ComponentExamples;
|
|
93
|
+
}
|
|
94
|
+
| Exercise;
|
|
95
|
+
|
|
96
|
+
export type BlockOf<T extends Block["type"]> = Extract<Block, { type: T }>;
|
|
97
|
+
|
|
98
|
+
export interface Page {
|
|
99
|
+
id: string;
|
|
100
|
+
chapter: string;
|
|
101
|
+
/** The source file, from the app's root: src/<chapter>/<page>.yaml. */
|
|
102
|
+
file: string;
|
|
103
|
+
title: Text;
|
|
104
|
+
description?: Text;
|
|
105
|
+
/** What the page teaches, for the tutor's scope (scope.ts). */
|
|
106
|
+
scope?: Text;
|
|
107
|
+
blocks: readonly Block[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface Chapter {
|
|
111
|
+
id: string;
|
|
112
|
+
title: Text;
|
|
113
|
+
summary?: Text;
|
|
114
|
+
pages: readonly Page[];
|
|
115
|
+
/** A self-assessment over the exercises of this chapter (assessment.ts). */
|
|
116
|
+
selfAssessment?: SelfAssessment;
|
|
117
|
+
/** What the chapter is about, for the tutor's scope. */
|
|
118
|
+
scope?: Text;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export type { DataRecord };
|
|
122
|
+
|
|
123
|
+
export interface Site {
|
|
124
|
+
app: App;
|
|
125
|
+
chapters: readonly Chapter[];
|
|
126
|
+
/** The records of each data file src/data/<name>.yaml, by name. */
|
|
127
|
+
data: Readonly<Record<string, readonly DataRecord[]>>;
|
|
128
|
+
/** The bundled images that blocks use, by their path from src/ (images/<name>), with the file's absolute path. */
|
|
129
|
+
images: ReadonlyMap<string, string>;
|
|
130
|
+
/** Each vue-component block, with its component and where it is. */
|
|
131
|
+
components: readonly ComponentUse[];
|
|
132
|
+
/** The app's name for what it keeps on the device (its package.json name; @lernapps/tooling/storage). */
|
|
133
|
+
storage?: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// What the build reads of a component (components.ts). Declared here, not there: the client module reaches this file,
|
|
137
|
+
// and components.ts is build code that needs Node.
|
|
138
|
+
|
|
139
|
+
/** A prop type that a block's props can give. */
|
|
140
|
+
export type PropType =
|
|
141
|
+
| { kind: "string" | "number" | "boolean" | "unknown" }
|
|
142
|
+
| { kind: "literal"; values: readonly (string | number | boolean)[] }
|
|
143
|
+
| { kind: "array"; of: PropType }
|
|
144
|
+
| { kind: "object"; fields: Readonly<Record<string, Field>> }
|
|
145
|
+
| { kind: "union"; of: readonly PropType[] };
|
|
146
|
+
|
|
147
|
+
export interface Field {
|
|
148
|
+
type: PropType;
|
|
149
|
+
optional: boolean;
|
|
150
|
+
/** The declaration as written, e.g. "parts: string[]". */
|
|
151
|
+
source: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface ComponentInfo {
|
|
155
|
+
name: string;
|
|
156
|
+
/** src/components/<Name>.vue */
|
|
157
|
+
file: string;
|
|
158
|
+
/** The .vue file's absolute path. */
|
|
159
|
+
path: string;
|
|
160
|
+
/** The props a block gives: every declared prop but seed, which the explainer gives an exercise component. */
|
|
161
|
+
props: Readonly<Record<string, Field>>;
|
|
162
|
+
/** Whether it emits answer: an exercise, which gets the seed of its task number as the prop seed. */
|
|
163
|
+
exercise: boolean;
|
|
164
|
+
/** Whether it declares the prop checked, which the explainer sets once it checked the answer the component has. */
|
|
165
|
+
checked: boolean;
|
|
166
|
+
/** Whether it keeps its nojs text, folded as a text description, once it runs, rather than replacing it. */
|
|
167
|
+
caption: boolean;
|
|
168
|
+
/** The absolute path of its logic module <Name>.ts, for an exercise. */
|
|
169
|
+
logic?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** An example of an exercise component: the answer its check takes, for the task of `seed`, or of every seed. */
|
|
173
|
+
export interface ComponentExample {
|
|
174
|
+
answer: unknown;
|
|
175
|
+
seed?: number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** The examples of an exercise component's block: test cases for the build, never shown to learners. */
|
|
179
|
+
export interface ComponentExamples {
|
|
180
|
+
accepted?: readonly ComponentExample[];
|
|
181
|
+
rejected?: readonly ComponentExample[];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** A vue-component block of a page, with the component it uses. */
|
|
185
|
+
export interface ComponentUse {
|
|
186
|
+
block: BlockOf<"vue-component">;
|
|
187
|
+
component: ComponentInfo;
|
|
188
|
+
/** Its anchor on the page, for an exercise component or a block with an id: the block's id or the default. */
|
|
189
|
+
id?: string;
|
|
190
|
+
/** Where the block is, as a problem line starts: src/<chapter>/<page>.yaml:<line>: blocks[0].blocks[3] */
|
|
191
|
+
place: string;
|
|
192
|
+
/** Where each of its examples is, as a problem line starts, by kind. */
|
|
193
|
+
examples: { accepted: string[]; rejected: string[] };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** The events of a timeline: its own, or the records of its data file. */
|
|
197
|
+
export function timelineEvents(site: Site, block: BlockOf<"timeline">): readonly Event[] {
|
|
198
|
+
if (block.events !== undefined) return block.events;
|
|
199
|
+
return (site.data[block.data ?? ""] ?? []) as unknown as readonly Event[];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* What an exercise component says about itself (the export about of its logic module), for a tutor: what the learner
|
|
204
|
+
* does, the answer's format, what counts as right, and the typical mistakes. Each a text, a map by language when the
|
|
205
|
+
* app has more than one.
|
|
206
|
+
*/
|
|
207
|
+
export interface ComponentAbout {
|
|
208
|
+
task: Text;
|
|
209
|
+
answer: Text;
|
|
210
|
+
correct: Text;
|
|
211
|
+
mistakes: readonly Text[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** A task of an exercise component, as its describe(task, props, lang) states it: restricted Markdown each. */
|
|
215
|
+
export interface DescribedTask {
|
|
216
|
+
/** Its task number, from 1. */
|
|
217
|
+
number: number;
|
|
218
|
+
seed: number;
|
|
219
|
+
task: string;
|
|
220
|
+
solution: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* An exercise component as a tutor reads it, in one language, from the exports template, params, mistakes and show
|
|
225
|
+
* of its logic: the task once with a placeholder for each input, and each task number's inputs and outputs, as a
|
|
226
|
+
* generated exercise has them (its typical mistakes are those of about).
|
|
227
|
+
*/
|
|
228
|
+
export interface ComponentExercise {
|
|
229
|
+
/** The task as a learner reads it, with {name} for each input, on one line: template(props, lang). */
|
|
230
|
+
template: string;
|
|
231
|
+
/** The names of the inputs in order, the columns before the solution: the keys of params(task, props, lang). */
|
|
232
|
+
inputs: readonly string[];
|
|
233
|
+
/** Each task number's task, from 1: the values of its inputs, its solution and what each typical mistake gives ("" for none), as text. */
|
|
234
|
+
tasks: readonly { inputs: readonly string[]; solution: string; mistakes: readonly string[] }[];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** What the build learnt from an exercise component's logic for one block: its about, and its tasks by language. */
|
|
238
|
+
export interface ComponentDescription {
|
|
239
|
+
about: ComponentAbout;
|
|
240
|
+
/** The seed of each task number, from 1: the seeds of its distinct tasks (distinctSeeds of tasks.ts). */
|
|
241
|
+
seeds: readonly number[];
|
|
242
|
+
/** The task of each number, in each language. */
|
|
243
|
+
tasks: Readonly<Record<string, readonly DescribedTask[]>>;
|
|
244
|
+
/** The exercise in each language, when its logic declares its inputs and outputs; else none. */
|
|
245
|
+
exercise?: Readonly<Record<string, ComponentExercise>>;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Every block of `blocks`, depth first, with the blocks inside sections and boxes. */
|
|
249
|
+
export function* allBlocks(blocks: readonly Block[]): Generator<Block> {
|
|
250
|
+
for (const block of blocks) {
|
|
251
|
+
yield block;
|
|
252
|
+
if (block.type === "section" || block.type === "example" || block.type === "note") yield* allBlocks(block.blocks);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Whether a block is an exercise. */
|
|
257
|
+
export const isExercise = (block: Block): block is Exercise =>
|
|
258
|
+
block.type === "generated" ||
|
|
259
|
+
block.type === "open-task" ||
|
|
260
|
+
["single-choice", "multiple-choice", "true-false", "number", "ordering", "matching"].includes(block.type);
|
|
261
|
+
|
|
262
|
+
/** The anchor of a term in the glossary: the German term in lower case, umlauts spelled out, hyphens for the rest. */
|
|
263
|
+
export function termId(term: Text): string {
|
|
264
|
+
return inLanguage(term, "de")
|
|
265
|
+
.toLowerCase()
|
|
266
|
+
.replace(/ä/g, "ae")
|
|
267
|
+
.replace(/ö/g, "oe")
|
|
268
|
+
.replace(/ü/g, "ue")
|
|
269
|
+
.replace(/ß/g, "ss")
|
|
270
|
+
.normalize("NFD")
|
|
271
|
+
.replace(/[̀-ͯ]/g, "")
|
|
272
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
273
|
+
.replace(/^-|-$/g, "");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** What the logic of each exercise component's block describes (plugin.ts): its about, and its tasks by language. */
|
|
277
|
+
export type Descriptions = ReadonlyMap<Block, ComponentDescription>;
|