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
@@ -1,75 +1,101 @@
1
1
  import { ALL_KNOWN_FIELDS } from '../content-schema.js';
2
2
  import { levenshtein } from '../validator/field-typos.js';
3
3
  // Valid section types per file type (exported for use by other parsers)
4
- export const MODULE_SECTION_TYPES = new Set(['learning outcome', 'page', 'uncategorized']);
4
+ export const MODULE_SECTION_TYPES = new Set(['learning outcome', 'lens']);
5
5
  export const LO_SECTION_TYPES = new Set(['lens', 'test']);
6
- // Lens sections: input headers are `### Article:`, `### Video:`, `### Page:`
7
- // Output types are `lens-article`, `lens-video`, `page` (v2 format)
6
+ // Legacy: Lens H3 section types (no longer used lenses are now flat H4 segments)
8
7
  export const LENS_SECTION_TYPES = new Set(['page', 'article', 'video']);
9
8
  // All known structural header types (sections + segments) for markdown heading detection
10
9
  const ALL_STRUCTURAL_TYPES = new Set([
11
10
  // Section types
12
- 'learning outcome', 'page', 'uncategorized', 'lens', 'test', 'module', 'meeting', 'article', 'video',
11
+ 'learning outcome', 'lens', 'test', 'module', 'meeting', 'article', 'video',
13
12
  // Segment types
14
- 'text', 'chat', 'article-excerpt', 'video-excerpt', 'question',
13
+ 'text', 'chat', 'question', 'roleplay',
15
14
  ]);
16
15
  // Fields that commonly contain markdown with headings
17
- const MARKDOWN_CONTENT_FIELDS = new Set(['content', 'instructions']);
16
+ const MARKDOWN_CONTENT_FIELDS = new Set(['content', 'instructions', 'ai-instructions']);
18
17
  // Map input section names to output types for Lens files
19
18
  export const LENS_OUTPUT_TYPE = {
20
19
  'page': 'page',
21
20
  'article': 'lens-article',
22
21
  'video': 'lens-video',
23
22
  };
24
- // Header pattern is parameterized by level (1-4)
25
- function makeSectionPattern(level) {
26
- const hashes = '#'.repeat(level);
27
- // Match: ^#{level} <type> OR ^#{level} <type>: <optional title>
28
- // Captures: group 1 = type, group 2 = title (may be undefined)
29
- return new RegExp(`^${hashes}\\s+([^:]+?)(?::\\s*(.*))?$`, 'i');
30
- }
31
- // Note: unrecognized headers are now caught by makeSectionPattern matching all
32
- // ### headers, with unknown types reported as "Unknown section type" errors.
33
- export function parseSections(content, headerLevel, validTypes, file = '') {
34
- const SECTION_HEADER_PATTERN = makeSectionPattern(headerLevel);
35
- // Build patterns for adjacent levels to detect wrong heading level
36
- const wrongLevelPatterns = [];
37
- for (const adjLevel of [headerLevel - 1, headerLevel + 1]) {
38
- if (adjLevel >= 1 && adjLevel <= 4) {
39
- wrongLevelPatterns.push({ pattern: makeSectionPattern(adjLevel), level: adjLevel });
40
- }
41
- }
23
+ /**
24
+ * Parse sections from markdown content based on header hierarchy.
25
+ *
26
+ * @param content - The markdown body to parse
27
+ * @param parentLevel - Headers deeper than this level are candidates (0 = match any header)
28
+ * @param validTypes - Set of valid section/segment type names
29
+ * @param file - Source file path for error reporting
30
+ * @param flat - When true, all matching headers are siblings (for segments).
31
+ * When false, deeper headers nest inside preceding siblings (for sections).
32
+ */
33
+ export function parseSections(content, parentLevel, validTypes, file = '', flat = false) {
34
+ const minLevel = parentLevel + 1;
35
+ // Match any header from minLevel to 6 with named capture groups
36
+ const HEADER_PATTERN = new RegExp(`^(?<hashes>#{${minLevel},6})\\s+(?<type>[^:]+?)(?:\\:\\s*(?<title>.*?))?\\s*$`, 'i');
42
37
  const lines = content.split('\n');
43
38
  const sections = [];
44
39
  const errors = [];
45
40
  let currentSection = null;
46
41
  let currentBody = [];
47
42
  let preHeaderWarned = false;
43
+ let currentSiblingLevel = 0; // Track sibling level for hierarchical mode
44
+ function finalizeSection() {
45
+ if (!currentSection)
46
+ return;
47
+ currentSection.body = currentBody.join('\n');
48
+ const { warnings } = parseFields(currentSection, file);
49
+ errors.push(...warnings);
50
+ // Submodule sections get recursive children parsing
51
+ if (currentSection.type === 'submodule') {
52
+ const childValidTypes = new Set([...validTypes]);
53
+ childValidTypes.delete('submodule'); // No nesting
54
+ const childResult = parseSections(currentSection.body, currentSection.level, childValidTypes, file);
55
+ currentSection.children = childResult.sections;
56
+ errors.push(...childResult.errors);
57
+ }
58
+ sections.push(currentSection);
59
+ }
48
60
  for (let i = 0; i < lines.length; i++) {
49
61
  const line = lines[i];
50
62
  const lineNum = i + 1;
51
- const headerMatch = line.match(SECTION_HEADER_PATTERN);
63
+ const headerMatch = line.match(HEADER_PATTERN);
52
64
  if (headerMatch) {
53
- // Save previous section
54
- if (currentSection) {
55
- currentSection.body = currentBody.join('\n');
56
- const { warnings } = parseFields(currentSection, file);
57
- errors.push(...warnings);
58
- sections.push(currentSection);
59
- }
60
- const rawType = headerMatch[1].trim();
65
+ const hashes = headerMatch.groups.hashes;
66
+ const headerLevel = hashes.length;
67
+ const rawType = headerMatch.groups.type.trim();
61
68
  const normalizedType = rawType.toLowerCase();
62
- const title = (headerMatch[2] ?? '').trim();
69
+ const title = (headerMatch.groups.title ?? '').trim();
70
+ // Check if this type is valid for the current context
63
71
  if (!validTypes.has(normalizedType)) {
64
- const capitalized = [...validTypes].map(t => t.split(' ').map(w => w[0].toUpperCase() + w.slice(1)).join(' '));
65
- errors.push({
66
- file,
67
- line: lineNum,
68
- message: `Unknown section type: ${rawType}`,
69
- suggestion: `Valid types: ${capitalized.join(', ')}`,
70
- severity: 'error',
71
- });
72
+ // Only error for unknown types at sibling level (not deeper body content)
73
+ const wouldBeSibling = flat || currentSiblingLevel === 0 || headerLevel <= currentSiblingLevel;
74
+ if (wouldBeSibling) {
75
+ const capitalized = [...validTypes].map(t => t.split(' ').map(w => w[0].toUpperCase() + w.slice(1)).join(' '));
76
+ errors.push({
77
+ file,
78
+ line: lineNum,
79
+ message: `Unknown section type: ${rawType}`,
80
+ suggestion: `Valid types: ${capitalized.join(', ')}`,
81
+ severity: 'error',
82
+ });
83
+ }
84
+ // Treat as body content of current section
85
+ if (currentSection) {
86
+ currentBody.push(line);
87
+ }
88
+ continue;
72
89
  }
90
+ // Sibling boundary rule (hierarchical mode only):
91
+ // Deeper headers go into the preceding sibling's body
92
+ if (!flat && currentSiblingLevel > 0 && headerLevel > currentSiblingLevel) {
93
+ currentBody.push(line);
94
+ continue;
95
+ }
96
+ // New sibling — finalize previous section
97
+ finalizeSection();
98
+ currentSiblingLevel = headerLevel;
73
99
  currentSection = {
74
100
  type: normalizedType.replaceAll(' ', '-'),
75
101
  title,
@@ -77,54 +103,33 @@ export function parseSections(content, headerLevel, validTypes, file = '') {
77
103
  fields: {},
78
104
  body: '',
79
105
  line: lineNum,
106
+ level: headerLevel,
80
107
  };
81
108
  currentBody = [];
109
+ preHeaderWarned = false;
82
110
  }
83
111
  else {
84
112
  if (currentSection) {
85
113
  currentBody.push(line);
86
114
  }
87
- else if (!currentSection) {
88
- // Check for headers at wrong level that match known section types
89
- for (const { pattern, level } of wrongLevelPatterns) {
90
- const wrongMatch = line.match(pattern);
91
- if (wrongMatch) {
92
- const rawType = wrongMatch[1].trim();
93
- if (validTypes.has(rawType.toLowerCase())) {
94
- const expected = '#'.repeat(headerLevel);
95
- const actual = '#'.repeat(level);
96
- errors.push({
97
- file,
98
- line: lineNum,
99
- message: `Found '${actual} ${rawType}:' (heading level ${level}) but expected heading level ${headerLevel} (${expected} ${rawType}:)`,
100
- suggestion: `Change '${actual}' to '${expected}'`,
101
- severity: 'warning',
102
- });
103
- }
104
- break;
105
- }
115
+ else {
116
+ // Before first section header suppress warnings for field:: lines and blank lines
117
+ const isFieldLine = /^[\w-]+::\s/.test(line);
118
+ if (line.trim() && !isFieldLine && !preHeaderWarned) {
119
+ preHeaderWarned = true;
120
+ errors.push({
121
+ file,
122
+ line: lineNum,
123
+ message: 'Content found before first section header — this text will be ignored',
124
+ suggestion: 'Move this text into a section, or remove it',
125
+ severity: 'error',
126
+ });
106
127
  }
107
128
  }
108
- if (!currentSection && line.trim() && !preHeaderWarned) {
109
- // Non-blank content before any section header — will be silently lost
110
- preHeaderWarned = true;
111
- errors.push({
112
- file,
113
- line: lineNum,
114
- message: 'Content found before first section header — this text will be ignored',
115
- suggestion: 'Move this text into a section, or remove it',
116
- severity: 'warning',
117
- });
118
- }
119
129
  }
120
130
  }
121
131
  // Don't forget last section
122
- if (currentSection) {
123
- currentSection.body = currentBody.join('\n');
124
- const { warnings } = parseFields(currentSection, file);
125
- errors.push(...warnings);
126
- sections.push(currentSection);
127
- }
132
+ finalizeSection();
128
133
  return { sections, errors };
129
134
  }
130
135
  const FIELD_PATTERN = /^([\w-]+)::\s*(.*)$/;
@@ -187,7 +192,7 @@ function parseFields(section, file) {
187
192
  line: lineNum,
188
193
  message: `Duplicate field '${currentField}' (previous value will be overwritten)`,
189
194
  suggestion: `Remove the duplicate '${currentField}::' definition`,
190
- severity: 'warning',
195
+ severity: 'error',
191
196
  });
192
197
  }
193
198
  seenFields.add(currentField);
@@ -206,7 +211,7 @@ function parseFields(section, file) {
206
211
  line: lineNum,
207
212
  message: `Found '${singleColonMatch[1]}:' with single colon — did you mean '${singleColonMatch[1]}::'?`,
208
213
  suggestion: `Change '${singleColonMatch[1]}:' to '${singleColonMatch[1]}::' (double colon)`,
209
- severity: 'warning',
214
+ severity: 'error',
210
215
  });
211
216
  }
212
217
  else if (line.trim() && !freeTextWarned) {
@@ -217,7 +222,7 @@ function parseFields(section, file) {
217
222
  line: lineNum,
218
223
  message: `Text outside of a field:: definition will be ignored: "${preview}"`,
219
224
  suggestion: 'Place this text inside a field (e.g., content:: your text), or remove it',
220
- severity: 'warning',
225
+ severity: 'error',
221
226
  });
222
227
  }
223
228
  }
@@ -226,6 +231,14 @@ function parseFields(section, file) {
226
231
  if (currentField) {
227
232
  section.fields[currentField] = currentValue.join('\n').trim();
228
233
  }
234
+ // Unescape \# → # at start of lines in markdown content fields.
235
+ // Authors use \## to prevent the parser from treating ## as a structural header;
236
+ // the escape must be stripped before the content reaches consumers (e.g. ReactMarkdown).
237
+ for (const field of MARKDOWN_CONTENT_FIELDS) {
238
+ if (section.fields[field]) {
239
+ section.fields[field] = section.fields[field].replace(/^\\(#+)/gm, '$1');
240
+ }
241
+ }
229
242
  return { warnings };
230
243
  }
231
244
  //# sourceMappingURL=sections.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/parser/sections.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/parser/sections.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import type { ContentError } from '../index.js';
1
+ import type { ContentError } from "../index.js";
2
2
  export interface ParsedVideoTranscript {
3
3
  title: string;
4
4
  channel: string;
5
5
  url: string;
6
+ allowUnreachableUrl?: boolean;
6
7
  }
7
8
  export interface VideoTranscriptParseResult {
8
9
  transcript: ParsedVideoTranscript | null;
@@ -1,7 +1,10 @@
1
- import { parseFrontmatter } from './frontmatter.js';
2
- import { validateFrontmatter } from '../validator/validate-frontmatter.js';
1
+ import { parseFrontmatter } from "./frontmatter.js";
2
+ import { validateFrontmatter } from "../validator/validate-frontmatter.js";
3
+ import { stripAuthoringMarkup } from "./lens.js";
3
4
  export function parseVideoTranscript(content, file) {
4
5
  const errors = [];
6
+ // Strip authoring markup (CriticMarkup + Obsidian comments) before parsing
7
+ content = stripAuthoringMarkup(content);
5
8
  const frontmatterResult = parseFrontmatter(content, file);
6
9
  if (frontmatterResult.error) {
7
10
  errors.push(frontmatterResult.error);
@@ -9,14 +12,14 @@ export function parseVideoTranscript(content, file) {
9
12
  }
10
13
  const { frontmatter } = frontmatterResult;
11
14
  // Validate frontmatter against schema (typo detection + required fields)
12
- const frontmatterErrors = validateFrontmatter(frontmatter, 'video-transcript', file);
15
+ const frontmatterErrors = validateFrontmatter(frontmatter, "video-transcript", file);
13
16
  errors.push(...frontmatterErrors);
14
- const hasRequiredError = frontmatterErrors.some(e => e.severity === 'error');
17
+ const hasRequiredError = frontmatterErrors.some((e) => e.severity === "error");
15
18
  if (hasRequiredError) {
16
19
  return { transcript: null, errors };
17
20
  }
18
21
  // Check text fields for wikilinks (not url — that's a URL)
19
- const textFields = ['title', 'channel'];
22
+ const textFields = ["title", "channel"];
20
23
  for (const field of textFields) {
21
24
  const value = String(frontmatter[field]);
22
25
  if (/\[\[.+?\]\]/.test(value)) {
@@ -25,7 +28,7 @@ export function parseVideoTranscript(content, file) {
25
28
  line: 2,
26
29
  message: `Field '${field}' contains a wikilink — use plain text`,
27
30
  suggestion: `Remove [[...]] from '${field}'`,
28
- severity: 'error',
31
+ severity: "error",
29
32
  });
30
33
  }
31
34
  }
@@ -33,6 +36,7 @@ export function parseVideoTranscript(content, file) {
33
36
  title: String(frontmatter.title),
34
37
  channel: String(frontmatter.channel),
35
38
  url: String(frontmatter.url),
39
+ allowUnreachableUrl: frontmatter.allowUnreachableUrl === true,
36
40
  };
37
41
  return { transcript, errors };
38
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"video-transcript.js","sourceRoot":"","sources":["../../src/parser/video-transcript.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAa3E,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,IAAY;IAChE,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1D,IAAI,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,GAAG,iBAAiB,CAAC;IAE1C,yEAAyE;IACzE,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,WAAW,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAC;IACrF,MAAM,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;IAElC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC7E,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,2DAA2D;IAC3D,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC;IACjD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,UAAU,KAAK,wCAAwC;gBAChE,UAAU,EAAE,wBAAwB,KAAK,GAAG;gBAC5C,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAA0B;QACxC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC;KAC7B,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"video-transcript.js","sourceRoot":"","sources":["../../src/parser/video-transcript.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAgBjD,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,IAAY;IAEZ,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,2EAA2E;IAC3E,OAAO,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAExC,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1D,IAAI,iBAAiB,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACrC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,GAAG,iBAAiB,CAAC;IAE1C,yEAAyE;IACzE,MAAM,iBAAiB,GAAG,mBAAmB,CAC3C,WAAW,EACX,kBAAkB,EAClB,IAAI,CACL,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,CAAC;IAElC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,CAC7C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAC9B,CAAC;IACF,IAAI,gBAAgB,EAAE,CAAC;QACrB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAED,2DAA2D;IAC3D,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC;IACjD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,UAAU,KAAK,wCAAwC;gBAChE,UAAU,EAAE,wBAAwB,KAAK,GAAG;gBAC5C,QAAQ,EAAE,OAAO;aAClB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAA0B;QACxC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC;QAC5B,mBAAmB,EAAE,WAAW,CAAC,mBAAmB,KAAK,IAAI;KAC9D,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Map each file path to the sorted list of course slugs whose reference chain
3
+ * transitively reaches it. Files reached by no course are simply absent (an
4
+ * absent or empty list means "orphaned").
5
+ *
6
+ * @param files all content files (path -> raw markdown)
7
+ */
8
+ export declare function buildFileToCourses(files: Map<string, string>): Record<string, string[]>;
@@ -0,0 +1,105 @@
1
+ // src/reference-graph.ts
2
+ //
3
+ // Builds a file -> course-slugs map by walking the reference chain of each
4
+ // course (course -> module -> learning outcome -> lens -> article/transcript).
5
+ //
6
+ // Every reference in the content model is a wikilink: course->module sits in an
7
+ // H1 title, module->LO/lens and lens->article are `source::` embeds (`![[...]]`
8
+ // / `[[...]]`), and `::card[[...]]` links cross-reference lenses/modules. A
9
+ // single wikilink scan over the markup-stripped content therefore captures every
10
+ // edge type uniformly, with no per-parser wiring to drift out of sync.
11
+ //
12
+ // The scan is intentionally permissive (a wikilink in prose still counts as a
13
+ // reference). For the consumer — "which courses use this file / is it orphaned"
14
+ // — over-capture is the safe direction: it never marks a still-referenced file
15
+ // as orphaned.
16
+ import { resolveWikilinkPath, findFileWithExtension, } from "./parser/wikilink.js";
17
+ import { stripAuthoringMarkup } from "./parser/lens.js";
18
+ import { parseFrontmatter } from "./parser/frontmatter.js";
19
+ // Matches [[path]], [[path|alias]], [[path#anchor]] and (via the leading `[[`)
20
+ // the `![[...]]` / `::card[[...]]` forms too. Captures only the path segment.
21
+ const WIKILINK_RE = /\[\[\s*([^\]|#]+?)\s*(?:#[^\]|]*)?(?:\|[^\]]*)?\]\]/g;
22
+ function isCourseFile(path) {
23
+ return path.startsWith("courses/") || path.includes("/courses/");
24
+ }
25
+ function isTranscriptMd(path) {
26
+ return (path.endsWith(".md") &&
27
+ (path.startsWith("video_transcripts/") ||
28
+ path.includes("/video_transcripts/")));
29
+ }
30
+ /** Resolve every wikilink in `content` to a real file path in `files`. */
31
+ function outgoingReferences(path, content, files) {
32
+ const targets = new Set();
33
+ const stripped = stripAuthoringMarkup(content);
34
+ for (const match of stripped.matchAll(WIKILINK_RE)) {
35
+ const rawTarget = match[1].trim();
36
+ if (!rawTarget)
37
+ continue;
38
+ const resolved = resolveWikilinkPath(rawTarget, path);
39
+ const actual = findFileWithExtension(resolved, files);
40
+ if (actual && actual !== path)
41
+ targets.add(actual);
42
+ }
43
+ // A transcript's `.timestamps.json` is paired by filename, not wikilinked, but
44
+ // belongs to the same course as its `.md`, so carry it along.
45
+ if (isTranscriptMd(path)) {
46
+ const ts = path.replace(/\.md$/, ".timestamps.json");
47
+ if (files.has(ts))
48
+ targets.add(ts);
49
+ }
50
+ return targets;
51
+ }
52
+ /** Read a course file's frontmatter slug, or null if absent/unparseable. */
53
+ function courseSlug(path, content) {
54
+ const { frontmatter } = parseFrontmatter(stripAuthoringMarkup(content), path);
55
+ const slug = frontmatter.slug;
56
+ return typeof slug === "string" && slug.trim() ? slug.trim() : null;
57
+ }
58
+ /**
59
+ * Map each file path to the sorted list of course slugs whose reference chain
60
+ * transitively reaches it. Files reached by no course are simply absent (an
61
+ * absent or empty list means "orphaned").
62
+ *
63
+ * @param files all content files (path -> raw markdown)
64
+ */
65
+ export function buildFileToCourses(files) {
66
+ // 1. Adjacency: file -> files it references (resolved to real files only).
67
+ const adjacency = new Map();
68
+ for (const [path, content] of files.entries()) {
69
+ adjacency.set(path, outgoingReferences(path, content, files));
70
+ }
71
+ // 2. BFS from each course root, tagging every reached file with the slug.
72
+ const fileToCourses = new Map();
73
+ for (const [coursePath, courseContent] of files.entries()) {
74
+ if (!isCourseFile(coursePath))
75
+ continue;
76
+ const slug = courseSlug(coursePath, courseContent);
77
+ if (!slug)
78
+ continue; // course that failed to parse a slug — skip
79
+ const queue = [coursePath];
80
+ const seen = new Set([coursePath]);
81
+ // Head index instead of Array.shift() to keep the BFS dequeue O(1).
82
+ for (let head = 0; head < queue.length; head++) {
83
+ const file = queue[head];
84
+ let slugs = fileToCourses.get(file);
85
+ if (!slugs) {
86
+ slugs = new Set();
87
+ fileToCourses.set(file, slugs);
88
+ }
89
+ slugs.add(slug);
90
+ for (const next of adjacency.get(file) ?? []) {
91
+ if (!seen.has(next)) {
92
+ seen.add(next);
93
+ queue.push(next);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ // 3. Serialize to a stable, sorted plain object for JSON output.
99
+ const result = {};
100
+ for (const [file, slugs] of fileToCourses.entries()) {
101
+ result[file] = [...slugs].sort();
102
+ }
103
+ return result;
104
+ }
105
+ //# sourceMappingURL=reference-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-graph.js","sourceRoot":"","sources":["../src/reference-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ContentError, FlattenedModule } from '../index.js';
2
+ export declare function validateCardModuleMembership(modules: FlattenedModule[]): ContentError[];
@@ -0,0 +1,80 @@
1
+ const CARD_HTML_RE = /<div data-lens-card='([^']+)'><\/div>/g;
2
+ export function validateCardModuleMembership(modules) {
3
+ const errors = [];
4
+ // A module that contains `# Submodule:` boundaries is split into multiple
5
+ // FlattenedModules at flatten time (slug `parent/sub-1`, `parent/sub-2`, …),
6
+ // each carrying its own sections. From an authoring perspective these are
7
+ // still one curriculum unit — a hidden Lens import in one submodule should
8
+ // satisfy a card link from a sibling submodule. Group siblings by their
9
+ // parent slug for the membership check.
10
+ const groupContentIds = new Map();
11
+ for (const mod of modules) {
12
+ if (mod.slug.startsWith('lens/'))
13
+ continue;
14
+ const groupKey = mod.parentSlug ?? mod.slug;
15
+ let s = groupContentIds.get(groupKey);
16
+ if (!s) {
17
+ s = new Set();
18
+ groupContentIds.set(groupKey, s);
19
+ }
20
+ for (const section of mod.sections) {
21
+ if (section.contentId)
22
+ s.add(section.contentId);
23
+ }
24
+ }
25
+ for (const mod of modules) {
26
+ // Skip standalone-lens pseudo-modules (lens/ prefix). They are single-lens
27
+ // entries created for lenses not imported by any real module. Checking
28
+ // card membership from their narrow perspective generates false positives.
29
+ if (mod.slug.startsWith('lens/'))
30
+ continue;
31
+ const groupKey = mod.parentSlug ?? mod.slug;
32
+ const groupIds = groupContentIds.get(groupKey) ?? new Set();
33
+ for (const section of mod.sections) {
34
+ for (const seg of section.segments) {
35
+ if (seg.type !== 'text')
36
+ continue;
37
+ if (!seg.content.includes('data-lens-card='))
38
+ continue;
39
+ const matches = seg.content.matchAll(CARD_HTML_RE);
40
+ for (const match of matches) {
41
+ let data;
42
+ try {
43
+ data = JSON.parse(match[1].replace(/&#39;/g, "'"));
44
+ }
45
+ catch {
46
+ continue;
47
+ }
48
+ if (data.targetType !== 'lens')
49
+ continue;
50
+ const targetId = data.contentId;
51
+ if (!targetId)
52
+ continue; // missing contentId is a separate validation problem
53
+ if (groupIds.has(targetId))
54
+ continue; // same module-group: OK
55
+ if (data.allowExternal)
56
+ continue; // explicit external opt-in: OK
57
+ // Echo back the exact directive with the flag appended so the
58
+ // author can copy-paste it. Falls back to a `<path>` placeholder
59
+ // for older card data without targetPath.
60
+ const directive = data.targetPath
61
+ ? `\`::card[[${data.targetPath}]]{allow-external}\``
62
+ : '`::card[[<path>]]{allow-external}`';
63
+ errors.push({
64
+ // Card directives live inside the section's source — typically an
65
+ // imported Lens, not the module file itself. Prefer the section's
66
+ // sourcePath so the error points at the file the author needs to
67
+ // edit. Falls back to mod.sourcePath for inline lenses defined in
68
+ // the module file directly.
69
+ file: section.sourcePath ?? mod.sourcePath ?? `module:${mod.slug}`,
70
+ message: `Card targets Lens "${data.title ?? targetId}" which is not imported by module "${groupKey}".`,
71
+ suggestion: `Either import the Lens into module "${groupKey}", or mark the directive as intentional by appending {allow-external}: ${directive}.`,
72
+ severity: 'error',
73
+ });
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return errors;
79
+ }
80
+ //# sourceMappingURL=card-module-membership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-module-membership.js","sourceRoot":"","sources":["../../src/validator/card-module-membership.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ContentError } from '../index.js';
2
+ /**
3
+ * Main validator for article body content.
4
+ * Checks for unclosed containers, unsupported names, empty containers,
5
+ * attribute typos, and {open} on closing markers.
6
+ */
7
+ export declare function validateDirectives(body: string, file: string, bodyStartLine: number): ContentError[];
8
+ /**
9
+ * Lightweight check for directives in non-article content (e.g., lens text segments).
10
+ * Returns a single warning per match since directives won't render outside articles.
11
+ */
12
+ export declare function detectDirectivesInNonArticle(content: string, file: string, line: number): ContentError[];