postext 1.58.2 → 1.59.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.
Files changed (195) hide show
  1. package/dist/__tests__/exercises/config.test.d.ts +2 -0
  2. package/dist/__tests__/exercises/config.test.d.ts.map +1 -0
  3. package/dist/__tests__/exercises/config.test.js +63 -0
  4. package/dist/__tests__/exercises/config.test.js.map +1 -0
  5. package/dist/__tests__/exercises/digital.test.d.ts +2 -0
  6. package/dist/__tests__/exercises/digital.test.d.ts.map +1 -0
  7. package/dist/__tests__/exercises/digital.test.js +163 -0
  8. package/dist/__tests__/exercises/digital.test.js.map +1 -0
  9. package/dist/__tests__/exercises/languages.test.d.ts +2 -0
  10. package/dist/__tests__/exercises/languages.test.d.ts.map +1 -0
  11. package/dist/__tests__/exercises/languages.test.js +109 -0
  12. package/dist/__tests__/exercises/languages.test.js.map +1 -0
  13. package/dist/__tests__/exercises/layout.test.d.ts +2 -0
  14. package/dist/__tests__/exercises/layout.test.d.ts.map +1 -0
  15. package/dist/__tests__/exercises/layout.test.js +77 -0
  16. package/dist/__tests__/exercises/layout.test.js.map +1 -0
  17. package/dist/__tests__/exercises/model.test.d.ts +2 -0
  18. package/dist/__tests__/exercises/model.test.d.ts.map +1 -0
  19. package/dist/__tests__/exercises/model.test.js +90 -0
  20. package/dist/__tests__/exercises/model.test.js.map +1 -0
  21. package/dist/__tests__/exercises/parse.test.d.ts +2 -0
  22. package/dist/__tests__/exercises/parse.test.d.ts.map +1 -0
  23. package/dist/__tests__/exercises/parse.test.js +37 -0
  24. package/dist/__tests__/exercises/parse.test.js.map +1 -0
  25. package/dist/__tests__/exercises/refs.test.d.ts +2 -0
  26. package/dist/__tests__/exercises/refs.test.d.ts.map +1 -0
  27. package/dist/__tests__/exercises/refs.test.js +46 -0
  28. package/dist/__tests__/exercises/refs.test.js.map +1 -0
  29. package/dist/__tests__/exercises/solutions.test.d.ts +2 -0
  30. package/dist/__tests__/exercises/solutions.test.d.ts.map +1 -0
  31. package/dist/__tests__/exercises/solutions.test.js +53 -0
  32. package/dist/__tests__/exercises/solutions.test.js.map +1 -0
  33. package/dist/__tests__/exports.test.js +14 -0
  34. package/dist/__tests__/exports.test.js.map +1 -1
  35. package/dist/__tests__/parse/containers.test.js +2 -2
  36. package/dist/__tests__/parse/containers.test.js.map +1 -1
  37. package/dist/__tests__/pipeline/pageShorterThanLine.test.d.ts +2 -0
  38. package/dist/__tests__/pipeline/pageShorterThanLine.test.d.ts.map +1 -0
  39. package/dist/__tests__/pipeline/pageShorterThanLine.test.js +29 -0
  40. package/dist/__tests__/pipeline/pageShorterThanLine.test.js.map +1 -0
  41. package/dist/__tests__/pipeline/spanHeadingMidPage.test.js +11 -0
  42. package/dist/__tests__/pipeline/spanHeadingMidPage.test.js.map +1 -1
  43. package/dist/canvas-backend/blockRender.d.ts.map +1 -1
  44. package/dist/canvas-backend/blockRender.js +18 -0
  45. package/dist/canvas-backend/blockRender.js.map +1 -1
  46. package/dist/canvas-backend/chip.d.ts +3 -0
  47. package/dist/canvas-backend/chip.d.ts.map +1 -1
  48. package/dist/canvas-backend/chip.js +31 -1
  49. package/dist/canvas-backend/chip.js.map +1 -1
  50. package/dist/configWarnings.d.ts +3 -1
  51. package/dist/configWarnings.d.ts.map +1 -1
  52. package/dist/configWarnings.js +5 -1
  53. package/dist/configWarnings.js.map +1 -1
  54. package/dist/defaults/chipStyles.d.ts.map +1 -1
  55. package/dist/defaults/chipStyles.js +7 -0
  56. package/dist/defaults/chipStyles.js.map +1 -1
  57. package/dist/defaults/exercises.d.ts +111 -0
  58. package/dist/defaults/exercises.d.ts.map +1 -0
  59. package/dist/defaults/exercises.js +255 -0
  60. package/dist/defaults/exercises.js.map +1 -0
  61. package/dist/defaults/index.d.ts +2 -0
  62. package/dist/defaults/index.d.ts.map +1 -1
  63. package/dist/defaults/index.js +16 -0
  64. package/dist/defaults/index.js.map +1 -1
  65. package/dist/defaults/shared.d.ts +4 -0
  66. package/dist/defaults/shared.d.ts.map +1 -1
  67. package/dist/defaults/shared.js +6 -0
  68. package/dist/defaults/shared.js.map +1 -1
  69. package/dist/design/elementKeys.d.ts +2 -0
  70. package/dist/design/elementKeys.d.ts.map +1 -1
  71. package/dist/design/elementKeys.js +1 -1
  72. package/dist/design/elementKeys.js.map +1 -1
  73. package/dist/exercises/build.d.ts +60 -0
  74. package/dist/exercises/build.d.ts.map +1 -0
  75. package/dist/exercises/build.js +177 -0
  76. package/dist/exercises/build.js.map +1 -0
  77. package/dist/exercises/configWarnings.d.ts +11 -0
  78. package/dist/exercises/configWarnings.d.ts.map +1 -0
  79. package/dist/exercises/configWarnings.js +175 -0
  80. package/dist/exercises/configWarnings.js.map +1 -0
  81. package/dist/exercises/designs.d.ts +38 -0
  82. package/dist/exercises/designs.d.ts.map +1 -0
  83. package/dist/exercises/designs.js +143 -0
  84. package/dist/exercises/designs.js.map +1 -0
  85. package/dist/exercises/digital.d.ts +69 -0
  86. package/dist/exercises/digital.d.ts.map +1 -0
  87. package/dist/exercises/digital.js +58 -0
  88. package/dist/exercises/digital.js.map +1 -0
  89. package/dist/exercises/expand.d.ts +74 -0
  90. package/dist/exercises/expand.d.ts.map +1 -0
  91. package/dist/exercises/expand.js +1089 -0
  92. package/dist/exercises/expand.js.map +1 -0
  93. package/dist/exercises/grids.d.ts +62 -0
  94. package/dist/exercises/grids.d.ts.map +1 -0
  95. package/dist/exercises/grids.js +535 -0
  96. package/dist/exercises/grids.js.map +1 -0
  97. package/dist/exercises/model.d.ts +24 -0
  98. package/dist/exercises/model.d.ts.map +1 -0
  99. package/dist/exercises/model.js +360 -0
  100. package/dist/exercises/model.js.map +1 -0
  101. package/dist/exercises/record.d.ts +94 -0
  102. package/dist/exercises/record.d.ts.map +1 -0
  103. package/dist/exercises/record.js +9 -0
  104. package/dist/exercises/record.js.map +1 -0
  105. package/dist/exercises/runtime.d.ts +65 -0
  106. package/dist/exercises/runtime.d.ts.map +1 -0
  107. package/dist/exercises/runtime.js +1261 -0
  108. package/dist/exercises/runtime.js.map +1 -0
  109. package/dist/exercises/shuffle.d.ts +13 -0
  110. package/dist/exercises/shuffle.d.ts.map +1 -0
  111. package/dist/exercises/shuffle.js +56 -0
  112. package/dist/exercises/shuffle.js.map +1 -0
  113. package/dist/exercises/styles.d.ts +51 -0
  114. package/dist/exercises/styles.d.ts.map +1 -0
  115. package/dist/exercises/styles.js +221 -0
  116. package/dist/exercises/styles.js.map +1 -0
  117. package/dist/exercises/text.d.ts +31 -0
  118. package/dist/exercises/text.d.ts.map +1 -0
  119. package/dist/exercises/text.js +82 -0
  120. package/dist/exercises/text.js.map +1 -0
  121. package/dist/exercises/types.d.ts +125 -0
  122. package/dist/exercises/types.d.ts.map +1 -0
  123. package/dist/exercises/types.js +9 -0
  124. package/dist/exercises/types.js.map +1 -0
  125. package/dist/exercises/warnings.d.ts +16 -0
  126. package/dist/exercises/warnings.d.ts.map +1 -0
  127. package/dist/exercises/warnings.js +55 -0
  128. package/dist/exercises/warnings.js.map +1 -0
  129. package/dist/html-backend.d.ts +6 -0
  130. package/dist/html-backend.d.ts.map +1 -1
  131. package/dist/html-backend.js +67 -6
  132. package/dist/html-backend.js.map +1 -1
  133. package/dist/index.d.ts +6 -0
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +4 -0
  136. package/dist/index.js.map +1 -1
  137. package/dist/measure/cache.d.ts.map +1 -1
  138. package/dist/measure/cache.js +6 -1
  139. package/dist/measure/cache.js.map +1 -1
  140. package/dist/measure/rich.d.ts.map +1 -1
  141. package/dist/measure/rich.js +11 -1
  142. package/dist/measure/rich.js.map +1 -1
  143. package/dist/migrate/markdownRuns.js +1 -1
  144. package/dist/migrate/markdownRuns.js.map +1 -1
  145. package/dist/numbering.d.ts +3 -0
  146. package/dist/numbering.d.ts.map +1 -1
  147. package/dist/numbering.js +6 -0
  148. package/dist/numbering.js.map +1 -1
  149. package/dist/parse/blockParser.d.ts.map +1 -1
  150. package/dist/parse/blockParser.js +47 -4
  151. package/dist/parse/blockParser.js.map +1 -1
  152. package/dist/parse/exerciseGaps.d.ts +50 -0
  153. package/dist/parse/exerciseGaps.d.ts.map +1 -0
  154. package/dist/parse/exerciseGaps.js +151 -0
  155. package/dist/parse/exerciseGaps.js.map +1 -0
  156. package/dist/parse/index.d.ts +1 -1
  157. package/dist/parse/index.d.ts.map +1 -1
  158. package/dist/parse/index.js.map +1 -1
  159. package/dist/parse/sourceMapping.d.ts.map +1 -1
  160. package/dist/parse/sourceMapping.js +21 -0
  161. package/dist/parse/sourceMapping.js.map +1 -1
  162. package/dist/parse/types.d.ts +49 -1
  163. package/dist/parse/types.d.ts.map +1 -1
  164. package/dist/pipeline/build.d.ts.map +1 -1
  165. package/dist/pipeline/build.js +51 -9
  166. package/dist/pipeline/build.js.map +1 -1
  167. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  168. package/dist/pipeline/calloutLayout.js +1 -0
  169. package/dist/pipeline/calloutLayout.js.map +1 -1
  170. package/dist/pipeline/chips.d.ts.map +1 -1
  171. package/dist/pipeline/chips.js +2 -0
  172. package/dist/pipeline/chips.js.map +1 -1
  173. package/dist/pipeline/config.d.ts.map +1 -1
  174. package/dist/pipeline/config.js +6 -0
  175. package/dist/pipeline/config.js.map +1 -1
  176. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  177. package/dist/pipeline/contentWarnings.js +29 -1
  178. package/dist/pipeline/contentWarnings.js.map +1 -1
  179. package/dist/pipeline/continuation.d.ts.map +1 -1
  180. package/dist/pipeline/continuation.js +21 -6
  181. package/dist/pipeline/continuation.js.map +1 -1
  182. package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
  183. package/dist/pipeline/measureContentBlock.js +3 -2
  184. package/dist/pipeline/measureContentBlock.js.map +1 -1
  185. package/dist/pipeline/outline.d.ts.map +1 -1
  186. package/dist/pipeline/outline.js +1 -0
  187. package/dist/pipeline/outline.js.map +1 -1
  188. package/dist/pipeline/textWrap.js +1 -1
  189. package/dist/pipeline/textWrap.js.map +1 -1
  190. package/dist/types.d.ts +303 -2
  191. package/dist/types.d.ts.map +1 -1
  192. package/dist/vdt.d.ts +67 -0
  193. package/dist/vdt.d.ts.map +1 -1
  194. package/dist/vdt.js.map +1 -1
  195. package/package.json +1 -1
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Runs of inline text for the exercise expansion (#1225): a block's plain
3
+ * text, its spans and its source map kept together, so a piece cut from a
4
+ * block (an option, the right side of a pair) or a word the engine adds (a
5
+ * label, a number) stays mapped to the source the Sandbox points at.
6
+ */
7
+ import { sliceSpan } from '../parse/links.js';
8
+ export const EMPTY_RUN = { text: '', spans: [], sourceMap: [] };
9
+ export function runOf(block) {
10
+ return { text: block.text, spans: block.spans, sourceMap: block.sourceMap };
11
+ }
12
+ /** `[start, end)` of a run. */
13
+ export function sliceRun(run, start, end = run.text.length) {
14
+ start = Math.max(0, Math.min(start, run.text.length));
15
+ end = Math.max(start, Math.min(end, run.text.length));
16
+ const spans = [];
17
+ let at = 0;
18
+ for (const s of run.spans) {
19
+ const a = at;
20
+ const b = at + s.text.length;
21
+ at = b;
22
+ if (b <= start || a >= end)
23
+ continue;
24
+ const from = Math.max(start, a) - a;
25
+ const to = Math.min(end, b) - a;
26
+ spans.push(from === 0 && to === s.text.length ? s : sliceSpan(s, from, to));
27
+ }
28
+ return { text: run.text.slice(start, end), spans, sourceMap: run.sourceMap.slice(start, end) };
29
+ }
30
+ /** The runs one after another. */
31
+ export function joinRuns(...runs) {
32
+ const out = { text: '', spans: [], sourceMap: [] };
33
+ for (const r of runs) {
34
+ out.text += r.text;
35
+ out.spans.push(...r.spans);
36
+ out.sourceMap.push(...r.sourceMap);
37
+ }
38
+ return out;
39
+ }
40
+ /** Words the engine sets (a label, a number), mapped to `at`. */
41
+ export function textRun(text, at, style = {}) {
42
+ if (text === '')
43
+ return EMPTY_RUN;
44
+ return { text, spans: [{ text, bold: false, italic: false, ...style }], sourceMap: new Array(text.length).fill(at) };
45
+ }
46
+ /** A run whose spans are all set bold (or `italic`). */
47
+ export function styledRun(run, style) {
48
+ return { ...run, spans: run.spans.map((s) => ({ ...s, ...style })) };
49
+ }
50
+ /** The run with the white space at its ends taken off. */
51
+ export function trimRun(run) {
52
+ let a = 0;
53
+ let b = run.text.length;
54
+ while (a < b && /\s/u.test(run.text[a]))
55
+ a++;
56
+ while (b > a && /\s/u.test(run.text[b - 1]))
57
+ b--;
58
+ return a === 0 && b === run.text.length ? run : sliceRun(run, a, b);
59
+ }
60
+ /** The run cut at every match of `sep` (a plain-text pattern), trimmed. */
61
+ export function splitRun(run, sep) {
62
+ const out = [];
63
+ const re = new RegExp(sep.source, sep.flags.includes('g') ? sep.flags : sep.flags + 'g');
64
+ let last = 0;
65
+ for (let m = re.exec(run.text); m; m = re.exec(run.text)) {
66
+ if (m[0].length === 0) {
67
+ re.lastIndex++;
68
+ continue;
69
+ }
70
+ out.push(trimRun(sliceRun(run, last, m.index)));
71
+ last = m.index + m[0].length;
72
+ }
73
+ out.push(trimRun(sliceRun(run, last)));
74
+ return out;
75
+ }
76
+ /** A content block of `type` holding `run`. */
77
+ export function blockOfRun(type, run, fields = {}) {
78
+ const start = run.sourceMap.length > 0 ? Math.min(...run.sourceMap) : (fields.sourceStart ?? 0);
79
+ const end = run.sourceMap.length > 0 ? Math.max(...run.sourceMap) + 1 : (fields.sourceEnd ?? start);
80
+ return { type, text: run.text, spans: run.spans, sourceMap: run.sourceMap, sourceStart: start, sourceEnd: end, ...fields };
81
+ }
82
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/exercises/text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The model of an exercise (#1225): what the Markdown of a `:::exercise`
3
+ * asks and answers, read once from the parsed blocks and shared by the
4
+ * page layout, the solutions and the digital outputs.
5
+ */
6
+ import type { DirectiveAttrs, ExerciseGap } from '../parse/index.js';
7
+ import type { Run } from './text.js';
8
+ export declare const EXERCISE_KINDS: readonly ["choice", "truefalse", "gaps", "match", "order", "scramble", "sort", "mark", "open", "wordsearch", "crossword", "arithmetic"];
9
+ /** What an exercise asks (`:::exercise{type=…}`). */
10
+ export type ExerciseKind = typeof EXERCISE_KINDS[number];
11
+ /** An option of a question (`- [x] Lisbon`). */
12
+ export interface ExerciseOption {
13
+ /** The task item's block index. */
14
+ block: number;
15
+ correct: boolean;
16
+ }
17
+ /** A question of a `choice` exercise: its stem (a list item with the
18
+ * options under it) and its options; or a statement of a `truefalse`
19
+ * exercise (one option, ticked when true). */
20
+ export interface ExerciseQuestion {
21
+ stem?: number;
22
+ options: ExerciseOption[];
23
+ /** More than one right option, or `select="many"`. */
24
+ multiple: boolean;
25
+ }
26
+ /** A `[[…]]` of the exercise. */
27
+ export interface ExerciseGapRef {
28
+ block: number;
29
+ /** Index of the gap's span in the block's spans. */
30
+ span: number;
31
+ gap: ExerciseGap;
32
+ /** 1-based, in Markdown order. */
33
+ n: number;
34
+ }
35
+ /** A pair of a `match` exercise (`- Bee -> Hive`); `left` empty for a
36
+ * distractor of the right column (`- -> Cave`). */
37
+ export interface ExercisePair {
38
+ block: number;
39
+ left: Run;
40
+ right: Run;
41
+ }
42
+ /** A category of a `sort` exercise (`- Mammals: dog, whale`). */
43
+ export interface ExerciseCategory {
44
+ block: number;
45
+ name: Run;
46
+ items: Run[];
47
+ }
48
+ /** A word of a `wordsearch` (`- MERCURY`) or an entry of a `crossword`
49
+ * (`- SUN: The star of the solar system`). */
50
+ export interface ExerciseEntry {
51
+ block: number;
52
+ /** The word as written, its spaces and hyphens taken out. */
53
+ word: string;
54
+ clue?: Run;
55
+ }
56
+ /** An operation of an `arithmetic` exercise (`- 345 + 278`). */
57
+ export interface ExerciseOperation {
58
+ block: number;
59
+ a: string;
60
+ b: string;
61
+ op: '+' | '-' | '×' | '÷';
62
+ /** The sign as the operation prints it (`×` or `·`, `÷` or `:`). */
63
+ sign?: string;
64
+ /** The result in the digits written; a division's quotient. */
65
+ result: string;
66
+ /** A division's remainder, when not zero. */
67
+ remainder?: string;
68
+ }
69
+ /** A sentence of a `scramble` exercise, cut into its pieces. */
70
+ export interface ExerciseSentence {
71
+ block: number;
72
+ pieces: Run[];
73
+ }
74
+ export type ExerciseIssueKind = 'exerciseUnknownType' | 'exerciseNoAnswer' | 'exerciseUnreadItem' | 'exerciseNested'
75
+ /** A word a crossword or a word search could not place (`detail`). */
76
+ | 'exerciseWordUnplaced' | 'solutionOutside';
77
+ export interface ExerciseIssue {
78
+ kind: ExerciseIssueKind;
79
+ /** The exercise's container id (absent for a solution outside one). */
80
+ exercise?: number;
81
+ /** What was written (an unknown type, an item read as nothing). */
82
+ detail?: string;
83
+ sourceStart: number;
84
+ sourceEnd: number;
85
+ }
86
+ export interface ExerciseModel {
87
+ /** The fence's container id. */
88
+ id: number;
89
+ /** 0-based, among the document's exercises. */
90
+ ordinal: number;
91
+ kind: ExerciseKind;
92
+ attrs: DirectiveAttrs;
93
+ /** Indices of the opening and closing markers. */
94
+ start: number;
95
+ end: number;
96
+ /** The leading paragraphs. */
97
+ instruction: number[];
98
+ /** Every block between the markers that is not the instruction, a
99
+ * solution, a hint or a bank, in order. */
100
+ body: number[];
101
+ /** The blocks the kind reads as items (options, pairs, words…). */
102
+ items: Set<number>;
103
+ /** `:::solution` and `:::hint` ranges (marker indices). */
104
+ solutions: Array<{
105
+ start: number;
106
+ end: number;
107
+ }>;
108
+ hints: Array<{
109
+ start: number;
110
+ end: number;
111
+ }>;
112
+ banks: number[];
113
+ gaps: ExerciseGapRef[];
114
+ questions: ExerciseQuestion[];
115
+ pairs: ExercisePair[];
116
+ /** `order`: the items' blocks in the right order. */
117
+ sequence: number[];
118
+ sentences: ExerciseSentence[];
119
+ categories: ExerciseCategory[];
120
+ entries: ExerciseEntry[];
121
+ operations: ExerciseOperation[];
122
+ sourceStart: number;
123
+ sourceEnd: number;
124
+ }
125
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/exercises/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The model of an exercise (#1225): what the Markdown of a `:::exercise`
3
+ * asks and answers, read once from the parsed blocks and shared by the
4
+ * page layout, the solutions and the digital outputs.
5
+ */
6
+ export const EXERCISE_KINDS = [
7
+ 'choice', 'truefalse', 'gaps', 'match', 'order', 'scramble', 'sort', 'mark', 'open', 'wordsearch', 'crossword', 'arithmetic',
8
+ ];
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/exercises/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY;CACpH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What the Markdown of a document's exercises says that the engine cannot
3
+ * read (#1225), as content warnings: an unknown kind or style, a graded
4
+ * exercise with no right answer, an item its kind cannot read, a word a
5
+ * grid cannot place, a solution outside an exercise.
6
+ */
7
+ import type { ContentBlock } from '../parse/index.js';
8
+ import type { PostextConfig } from '../types.js';
9
+ import type { ContentWarning } from '../vdt.js';
10
+ type Located<T> = T & {
11
+ sourceStart: number;
12
+ sourceEnd: number;
13
+ };
14
+ export declare function exerciseContentWarnings(blocks: readonly ContentBlock[], config: PostextConfig | undefined): Located<ContentWarning>[];
15
+ export {};
16
+ //# sourceMappingURL=warnings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.d.ts","sourceRoot":"","sources":["../../src/exercises/warnings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMhD,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,EAAE,CAgCrI"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * What the Markdown of a document's exercises says that the engine cannot
3
+ * read (#1225), as content warnings: an unknown kind or style, a graded
4
+ * exercise with no right answer, an item its kind cannot read, a word a
5
+ * grid cannot place, a solution outside an exercise.
6
+ */
7
+ import { resolveAllConfig } from '../pipeline/config.js';
8
+ import { exerciseSettingsFor } from './build.js';
9
+ import { readExercises } from './model.js';
10
+ import { gridBox } from './grids.js';
11
+ export function exerciseContentWarnings(blocks, config) {
12
+ const { exercises, issues } = readExercises(blocks);
13
+ const out = [];
14
+ const at = (i) => ({ sourceStart: i.sourceStart, sourceEnd: i.sourceEnd });
15
+ for (const i of issues) {
16
+ switch (i.kind) {
17
+ case 'exerciseUnknownType':
18
+ out.push({ kind: 'exerciseUnknownType', type: i.detail ?? '', ...at(i) });
19
+ break;
20
+ case 'exerciseNoAnswer': {
21
+ const ex = exercises.find((e) => e.id === i.exercise);
22
+ out.push({ kind: 'exerciseNoAnswer', exerciseKind: ex?.kind ?? '', ...at(i) });
23
+ break;
24
+ }
25
+ case 'exerciseUnreadItem':
26
+ out.push({ kind: 'exerciseUnreadItem', text: i.detail ?? '', ...at(i) });
27
+ break;
28
+ case 'exerciseNested':
29
+ out.push({ kind: 'exerciseNested', ...at(i) });
30
+ break;
31
+ case 'solutionOutside':
32
+ out.push({ kind: 'solutionOutside', ...at(i) });
33
+ break;
34
+ case 'exerciseWordUnplaced':
35
+ out.push({ kind: 'exerciseWordUnplaced', word: i.detail ?? '', ...at(i) });
36
+ break;
37
+ }
38
+ }
39
+ const settings = exerciseSettingsFor(resolveAllConfig(config));
40
+ const styles = new Set((config?.exerciseStyles ?? []).map((s) => s.id));
41
+ for (const ex of exercises) {
42
+ if (config?.exerciseStyles && ex.attrs.style !== undefined && !styles.has(ex.attrs.style)) {
43
+ out.push({ kind: 'exerciseUnknownStyle', style: ex.attrs.style, sourceStart: ex.sourceStart, sourceEnd: ex.sourceStart });
44
+ }
45
+ // A grid places its words whatever the page: generated here with the
46
+ // first style, words that do not fit reported.
47
+ if (ex.kind === 'crossword' || ex.kind === 'wordsearch') {
48
+ const box = gridBox({ kind: ex.kind, id: 'check', style: settings.styles[0], exercise: ex, blocks, seed: settings.exercises.seed, bodySizePt: 10, lineHeightPt: 12, measurePt: 1e6 });
49
+ for (const word of box.unplaced ?? [])
50
+ out.push({ kind: 'exerciseWordUnplaced', word, sourceStart: ex.sourceStart, sourceEnd: ex.sourceEnd });
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ //# sourceMappingURL=warnings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warnings.js","sourceRoot":"","sources":["../../src/exercises/warnings.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { VDTDocument, RenderWarning } from './vdt.js';
2
2
  import { type SvgFontSyncProvider } from './svg/fonts.js';
3
+ import { type ExerciseData } from './exercises/digital.js';
3
4
  export interface RenderHtmlOptions {
4
5
  /** Layout mode: single vertical column or many columns laid out horizontally. */
5
6
  mode?: 'single' | 'multi';
@@ -119,6 +120,11 @@ export interface HtmlRenderIndex {
119
120
  html: string;
120
121
  mode: 'single' | 'multi';
121
122
  pages: HtmlRenderIndexPage[];
123
+ /** The document's exercises for the exercise script (#1230), as `html`
124
+ * writes them in its `<script class="pt-exercises">`: a host that
125
+ * patches the pages instead of setting `html` hands them to
126
+ * `attachExercises` itself. Absent when it has none. */
127
+ exercises?: ExerciseData;
122
128
  }
123
129
  /**
124
130
  * CSS declarations (a `prop:value;` list) that reset the inherited text
@@ -1 +1 @@
1
- {"version":3,"file":"html-backend.d.ts","sourceRoot":"","sources":["../src/html-backend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAwBX,aAAa,EACd,MAAM,UAAU,CAAC;AAKlB,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAiJtF,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;kDAI8C;IAC9C,gBAAgB,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC,GAAG;QAC5D;;;0BAGkB;QAClB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;IACF;;;;;;;;;;;;iEAY6D;IAC7D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;4DAGwD;IACxD,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1D;;;;;;;2DAOuD;IACvD,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,GAAG,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;KAAE,CAAC;IACnG;;;wDAGoD;IACpD,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C;;;;;;;uEAOmE;IACnE,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B;;;;;;;;;;uBAUmB;IACnB,cAAc,CAAC,EAAE,OAAO,GAAG;QACzB,KAAK,CAAC,EAAE,mBAAmB,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;QACvC;2DACmD;QACnD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;KAClD,CAAC;CACH;AAkWD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAajE;AAiuGD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5C,8EAA8E;IAC9E,cAAc,EAAE,MAAM,CAAC;IACvB;4EACwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,QAS4B,CAAC;AAEzD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,WAAW,EAChB,OAAO,GAAE,iBAAsB,GAC9B,eAAe,CAuGjB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAEtF"}
1
+ {"version":3,"file":"html-backend.d.ts","sourceRoot":"","sources":["../src/html-backend.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ import { altWithLabels } from './composed/labelText.js';
32
32
  import { figureLabelLeaderPaths, figureLabelMatrix, undrawnLabels, unmirrorLabelLayout } from './composed/labels.js';
33
33
  import { comicFramePaintOrder, composedFrameBlockIds, composedPaintOrder, composedReadingOrder, composedSheetClip, composedSheetClipOnSheet, decorationOver, decorationUnder, frameClips, frameContentRect, frameMatrix } from './composed/paint.js';
34
34
  import { taskBoxSvgBody, taskBoxText } from './taskBox.js';
35
+ import { exerciseDataJson, exerciseDataOf } from './exercises/digital.js';
35
36
  /**
36
37
  * Declarations of every box of CJK text measured with no punctuation
37
38
  * trimming: the browser adds and removes nothing. Chrome's
@@ -1763,14 +1764,28 @@ function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor,
1763
1764
  rootDir = 'ltr') {
1764
1765
  const bx = x + chip.marginLeft;
1765
1766
  const parts = [];
1767
+ const boxGeometry = `position:absolute;left:${bx.toFixed(3)}px;top:${(baselineOffset - chip.ascent).toFixed(3)}px;` +
1768
+ `width:${chip.boxWidth.toFixed(3)}px;height:${(chip.ascent + chip.descent).toFixed(3)}px;box-sizing:border-box;`;
1766
1769
  if (chip.background || (chip.borderColor && chip.borderWidth > 0)) {
1767
- parts.push(`<span aria-hidden="true" style="position:absolute;left:${bx.toFixed(3)}px;top:${(baselineOffset - chip.ascent).toFixed(3)}px;` +
1768
- `width:${chip.boxWidth.toFixed(3)}px;height:${(chip.ascent + chip.descent).toFixed(3)}px;box-sizing:border-box;` +
1770
+ // An underline (#1227) is the box's bottom border alone.
1771
+ const border = chip.borderColor && chip.borderWidth > 0
1772
+ ? `${chip.underline ? 'border-bottom' : 'border'}:${chip.borderWidth.toFixed(3)}px ${chip.underline && chip.underline !== 'solid' ? chip.underline : 'solid'} ${chip.borderColor};`
1773
+ : '';
1774
+ parts.push(`<span aria-hidden="true" style="${boxGeometry}` +
1769
1775
  (chip.background ? `background:${chip.background};` : '') +
1770
- (chip.borderColor && chip.borderWidth > 0 ? `border:${chip.borderWidth.toFixed(3)}px solid ${chip.borderColor};` : '') +
1771
- (chip.borderRadius > 0 ? `border-radius:${chip.borderRadius.toFixed(3)}px;` : '') +
1776
+ border +
1777
+ (chip.borderRadius > 0 && !chip.underline ? `border-radius:${chip.borderRadius.toFixed(3)}px;` : '') +
1772
1778
  `"></span>`);
1773
1779
  }
1780
+ // Where an exercise is answered (#1230): a box the digital outputs find
1781
+ // by its slot. A blank reads as what it is; its answer is not written.
1782
+ if (chip.exercise || chip.blank) {
1783
+ const data = chip.exercise ? ` data-pt-ex="${chip.exercise.ex}" data-pt-slot="${esc(chip.exercise.slot)}"` : '';
1784
+ const label = chip.blank ? ` role="img" aria-label="${esc(chip.blankLabel ?? 'blank')}"` : '';
1785
+ parts.push(`<span class="pt-ex-slot${chip.blank ? ' pt-ex-blank' : ''}"${data}${label} style="${boxGeometry}"></span>`);
1786
+ }
1787
+ if (chip.blank)
1788
+ return parts.join('');
1774
1789
  let tx = bx + chip.borderWidth + chip.paddingX;
1775
1790
  // The runs in the chip's paint order (`VDTChip.order`); a right-to-left
1776
1791
  // run's box reads right to left.
@@ -3252,11 +3267,51 @@ function renderBlock(block, options, extra = '') {
3252
3267
  const note = block.footnoteNote !== undefined && !block.hidden
3253
3268
  ? zeroSizeAnchor(footnoteElementId(block.footnoteNote), block.bbox.x, block.bbox.y)
3254
3269
  : '';
3255
- return (`<div class="pt-block" data-block-id="${esc(block.id)}" style="display:contents;">` +
3270
+ // A box printed upside down (#1229): a positioned layer at the page's
3271
+ // origin, turned about the box's centre.
3272
+ const style = block.turn
3273
+ ? `position:absolute;left:0;top:0;width:0;height:0;transform-origin:${block.turn.cx.toFixed(3)}px ${block.turn.cy.toFixed(3)}px;transform:rotate(180deg);`
3274
+ : 'display:contents;';
3275
+ return (`<div class="pt-block" data-block-id="${esc(block.id)}" style="${style}">` +
3256
3276
  note +
3257
3277
  (block.comic && block.stripCaption && !block.hidden ? renderStripBlockHtml(block, options, extra) : renderBlockInner(block, options) + extra) +
3278
+ exerciseBoxHtml(block, options) +
3258
3279
  `</div>`);
3259
3280
  }
3281
+ /** The boxes of the document's exercises by their own container id (see
3282
+ * {@link HtmlPaint.exerciseBoxes}); `undefined` when it has none. */
3283
+ function exerciseBoxesOf(data) {
3284
+ if (!data)
3285
+ return undefined;
3286
+ const out = new Map();
3287
+ for (const r of data.exercises) {
3288
+ out.set(r.id, { ex: r.id, outer: true });
3289
+ for (const s of r.slots)
3290
+ if (s.box !== undefined && !out.has(s.box))
3291
+ out.set(s.box, { ex: r.id, outer: false });
3292
+ for (const g of r.grids ?? [])
3293
+ if (!out.has(g.box))
3294
+ out.set(g.box, { ex: r.id, outer: false });
3295
+ }
3296
+ return out;
3297
+ }
3298
+ /** Where an exercise's box lies (#1230): an empty element over a callout
3299
+ * frame of an exercise — its outer box, a writing area, a grid — that the
3300
+ * exercise script finds by `data-pt-box` and lays its inputs, lines and
3301
+ * bar in. Not on a vertical page, whose flow is turned. */
3302
+ function exerciseBoxHtml(block, options) {
3303
+ const boxes = options.exerciseBoxes;
3304
+ if (!boxes || block.type !== 'callout' || !block.callout || block.hidden || options.vertical)
3305
+ return '';
3306
+ const own = block.calloutPath && block.calloutPath.length > 0 ? block.calloutPath[block.calloutPath.length - 1] : block.containerId;
3307
+ const box = own !== undefined ? boxes.get(own) : undefined;
3308
+ if (!box)
3309
+ return '';
3310
+ const { x, y, width, height } = block.bbox;
3311
+ const part = block.callout.part !== undefined ? ` data-pt-part="${block.callout.part}"${block.callout.continued ? ' data-pt-continued=""' : ''}` : '';
3312
+ return `<div class="pt-ex-box" data-pt-box="${own}" data-pt-ex="${box.ex}"${box.outer ? ` data-pt-exercise="${box.ex}"` : ''}${part} ` +
3313
+ `style="position:absolute;left:${x}px;top:${y}px;width:${width}px;height:${height}px;pointer-events:none;"></div>`;
3314
+ }
3260
3315
  /** An empty element with an id at a point of the page: the target of an
3261
3316
  * in-document link. */
3262
3317
  function zeroSizeAnchor(id, x, y) {
@@ -3617,7 +3672,12 @@ export function renderToHtmlIndexed(doc, options = {}) {
3617
3672
  const linkTargets = anchoredResourceIds(doc);
3618
3673
  for (const id of options.refTargets ?? [])
3619
3674
  linkTargets.add(id);
3675
+ // The exercises (#1230): their boxes are marked on the pages, their
3676
+ // records written once for the exercise script.
3677
+ const exercises = exerciseDataOf(doc);
3678
+ const exerciseBoxes = exerciseBoxesOf(exercises);
3620
3679
  const anchorPaint = {
3680
+ ...(exerciseBoxes ? { exerciseBoxes } : {}),
3621
3681
  ...(doc.config.comics?.cast.length ? { comicCast: doc.config.comics.cast } : {}),
3622
3682
  ...(doc.anchors ? { anchors: doc.anchors } : {}),
3623
3683
  pageIndexOffset: doc.pageIndexOffset ?? 0,
@@ -3677,8 +3737,9 @@ export function renderToHtmlIndexed(doc, options = {}) {
3677
3737
  // escaped, they cannot leave their attributes.
3678
3738
  const html = `<div class="pt-doc"${docLang !== undefined ? ` lang="${docLang}"` : ''}${rtl ? ' dir="rtl"' : ''} data-mode="${esc(mode)}" style="${esc(reset + docStyle)}">` +
3679
3739
  pageHtmlParts.join('') +
3740
+ (exercises ? `<script type="application/json" class="pt-exercises">${exerciseDataJson(exercises)}</script>` : '') +
3680
3741
  `</div>`;
3681
- return { html, mode, pages: indexedPages };
3742
+ return { html, mode, pages: indexedPages, ...(exercises ? { exercises } : {}) };
3682
3743
  }
3683
3744
  export function renderToHtml(doc, options = {}) {
3684
3745
  return renderToHtmlIndexed(doc, options).html;