lens-content-processor 0.3.0 → 0.5.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 (78) hide show
  1. package/dist/bundler/article.d.ts +7 -2
  2. package/dist/bundler/article.js +19 -8
  3. package/dist/bundler/article.js.map +1 -1
  4. package/dist/bundler/video.d.ts +12 -6
  5. package/dist/bundler/video.js +57 -34
  6. package/dist/bundler/video.js.map +1 -1
  7. package/dist/cli.d.ts +11 -2
  8. package/dist/cli.js +36 -19
  9. package/dist/cli.js.map +1 -1
  10. package/dist/content-schema.js +64 -15
  11. package/dist/content-schema.js.map +1 -1
  12. package/dist/dedupe-errors.d.ts +14 -0
  13. package/dist/dedupe-errors.js +33 -0
  14. package/dist/dedupe-errors.js.map +1 -0
  15. package/dist/flattener/index.d.ts +22 -28
  16. package/dist/flattener/index.js +773 -613
  17. package/dist/flattener/index.js.map +1 -1
  18. package/dist/flattener/resolve-text-links.d.ts +25 -0
  19. package/dist/flattener/resolve-text-links.js +248 -0
  20. package/dist/flattener/resolve-text-links.js.map +1 -0
  21. package/dist/flattener/test-helpers.d.ts +23 -0
  22. package/dist/flattener/test-helpers.js +56 -0
  23. package/dist/flattener/test-helpers.js.map +1 -0
  24. package/dist/index.d.ts +66 -20
  25. package/dist/index.js +327 -152
  26. package/dist/index.js.map +1 -1
  27. package/dist/parser/article.d.ts +3 -2
  28. package/dist/parser/article.js +80 -12
  29. package/dist/parser/article.js.map +1 -1
  30. package/dist/parser/course.d.ts +1 -1
  31. package/dist/parser/course.js +88 -28
  32. package/dist/parser/course.js.map +1 -1
  33. package/dist/parser/frontmatter.d.ts +1 -1
  34. package/dist/parser/frontmatter.js +38 -12
  35. package/dist/parser/frontmatter.js.map +1 -1
  36. package/dist/parser/learning-outcome.d.ts +12 -2
  37. package/dist/parser/learning-outcome.js +177 -96
  38. package/dist/parser/learning-outcome.js.map +1 -1
  39. package/dist/parser/lens.d.ts +52 -28
  40. package/dist/parser/lens.js +283 -260
  41. package/dist/parser/lens.js.map +1 -1
  42. package/dist/parser/module.d.ts +7 -15
  43. package/dist/parser/module.js +139 -170
  44. package/dist/parser/module.js.map +1 -1
  45. package/dist/parser/sections.d.ts +14 -1
  46. package/dist/parser/sections.js +94 -81
  47. package/dist/parser/sections.js.map +1 -1
  48. package/dist/parser/video-transcript.d.ts +2 -1
  49. package/dist/parser/video-transcript.js +10 -6
  50. package/dist/parser/video-transcript.js.map +1 -1
  51. package/dist/reference-graph.d.ts +8 -0
  52. package/dist/reference-graph.js +105 -0
  53. package/dist/reference-graph.js.map +1 -0
  54. package/dist/validator/card-module-membership.d.ts +2 -0
  55. package/dist/validator/card-module-membership.js +80 -0
  56. package/dist/validator/card-module-membership.js.map +1 -0
  57. package/dist/validator/directives.d.ts +12 -0
  58. package/dist/validator/directives.js +428 -0
  59. package/dist/validator/directives.js.map +1 -0
  60. package/dist/validator/field-values.js +14 -0
  61. package/dist/validator/field-values.js.map +1 -1
  62. package/dist/validator/output-integrity.js +5 -5
  63. package/dist/validator/output-integrity.js.map +1 -1
  64. package/dist/validator/segment-fields.d.ts +1 -1
  65. package/dist/validator/segment-fields.js +2 -2
  66. package/dist/validator/segment-fields.js.map +1 -1
  67. package/dist/validator/test-segments.d.ts +12 -0
  68. package/dist/validator/test-segments.js +40 -0
  69. package/dist/validator/test-segments.js.map +1 -0
  70. package/dist/validator/url-reachability.d.ts +2 -1
  71. package/dist/validator/url-reachability.js +42 -20
  72. package/dist/validator/url-reachability.js.map +1 -1
  73. package/dist/validator/uuid.js +9 -6
  74. package/dist/validator/uuid.js.map +1 -1
  75. package/package.json +1 -1
  76. package/dist/validator/chat-precedence.d.ts +0 -9
  77. package/dist/validator/chat-precedence.js +0 -32
  78. package/dist/validator/chat-precedence.js.map +0 -1
@@ -0,0 +1,428 @@
1
+ import { levenshtein } from './field-typos.js';
2
+ const SUPPORTED_DIRECTIVES = {
3
+ note: { container: true, leaf: true, text: true, open: false },
4
+ collapse: { container: true, leaf: false, text: true, open: false },
5
+ footnote: { container: false, leaf: true, text: true, open: false },
6
+ };
7
+ const UNSUPPORTED_NAMES = new Set([
8
+ 'warning', 'info', 'tip', 'caution', 'important',
9
+ 'danger', 'details', 'summary', 'aside', 'callout', 'admonition',
10
+ ]);
11
+ const ALL_DIRECTIVE_NAMES = new Set([...Object.keys(SUPPORTED_DIRECTIVES), ...UNSUPPORTED_NAMES]);
12
+ /**
13
+ * Check if a name is a near-miss typo of a supported directive name.
14
+ * Returns the closest match if levenshtein distance ≤ 2, else undefined.
15
+ */
16
+ function findNearMissDirective(name) {
17
+ let bestMatch;
18
+ let bestDist = Infinity;
19
+ for (const supported of Object.keys(SUPPORTED_DIRECTIVES)) {
20
+ const dist = levenshtein(name.toLowerCase(), supported);
21
+ if (dist > 0 && dist <= 2 && dist < bestDist) {
22
+ bestDist = dist;
23
+ bestMatch = supported;
24
+ }
25
+ }
26
+ return bestMatch;
27
+ }
28
+ // Regex patterns
29
+ const CONTAINER_OPEN = /^:::([\w-]+)(?:\{([^}]*)\})?/;
30
+ const CONTAINER_CLOSE_BARE = /^:::\s*$/;
31
+ const CONTAINER_CLOSE_ATTR = /^:::\s*\{([^}]*)\}/;
32
+ const CODE_FENCE = /^(?:```|~~~)/;
33
+ const LEAF_DIRECTIVE_PRE = /^::([\w-]+)(?:\{([^}]*)\})?\[/;
34
+ const LEAF_DIRECTIVE_POST = /^::([\w-]+)\[[^\]]*\]\{([^}]*)\}/;
35
+ const TEXT_DIRECTIVE_PRE = /(?:^|[^:]):(\w[\w-]*)(?:\{([^}]*)\})?\[/;
36
+ const TEXT_DIRECTIVE_POST = /(?:^|[^:]):(\w[\w-]*)\[[^\]]*\]\{([^}]*)\}/;
37
+ // Unclosed bracket patterns — match ::name[ or :name[ without closing ]
38
+ const LEAF_UNCLOSED = /^::([\w-]+)(?:\{[^}]*\})?\[[^\]]*$/;
39
+ const TEXT_UNCLOSED = /(?:^|[^:]):([\w][\w-]*)(?:\{[^}]*\})?\[[^\]]*$/;
40
+ /**
41
+ * Check if an attribute value looks like a typo of "open".
42
+ */
43
+ function isOpenTypo(attr) {
44
+ if (attr === 'open')
45
+ return false;
46
+ if (!attr)
47
+ return false;
48
+ // Case-insensitive match
49
+ if (attr.toLowerCase() === 'open')
50
+ return true;
51
+ // Contains = (like open=true)
52
+ if (attr.includes('=')) {
53
+ const key = attr.split('=')[0];
54
+ if (key.toLowerCase() === 'open')
55
+ return true;
56
+ }
57
+ // Levenshtein distance
58
+ if (levenshtein(attr.toLowerCase(), 'open') <= 2)
59
+ return true;
60
+ return false;
61
+ }
62
+ /**
63
+ * Check attribute validity on a supported directive and return warnings.
64
+ */
65
+ function checkAttribute(name, attr, file, line) {
66
+ const errors = [];
67
+ if (attr === undefined)
68
+ return errors;
69
+ const info = SUPPORTED_DIRECTIVES[name];
70
+ if (!info)
71
+ return errors;
72
+ if (attr === '') {
73
+ errors.push({
74
+ file,
75
+ line,
76
+ message: `Directive '${name}' has an empty attribute '{}'`,
77
+ suggestion: 'Remove the empty braces, or use {open} to make the directive open by default',
78
+ severity: 'warning',
79
+ });
80
+ return errors;
81
+ }
82
+ if (attr === 'open') {
83
+ // Valid attribute — but check if this directive supports it
84
+ if (!info.open) {
85
+ errors.push({
86
+ file,
87
+ line,
88
+ message: `Directive '${name}' does not support {open}`,
89
+ suggestion: `Remove {open} — '${name}' does not support the open attribute`,
90
+ severity: 'warning',
91
+ });
92
+ }
93
+ }
94
+ else if (isOpenTypo(attr)) {
95
+ errors.push({
96
+ file,
97
+ line,
98
+ message: `Possible attribute typo '{${attr}}' on directive '${name}'`,
99
+ suggestion: `Did you mean {open}?`,
100
+ severity: 'warning',
101
+ });
102
+ }
103
+ else {
104
+ // Completely unrecognized attribute
105
+ errors.push({
106
+ file,
107
+ line,
108
+ message: `Unrecognized attribute '{${attr}}' on directive '${name}'`,
109
+ suggestion: info.open ? `The only supported attribute is {open}` : `'${name}' does not support any attributes`,
110
+ severity: 'warning',
111
+ });
112
+ }
113
+ return errors;
114
+ }
115
+ /**
116
+ * Main validator for article body content.
117
+ * Checks for unclosed containers, unsupported names, empty containers,
118
+ * attribute typos, and {open} on closing markers.
119
+ */
120
+ export function validateDirectives(body, file, bodyStartLine) {
121
+ const errors = [];
122
+ const lines = body.split('\n');
123
+ const stack = [];
124
+ let inCodeBlock = false;
125
+ for (let i = 0; i < lines.length; i++) {
126
+ const line = lines[i];
127
+ const absLine = bodyStartLine + i;
128
+ // Toggle code block state
129
+ if (CODE_FENCE.test(line)) {
130
+ inCodeBlock = !inCodeBlock;
131
+ continue;
132
+ }
133
+ if (inCodeBlock)
134
+ continue;
135
+ // Check container close with attribute (error: {open} on closing marker)
136
+ const closeAttrMatch = line.match(CONTAINER_CLOSE_ATTR);
137
+ if (closeAttrMatch) {
138
+ const attrOnClose = closeAttrMatch[1];
139
+ const top = stack.pop();
140
+ if (top) {
141
+ errors.push({
142
+ file,
143
+ line: absLine,
144
+ message: `Attribute {${attrOnClose}} on closing ':::' marker has no effect`,
145
+ suggestion: `Move to opening marker: :::${top.name}{${attrOnClose}}`,
146
+ severity: 'error',
147
+ });
148
+ // Check empty container
149
+ if (!top.hasContent) {
150
+ errors.push({
151
+ file,
152
+ line: top.line,
153
+ message: `Empty container directive ':::${top.name}' has no content`,
154
+ suggestion: 'Add content between the opening and closing markers',
155
+ severity: 'warning',
156
+ });
157
+ }
158
+ }
159
+ continue;
160
+ }
161
+ // Check bare container close
162
+ if (CONTAINER_CLOSE_BARE.test(line)) {
163
+ const top = stack.pop();
164
+ if (top && !top.hasContent) {
165
+ errors.push({
166
+ file,
167
+ line: top.line,
168
+ message: `Empty container directive ':::${top.name}' has no content`,
169
+ suggestion: 'Add content between the opening and closing markers',
170
+ severity: 'warning',
171
+ });
172
+ }
173
+ continue;
174
+ }
175
+ // Check container open
176
+ const openMatch = line.match(CONTAINER_OPEN);
177
+ if (openMatch) {
178
+ const name = openMatch[1];
179
+ const attr = openMatch[2];
180
+ if (UNSUPPORTED_NAMES.has(name)) {
181
+ errors.push({
182
+ file,
183
+ line: absLine,
184
+ message: `Unsupported directive ':::${name}'`,
185
+ suggestion: `Supported container directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.container).map(([k]) => k).join(', ')}`,
186
+ severity: 'error',
187
+ });
188
+ }
189
+ else if (SUPPORTED_DIRECTIVES[name]) {
190
+ if (!SUPPORTED_DIRECTIVES[name].container) {
191
+ errors.push({
192
+ file,
193
+ line: absLine,
194
+ message: `Directive '${name}' does not support the container ':::' form`,
195
+ suggestion: `Use the leaf form '::${name}[text]' or inline form ':${name}[text]' instead`,
196
+ severity: 'error',
197
+ });
198
+ }
199
+ errors.push(...checkAttribute(name, attr, file, absLine));
200
+ }
201
+ else {
202
+ const nearMiss = findNearMissDirective(name);
203
+ if (nearMiss) {
204
+ errors.push({
205
+ file,
206
+ line: absLine,
207
+ message: `Unknown directive ':::${name}' — did you mean ':::${nearMiss}'?`,
208
+ suggestion: `Supported container directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.container).map(([k]) => k).join(', ')}`,
209
+ severity: 'error',
210
+ });
211
+ }
212
+ }
213
+ stack.push({ name, line: absLine, hasContent: false });
214
+ continue;
215
+ }
216
+ // Check leaf directive (::name[...)
217
+ // First check for unclosed bracket: ::name[ without ]
218
+ const leafUnclosedMatch = line.match(LEAF_UNCLOSED);
219
+ if (leafUnclosedMatch) {
220
+ const name = leafUnclosedMatch[1];
221
+ if (SUPPORTED_DIRECTIVES[name] || UNSUPPORTED_NAMES.has(name) || findNearMissDirective(name)) {
222
+ errors.push({
223
+ file,
224
+ line: absLine,
225
+ message: `Unclosed bracket in leaf directive '::${name}[' — missing closing ']'`,
226
+ suggestion: `Add a closing bracket: ::${name}[content]`,
227
+ severity: 'error',
228
+ });
229
+ if (stack.length > 0) {
230
+ stack[stack.length - 1].hasContent = true;
231
+ }
232
+ continue;
233
+ }
234
+ }
235
+ // Try POST first to capture post-bracket attributes, fall back to PRE
236
+ const leafMatchPost = line.match(LEAF_DIRECTIVE_POST);
237
+ const leafMatchPre = line.match(LEAF_DIRECTIVE_PRE);
238
+ const leafMatch = leafMatchPost ?? leafMatchPre;
239
+ if (leafMatch) {
240
+ const name = leafMatch[1];
241
+ // Prefer post-bracket attr if available
242
+ const attr = leafMatchPost?.[2] ?? leafMatchPre?.[2];
243
+ if (UNSUPPORTED_NAMES.has(name)) {
244
+ errors.push({
245
+ file,
246
+ line: absLine,
247
+ message: `Unsupported directive '::${name}'`,
248
+ suggestion: `Supported leaf directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.leaf).map(([k]) => k).join(', ')}`,
249
+ severity: 'error',
250
+ });
251
+ }
252
+ else if (SUPPORTED_DIRECTIVES[name]) {
253
+ if (!SUPPORTED_DIRECTIVES[name].leaf) {
254
+ errors.push({
255
+ file,
256
+ line: absLine,
257
+ message: `Directive '${name}' does not support the leaf '::' form`,
258
+ suggestion: `Use the container form ':::${name}' or inline form ':${name}[text]' instead`,
259
+ severity: 'warning',
260
+ });
261
+ }
262
+ errors.push(...checkAttribute(name, attr, file, absLine));
263
+ }
264
+ else {
265
+ const nearMiss = findNearMissDirective(name);
266
+ if (nearMiss) {
267
+ errors.push({
268
+ file,
269
+ line: absLine,
270
+ message: `Unknown directive '::${name}' — did you mean '::${nearMiss}'?`,
271
+ suggestion: `Supported leaf directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.leaf).map(([k]) => k).join(', ')}`,
272
+ severity: 'error',
273
+ });
274
+ }
275
+ }
276
+ // Mark parent container as having content
277
+ if (stack.length > 0) {
278
+ stack[stack.length - 1].hasContent = true;
279
+ }
280
+ continue;
281
+ }
282
+ // Check for unclosed text directive brackets (:name[ without ])
283
+ const textUnclosedMatches = line.matchAll(new RegExp(TEXT_UNCLOSED, 'g'));
284
+ for (const m of textUnclosedMatches) {
285
+ const name = m[1];
286
+ const matchIndex = m.index;
287
+ const beforeMatch = line.substring(0, matchIndex + (m[0].startsWith(':') ? 0 : 1));
288
+ if (/https?$|ftp$|mailto$|tel$/.test(beforeMatch))
289
+ continue;
290
+ if (SUPPORTED_DIRECTIVES[name] || UNSUPPORTED_NAMES.has(name) || findNearMissDirective(name)) {
291
+ errors.push({
292
+ file,
293
+ line: absLine,
294
+ message: `Unclosed bracket in text directive ':${name}[' — missing closing ']'`,
295
+ suggestion: `Add a closing bracket: :${name}[content]`,
296
+ severity: 'error',
297
+ });
298
+ }
299
+ }
300
+ // Check text/inline directive (:name[...)
301
+ // Must not be preceded by another colon (to avoid matching ::name)
302
+ // Check both :name{attr}[text] and :name[text]{attr} forms
303
+ const seenTextDirectives = new Set(); // track by match index to avoid duplicates
304
+ // Check POST first so :name[text]{attr} captures the attribute before PRE sees it without attr
305
+ for (const pattern of [TEXT_DIRECTIVE_POST, TEXT_DIRECTIVE_PRE]) {
306
+ const textMatches = line.matchAll(new RegExp(pattern, 'g'));
307
+ for (const textMatch of textMatches) {
308
+ const matchIndex = textMatch.index;
309
+ if (seenTextDirectives.has(matchIndex))
310
+ continue;
311
+ seenTextDirectives.add(matchIndex);
312
+ const name = textMatch[1];
313
+ const attr = textMatch[2];
314
+ // Skip URL-like patterns (http:, https:, ftp:, etc.)
315
+ const beforeMatch = line.substring(0, matchIndex + (textMatch[0].startsWith(':') ? 0 : 1));
316
+ if (/https?$|ftp$|mailto$|tel$/.test(beforeMatch))
317
+ continue;
318
+ if (UNSUPPORTED_NAMES.has(name)) {
319
+ errors.push({
320
+ file,
321
+ line: absLine,
322
+ message: `Unsupported directive ':${name}'`,
323
+ suggestion: `Supported text directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.text).map(([k]) => k).join(', ')}`,
324
+ severity: 'error',
325
+ });
326
+ }
327
+ else if (SUPPORTED_DIRECTIVES[name]) {
328
+ errors.push(...checkAttribute(name, attr, file, absLine));
329
+ }
330
+ else {
331
+ const nearMiss = findNearMissDirective(name);
332
+ if (nearMiss) {
333
+ errors.push({
334
+ file,
335
+ line: absLine,
336
+ message: `Unknown directive ':${name}' — did you mean ':${nearMiss}'?`,
337
+ suggestion: `Supported text directives: ${Object.entries(SUPPORTED_DIRECTIVES).filter(([, v]) => v.text).map(([k]) => k).join(', ')}`,
338
+ severity: 'error',
339
+ });
340
+ }
341
+ }
342
+ // Mark parent container as having content
343
+ if (stack.length > 0) {
344
+ stack[stack.length - 1].hasContent = true;
345
+ }
346
+ }
347
+ }
348
+ // Mark content in parent container (non-blank, non-directive line)
349
+ if (stack.length > 0 && line.trim() !== '') {
350
+ stack[stack.length - 1].hasContent = true;
351
+ }
352
+ }
353
+ // Report unclosed containers
354
+ for (const entry of stack) {
355
+ errors.push({
356
+ file,
357
+ line: entry.line,
358
+ message: `Unclosed container directive ':::${entry.name}'`,
359
+ suggestion: 'Add a closing ::: marker',
360
+ severity: 'error',
361
+ });
362
+ }
363
+ return errors;
364
+ }
365
+ /**
366
+ * Lightweight check for directives in non-article content (e.g., lens text segments).
367
+ * Returns a single warning per match since directives won't render outside articles.
368
+ */
369
+ export function detectDirectivesInNonArticle(content, file, line) {
370
+ const lines = content.split('\n');
371
+ let inCodeBlock = false;
372
+ for (const l of lines) {
373
+ if (CODE_FENCE.test(l)) {
374
+ inCodeBlock = !inCodeBlock;
375
+ continue;
376
+ }
377
+ if (inCodeBlock)
378
+ continue;
379
+ // Container directive
380
+ if (CONTAINER_OPEN.test(l)) {
381
+ const match = l.match(CONTAINER_OPEN);
382
+ if (ALL_DIRECTIVE_NAMES.has(match[1])) {
383
+ return [{
384
+ file,
385
+ line,
386
+ message: `Directive ':::${match[1]}' found in non-article content — directives only render in article files`,
387
+ suggestion: 'Move this content to an article file (articles/*.md) or remove the directive syntax',
388
+ severity: 'warning',
389
+ }];
390
+ }
391
+ }
392
+ // Leaf directive
393
+ const leafMatch = l.match(LEAF_DIRECTIVE_PRE);
394
+ if (leafMatch && ALL_DIRECTIVE_NAMES.has(leafMatch[1])) {
395
+ return [{
396
+ file,
397
+ line,
398
+ message: `Directive '::${leafMatch[1]}' found in non-article content — directives only render in article files`,
399
+ suggestion: 'Move this content to an article file (articles/*.md) or remove the directive syntax',
400
+ severity: 'warning',
401
+ }];
402
+ }
403
+ // Text/inline directive — scan for :name[ patterns (both pre and post attribute forms)
404
+ for (const pattern of [TEXT_DIRECTIVE_PRE, TEXT_DIRECTIVE_POST]) {
405
+ const textRegex = new RegExp(pattern, 'g');
406
+ let textMatch;
407
+ while ((textMatch = textRegex.exec(l)) !== null) {
408
+ const name = textMatch[1];
409
+ // Skip URL-like patterns
410
+ const matchIndex = textMatch.index;
411
+ const beforeMatch = l.substring(0, matchIndex + (textMatch[0].startsWith(':') ? 0 : 1));
412
+ if (/https?$|ftp$|mailto$|tel$/.test(beforeMatch))
413
+ continue;
414
+ if (ALL_DIRECTIVE_NAMES.has(name)) {
415
+ return [{
416
+ file,
417
+ line,
418
+ message: `Directive ':${name}' found in non-article content — directives only render in article files`,
419
+ suggestion: 'Move this content to an article file (articles/*.md) or remove the directive syntax',
420
+ severity: 'warning',
421
+ }];
422
+ }
423
+ }
424
+ }
425
+ }
426
+ return [];
427
+ }
428
+ //# sourceMappingURL=directives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.js","sourceRoot":"","sources":["../../src/validator/directives.ts"],"names":[],"mappings":"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"}
@@ -60,6 +60,10 @@ export function validateSlugFormat(slug, file, line) {
60
60
  }
61
61
  return null;
62
62
  }
63
+ function isEmptyValue(value) {
64
+ const trimmed = value.trim();
65
+ return trimmed === '' || trimmed === '""' || trimmed === "''";
66
+ }
63
67
  /**
64
68
  * Validate field values, checking for appropriate types.
65
69
  * Currently validates that boolean fields contain 'true' or 'false'.
@@ -72,6 +76,16 @@ export function validateSlugFormat(slug, file, line) {
72
76
  export function validateFieldValues(fields, file, line) {
73
77
  const warnings = [];
74
78
  for (const [name, value] of Object.entries(fields)) {
79
+ // Check for empty 'from' field
80
+ if (name === 'from' && isEmptyValue(value)) {
81
+ warnings.push({
82
+ file,
83
+ line,
84
+ message: `Field 'from' is empty and can be omitted`,
85
+ suggestion: 'Without a from:: field, the content shows from the start',
86
+ severity: 'warning',
87
+ });
88
+ }
75
89
  // Check if this is a boolean field
76
90
  if (ALL_BOOLEAN_FIELDS.includes(name)) {
77
91
  const normalizedValue = value.toLowerCase();
@@ -1 +1 @@
1
- {"version":3,"file":"field-values.js","sourceRoot":"","sources":["../../src/validator/field-values.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;GAGG;AACH,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,IAAY,EACZ,IAAY;IAEZ,4DAA4D;IAC5D,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,+BAA+B;YACpE,UAAU,EAAE,4BAA4B,IAAI,CAAC,WAAW,EAAE,GAAG;YAC7D,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,+BAA+B;YACpE,UAAU,EAAE,2BAA2B;YACvC,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,6BAA6B;YAClE,UAAU,EAAE,4BAA4B;YACxC,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,8DAA8D;YACnG,UAAU,EAAE,oCAAoC;YAChD,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA8B,EAC9B,IAAY,EACZ,IAAY;IAEZ,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,mCAAmC;QACnC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,eAAe,KAAK,MAAM,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;gBAC9D,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI;oBACJ,IAAI;oBACJ,OAAO,EAAE,UAAU,IAAI,4BAA4B,KAAK,GAAG;oBAC3D,UAAU,EAAE,4BAA4B;oBACxC,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"field-values.js","sourceRoot":"","sources":["../../src/validator/field-values.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;GAGG;AACH,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAEtD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,IAAY,EACZ,IAAY;IAEZ,4DAA4D;IAC5D,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,+BAA+B;YACpE,UAAU,EAAE,4BAA4B,IAAI,CAAC,WAAW,EAAE,GAAG;YAC7D,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,+BAA+B;YACpE,UAAU,EAAE,2BAA2B;YACvC,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,6BAA6B;YAClE,UAAU,EAAE,4BAA4B;YACxC,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,OAAO;YACL,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,wBAAwB,IAAI,8DAA8D;YACnG,UAAU,EAAE,oCAAoC;YAChD,QAAQ,EAAE,OAAO;SAClB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,OAAO,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC;AAChE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA8B,EAC9B,IAAY,EACZ,IAAY;IAEZ,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,+BAA+B;QAC/B,IAAI,IAAI,KAAK,MAAM,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,IAAI;gBACJ,OAAO,EAAE,0CAA0C;gBACnD,UAAU,EACR,0DAA0D;gBAC5D,QAAQ,EAAE,SAAS;aACpB,CAAC,CAAC;QACL,CAAC;QAED,mCAAmC;QACnC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,eAAe,KAAK,MAAM,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;gBAC9D,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI;oBACJ,IAAI;oBACJ,OAAO,EAAE,UAAU,IAAI,4BAA4B,KAAK,GAAG;oBAC3D,UAAU,EAAE,4BAA4B;oBACxC,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -29,20 +29,20 @@ export function validateOutputIntegrity(modules, slugToPath) {
29
29
  });
30
30
  }
31
31
  break;
32
- case 'article-excerpt':
32
+ case 'article':
33
33
  if (!segment.content?.trim()) {
34
34
  errors.push({
35
35
  file,
36
- message: `Empty article-excerpt segment in "${sectionLabel}" (segment ${i + 1})`,
36
+ message: `Empty article segment in "${sectionLabel}" (segment ${i + 1})`,
37
37
  severity: 'error',
38
38
  });
39
39
  }
40
40
  break;
41
- case 'video-excerpt':
42
- if (!segment.transcript?.trim()) {
41
+ case 'video':
42
+ if (!segment.transcript?.length) {
43
43
  errors.push({
44
44
  file,
45
- message: `Empty video-excerpt transcript in "${sectionLabel}" (segment ${i + 1})`,
45
+ message: `Empty video transcript in "${sectionLabel}" (segment ${i + 1})`,
46
46
  severity: 'error',
47
47
  });
48
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"output-integrity.js","sourceRoot":"","sources":["../../src/validator/output-integrity.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAA0B,EAC1B,UAAgC;IAEhC,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC;QAEzD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAExD,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI;oBACJ,OAAO,EAAE,YAAY,YAAY,mBAAmB;oBACpD,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAEpC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;oBACrB,KAAK,MAAM;wBACT,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;4BAC7B,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,0BAA0B,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCACrE,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,KAAK,iBAAiB;wBACpB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;4BAC7B,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,qCAAqC,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCAChF,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,KAAK,eAAe;wBAClB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;4BAChC,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,sCAAsC,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCACjF,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,8CAA8C;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"output-integrity.js","sourceRoot":"","sources":["../../src/validator/output-integrity.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAA0B,EAC1B,UAAgC;IAEhC,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC;QAEzD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAExD,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI;oBACJ,OAAO,EAAE,YAAY,YAAY,mBAAmB;oBACpD,QAAQ,EAAE,OAAO;iBAClB,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBAEpC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;oBACrB,KAAK,MAAM;wBACT,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;4BAC7B,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,0BAA0B,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCACrE,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,KAAK,SAAS;wBACZ,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;4BAC7B,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,6BAA6B,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCACxE,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,KAAK,OAAO;wBACV,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;4BAChC,MAAM,CAAC,IAAI,CAAC;gCACV,IAAI;gCACJ,OAAO,EAAE,8BAA8B,YAAY,cAAc,CAAC,GAAG,CAAC,GAAG;gCACzE,QAAQ,EAAE,OAAO;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM;oBACR,8CAA8C;gBAChD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -3,7 +3,7 @@ import type { ContentError } from '../index.js';
3
3
  * Validate that fields are appropriate for the segment type.
4
4
  * Warns about fields that belong to different segment types.
5
5
  *
6
- * @param segmentType - The type of segment (text, chat, article-excerpt, video-excerpt)
6
+ * @param segmentType - The type of segment (text, chat, article, video, question, roleplay)
7
7
  * @param fields - Object mapping field names to their values
8
8
  * @param file - File path for error reporting
9
9
  * @param line - Line number for error reporting
@@ -7,7 +7,7 @@ const EXCERPT_ONLY_FIELDS = new Set(['from', 'to']);
7
7
  * Validate that fields are appropriate for the segment type.
8
8
  * Warns about fields that belong to different segment types.
9
9
  *
10
- * @param segmentType - The type of segment (text, chat, article-excerpt, video-excerpt)
10
+ * @param segmentType - The type of segment (text, chat, article, video, question, roleplay)
11
11
  * @param fields - Object mapping field names to their values
12
12
  * @param file - File path for error reporting
13
13
  * @param line - Line number for error reporting
@@ -28,7 +28,7 @@ export function validateSegmentFields(segmentType, fields, file, line) {
28
28
  file,
29
29
  line,
30
30
  message: `Field '${fieldName}' is not valid in ${segmentType} segment`,
31
- suggestion: `'${fieldName}' is only valid in article-excerpt or video-excerpt segments`,
31
+ suggestion: `'${fieldName}' is only valid in article or video segments`,
32
32
  severity: 'warning',
33
33
  });
34
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"segment-fields.js","sourceRoot":"","sources":["../../src/validator/segment-fields.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAEpE;;GAEG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,WAAmB,EACnB,MAA8B,EAC9B,IAAY,EACZ,IAAY;IAEZ,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,4BAA4B,CAAC,WAAW,CAAC,CAAC;IAE9D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,sDAAsD;QACtD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,oEAAoE;YACpE,IAAI,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvC,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI;oBACJ,IAAI;oBACJ,OAAO,EAAE,UAAU,SAAS,qBAAqB,WAAW,UAAU;oBACtE,UAAU,EAAE,IAAI,SAAS,8DAA8D;oBACvF,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;YACD,2DAA2D;YAC3D,mCAAmC;QACrC,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"segment-fields.js","sourceRoot":"","sources":["../../src/validator/segment-fields.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AAEpE;;GAEG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AAEpD;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,WAAmB,EACnB,MAA8B,EAC9B,IAAY,EACZ,IAAY;IAEZ,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,4BAA4B,CAAC,WAAW,CAAC,CAAC;IAE9D,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,sDAAsD;QACtD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,oEAAoE;YACpE,IAAI,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvC,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI;oBACJ,IAAI;oBACJ,OAAO,EAAE,UAAU,SAAS,qBAAqB,WAAW,UAAU;oBACtE,UAAU,EAAE,IAAI,SAAS,8CAA8C;oBACvE,QAAQ,EAAE,SAAS;iBACpB,CAAC,CAAC;YACL,CAAC;YACD,2DAA2D;YAC3D,mCAAmC;QACrC,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ContentError } from "../index.js";
2
+ import type { ParsedSection } from "../parser/sections.js";
3
+ /**
4
+ * Validate that an LO Test section contains only assessable segment types.
5
+ * Flags non-assessable segments (text/article/video/chat) as errors, since
6
+ * they are silently discarded by every consumer.
7
+ *
8
+ * @param segments - The raw segments parsed from the Test section body
9
+ * @param file - File path for error reporting
10
+ * @returns Array of error ContentError objects for disallowed segments
11
+ */
12
+ export declare function validateTestSegments(segments: ParsedSection[], file: string): ContentError[];
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Segment types that an LO `## Test:` section may contain.
3
+ *
4
+ * A Test is an assessment: only `question` and `roleplay` segments are rendered
5
+ * to the student (web_frontend TestSection.tsx) and scored by the grader
6
+ * (core/assessment.py) / tutor (core/modules/tutor_scenario.py). Any other
7
+ * segment type (text, article, video, chat) placed in a Test is silently
8
+ * dropped everywhere — never shown and never sent to the model — so it is
9
+ * almost always an authoring mistake (e.g. intro text that belongs inside the
10
+ * question's content::).
11
+ */
12
+ const ASSESSABLE_TEST_SEGMENT_TYPES = new Set(["question", "roleplay"]);
13
+ /**
14
+ * Validate that an LO Test section contains only assessable segment types.
15
+ * Flags non-assessable segments (text/article/video/chat) as errors, since
16
+ * they are silently discarded by every consumer.
17
+ *
18
+ * @param segments - The raw segments parsed from the Test section body
19
+ * @param file - File path for error reporting
20
+ * @returns Array of error ContentError objects for disallowed segments
21
+ */
22
+ export function validateTestSegments(segments, file) {
23
+ const errors = [];
24
+ for (const segment of segments) {
25
+ if (ASSESSABLE_TEST_SEGMENT_TYPES.has(segment.type))
26
+ continue;
27
+ const suggestion = segment.type === "text"
28
+ ? "Move this text into the following Question's content:: field — a Test only renders question/roleplay segments, so a standalone Text is never shown to students or sent to the grader."
29
+ : `A Test section only renders question/roleplay segments. Remove this '${segment.type}' segment, or move it into a Lens.`;
30
+ errors.push({
31
+ file,
32
+ line: segment.line,
33
+ message: `Test section contains a '${segment.type}' segment, which is silently dropped (not rendered to students, not sent to the grader or tutor). A Test may only contain question or roleplay segments.`,
34
+ suggestion,
35
+ severity: "error",
36
+ });
37
+ }
38
+ return errors;
39
+ }
40
+ //# sourceMappingURL=test-segments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-segments.js","sourceRoot":"","sources":["../../src/validator/test-segments.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;AAExE;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAyB,EACzB,IAAY;IAEZ,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,6BAA6B,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QAE9D,MAAM,UAAU,GACd,OAAO,CAAC,IAAI,KAAK,MAAM;YACrB,CAAC,CAAC,uLAAuL;YACzL,CAAC,CAAC,wEAAwE,OAAO,CAAC,IAAI,oCAAoC,CAAC;QAE/H,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,4BAA4B,OAAO,CAAC,IAAI,0JAA0J;YAC3M,UAAU;YACV,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,8 +1,9 @@
1
- import type { ContentError } from '../index.js';
1
+ import type { ContentError } from "../index.js";
2
2
  export interface UrlToValidate {
3
3
  url: string;
4
4
  file: string;
5
5
  line: number;
6
6
  label: string;
7
+ allowUnreachable?: boolean;
7
8
  }
8
9
  export declare function validateUrls(urls: UrlToValidate[]): Promise<ContentError[]>;