lens-content-processor 0.2.2 → 0.3.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 (45) hide show
  1. package/dist/bundler/article.js +4 -16
  2. package/dist/bundler/article.js.map +1 -1
  3. package/dist/cli.d.ts +1 -2
  4. package/dist/cli.js +6 -10
  5. package/dist/cli.js.map +1 -1
  6. package/dist/content-schema.js +6 -5
  7. package/dist/content-schema.js.map +1 -1
  8. package/dist/flattener/index.d.ts +21 -1
  9. package/dist/flattener/index.js +258 -11
  10. package/dist/flattener/index.js.map +1 -1
  11. package/dist/fs/read-vault.d.ts +1 -4
  12. package/dist/fs/read-vault.js +4 -8
  13. package/dist/fs/read-vault.js.map +1 -1
  14. package/dist/index.d.ts +17 -5
  15. package/dist/index.js +123 -16
  16. package/dist/index.js.map +1 -1
  17. package/dist/parser/article.js +6 -3
  18. package/dist/parser/article.js.map +1 -1
  19. package/dist/parser/course.d.ts +2 -2
  20. package/dist/parser/course.js +5 -15
  21. package/dist/parser/course.js.map +1 -1
  22. package/dist/parser/learning-outcome.d.ts +4 -2
  23. package/dist/parser/learning-outcome.js +49 -19
  24. package/dist/parser/learning-outcome.js.map +1 -1
  25. package/dist/parser/lens.d.ts +38 -1
  26. package/dist/parser/lens.js +47 -9
  27. package/dist/parser/lens.js.map +1 -1
  28. package/dist/parser/module.js +1 -1
  29. package/dist/parser/module.js.map +1 -1
  30. package/dist/parser/sections.js +5 -3
  31. package/dist/parser/sections.js.map +1 -1
  32. package/dist/parser/wikilink.js +6 -1
  33. package/dist/parser/wikilink.js.map +1 -1
  34. package/dist/utils/slug.d.ts +5 -0
  35. package/dist/utils/slug.js +16 -0
  36. package/dist/utils/slug.js.map +1 -0
  37. package/dist/validator/chat-precedence.d.ts +9 -0
  38. package/dist/validator/chat-precedence.js +32 -0
  39. package/dist/validator/chat-precedence.js.map +1 -0
  40. package/dist/validator/field-typos.js +0 -9
  41. package/dist/validator/field-typos.js.map +1 -1
  42. package/dist/validator/tier.d.ts +18 -0
  43. package/dist/validator/tier.js +74 -0
  44. package/dist/validator/tier.js.map +1 -0
  45. package/package.json +5 -5
@@ -1,22 +1,10 @@
1
1
  /**
2
- * Normalize smart/curly quotes to their straight equivalents.
3
- * This handles mismatches between content authored in rich text editors
4
- * (which produce curly quotes) and source articles (which may use straight quotes).
5
- */
6
- function normalizeQuotes(text) {
7
- return text
8
- .replaceAll('\u2018', "'") // left single quote
9
- .replaceAll('\u2019', "'") // right single quote (smart apostrophe)
10
- .replaceAll('\u201C', '"') // left double quote
11
- .replaceAll('\u201D', '"'); // right double quote
12
- }
13
- /**
14
- * Find all occurrences of a substring in text (case-insensitive, quote-normalized).
15
- * Returns array of start indices in the ORIGINAL text.
2
+ * Find all occurrences of a substring in text (case-insensitive).
3
+ * Returns array of start indices.
16
4
  */
17
5
  function findAllOccurrences(text, anchor) {
18
- const lowerText = normalizeQuotes(text.toLowerCase());
19
- const lowerAnchor = normalizeQuotes(anchor.toLowerCase());
6
+ const lowerText = text.toLowerCase();
7
+ const lowerAnchor = anchor.toLowerCase();
20
8
  const indices = [];
21
9
  let pos = 0;
22
10
  while (true) {
@@ -1 +1 @@
1
- {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/bundler/article.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/bundler/article.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AACH,SAAS,kBAAkB,CAAC,IAAY,EAAE,MAAc;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACzC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,MAAM;QACtB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClB,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;IAChB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC/D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,UAA8B,EAC9B,QAA4B,EAC5B,IAAY;IAEZ,2DAA2D;IAC3D,IAAI,CAAC,UAAU,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO;YACL,OAAO;YACP,UAAU,EAAE,CAAC;YACb,QAAQ,EAAE,OAAO,CAAC,MAAM;SACzB,CAAC;IACJ,CAAC;IAED,sDAAsD;IACtD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEvC,iDAAiD;IACjD,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAEzD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI;oBACJ,OAAO,EAAE,eAAe,QAAQ,wBAAwB;oBACxD,UAAU,EAAE,0DAA0D;oBACtE,QAAQ,EAAE,OAAO;iBAClB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI;oBACJ,OAAO,EAAE,eAAe,QAAQ,2BAA2B,aAAa,CAAC,MAAM,2BAA2B;oBAC1G,UAAU,EAAE,wDAAwD;oBACpE,QAAQ,EAAE,OAAO;iBAClB;aACF,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAExC,OAAO;YACL,OAAO;YACP,UAAU,EAAE,CAAC;YACb,QAAQ;SACT,CAAC;IACJ,CAAC;IAED,iDAAiD;IACjD,IAAI,UAAU,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,eAAe,GAAG,kBAAkB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAE7D,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI;oBACJ,OAAO,EAAE,iBAAiB,UAAU,wBAAwB;oBAC5D,UAAU,EAAE,0DAA0D;oBACtE,QAAQ,EAAE,OAAO;iBAClB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI;oBACJ,OAAO,EAAE,iBAAiB,UAAU,2BAA2B,eAAe,CAAC,MAAM,2BAA2B;oBAChH,UAAU,EAAE,wDAAwD;oBACpE,QAAQ,EAAE,OAAO;iBAClB;aACF,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAEvC,OAAO;YACL,OAAO;YACP,UAAU;YACV,QAAQ,EAAE,IAAI,CAAC,MAAM;SACtB,CAAC;IACJ,CAAC;IAED,oDAAoD;IACpD,iFAAiF;IACjF,MAAM,aAAa,GAAG,UAAoB,CAAC;IAC3C,MAAM,WAAW,GAAG,QAAkB,CAAC;IAEvC,MAAM,eAAe,GAAG,kBAAkB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAEnE,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,OAAO,EAAE,iBAAiB,aAAa,wBAAwB;gBAC/D,UAAU,EAAE,0DAA0D;gBACtE,QAAQ,EAAE,OAAO;aAClB;SACF,CAAC;IACJ,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,OAAO,EAAE,iBAAiB,aAAa,2BAA2B,eAAe,CAAC,MAAM,2BAA2B;gBACnH,UAAU,EAAE,wDAAwD;gBACpE,QAAQ,EAAE,OAAO;aAClB;SACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAEtC,uEAAuE;IACvE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IAElE,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,OAAO,EAAE,eAAe,WAAW,2CAA2C;gBAC9E,UAAU,EAAE,0DAA0D;gBACtE,QAAQ,EAAE,OAAO;aAClB;SACF,CAAC;IACJ,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,OAAO,EAAE,eAAe,WAAW,2BAA2B,aAAa,CAAC,MAAM,uCAAuC;gBACzH,UAAU,EAAE,wDAAwD;gBACpE,QAAQ,EAAE,OAAO;aAClB;SACF,CAAC;IACJ,CAAC;IAED,wDAAwD;IACxD,MAAM,eAAe,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,UAAU,GAAG,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC;IAEnE,0DAA0D;IAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAEpD,OAAO;QACL,OAAO;QACP,UAAU;QACV,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAe,EACf,QAAwB,EACxB,IAAY;IAEZ,kDAAkD;IAClD,MAAM,iBAAiB,GAKlB,EAAE,CAAC;IAER,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAE9E,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,iBAAiB,CAAC,IAAI,CAAC;gBACrB,OAAO,EAAE,EAAE;gBACX,UAAU,EAAE,CAAC,CAAC;gBACd,QAAQ,EAAE,CAAC,CAAC;gBACZ,KAAK,EAAE,MAAM,CAAC,KAAK;aACpB,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,iBAAiB,CAAC,IAAI,CAAC;gBACrB,OAAO,EAAE,MAAM,CAAC,OAAQ;gBACxB,UAAU,EAAE,MAAM,CAAC,UAAW;gBAC9B,QAAQ,EAAE,MAAM,CAAC,QAAS;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClD,MAAM,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAEvC,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC;gBACX,OAAO,EAAE,EAAE;gBACX,KAAK,EAAE,SAAS,CAAC,KAAK;aACvB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAqB;YAC/B,OAAO,EAAE,SAAS,CAAC,OAAO;SAC3B,CAAC;QAEF,2FAA2F;QAC3F,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,MAAM,WAAW,GAAG,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,QAAQ,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;gBACtE,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;gBACzF,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC/B,MAAM,CAAC,gBAAgB,GAAG,eAAe,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;QAED,gFAAgF;QAChF,gCAAgC;QAChC,IAAI,CAAC,KAAK,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YAChE,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,eAAe,GAAG,cAAc,CAAC;YAC1C,CAAC;QACH,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { ProcessResult } from './index.js';
2
+ import { type ProcessResult } from './index.js';
3
3
  export interface CliOptions {
4
4
  vaultPath: string | null;
5
5
  outputPath: string | null;
6
- includeWip: boolean;
7
6
  stdin: boolean;
8
7
  }
9
8
  export declare function parseArgs(argv: string[]): CliOptions;
package/dist/cli.js CHANGED
@@ -8,24 +8,20 @@ export function parseArgs(argv) {
8
8
  const args = argv.slice(2);
9
9
  let vaultPath = null;
10
10
  let outputPath = null;
11
- let includeWip = false;
12
- let stdin = false; // NEW
11
+ let stdin = false;
13
12
  for (let i = 0; i < args.length; i++) {
14
13
  if (args[i] === '--output' || args[i] === '-o') {
15
14
  outputPath = args[i + 1] || null;
16
15
  i++; // skip next arg
17
16
  }
18
- else if (args[i] === '--include-wip') {
19
- includeWip = true;
20
- }
21
- else if (args[i] === '--stdin') { // NEW
17
+ else if (args[i] === '--stdin') {
22
18
  stdin = true;
23
19
  }
24
20
  else if (!args[i].startsWith('-')) {
25
21
  vaultPath = args[i];
26
22
  }
27
23
  }
28
- return { vaultPath, outputPath, includeWip, stdin };
24
+ return { vaultPath, outputPath, stdin };
29
25
  }
30
26
  async function readStdin() {
31
27
  const chunks = [];
@@ -46,14 +42,14 @@ export async function run(options) {
46
42
  if (!options.vaultPath) {
47
43
  throw new Error('Vault path is required (or use --stdin)');
48
44
  }
49
- files = await readVaultFiles(options.vaultPath, { includeWip: options.includeWip });
45
+ files = await readVaultFiles(options.vaultPath);
50
46
  }
51
- return processContent(files, { includeWip: options.includeWip });
47
+ return processContent(files);
52
48
  }
53
49
  async function main() {
54
50
  const options = parseArgs(process.argv);
55
51
  if (!options.vaultPath && !options.stdin) {
56
- console.error('Usage: npx tsx src/cli.ts <vault-path> [--output <file>] [--include-wip]');
52
+ console.error('Usage: npx tsx src/cli.ts <vault-path> [--output <file>]');
57
53
  console.error(' npx tsx src/cli.ts --stdin [--output <file>]');
58
54
  process.exit(1);
59
55
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -6,18 +6,19 @@ function segmentSchema(required, optional, booleanFields) {
6
6
  return { requiredFields: required, optionalFields: optional, allFields: [...required, ...optional], booleanFields };
7
7
  }
8
8
  export const CONTENT_SCHEMAS = {
9
- 'module': contentSchema(['slug', 'title'], ['contentId', 'id', 'discussion']),
10
- 'course': contentSchema(['slug', 'title'], ['id']),
11
- 'lens': contentSchema(['id'], []),
12
- 'learning-outcome': contentSchema(['id'], ['discussion', 'learning-outcome']),
9
+ 'module': contentSchema(['slug', 'title'], ['contentId', 'id', 'discussion', 'tags']),
10
+ 'course': contentSchema(['slug', 'title'], ['id', 'tags']),
11
+ 'lens': contentSchema(['id'], ['tags']),
12
+ 'learning-outcome': contentSchema(['id'], ['discussion', 'learning-outcome', 'tags']),
13
13
  'article': contentSchema(['title', 'author', 'source_url'], ['date', 'published', 'created', 'description', 'tags', 'url']),
14
- 'video-transcript': contentSchema(['title', 'channel', 'url'], []),
14
+ 'video-transcript': contentSchema(['title', 'channel', 'url'], ['tags']),
15
15
  };
16
16
  export const SEGMENT_SCHEMAS = {
17
17
  'text': segmentSchema(['content'], ['optional'], ['optional']),
18
18
  'chat': segmentSchema(['instructions'], ['optional', 'hidePreviousContentFromUser', 'hidePreviousContentFromTutor'], ['optional', 'hidePreviousContentFromUser', 'hidePreviousContentFromTutor']),
19
19
  'article-excerpt': segmentSchema([], ['from', 'to', 'optional'], ['optional']),
20
20
  'video-excerpt': segmentSchema(['to'], ['from', 'optional'], ['optional']),
21
+ 'question': segmentSchema(['content'], ['assessment-instructions', 'max-time', 'max-chars', 'enforce-voice', 'optional', 'feedback'], ['enforce-voice', 'optional', 'feedback']),
21
22
  };
22
23
  /**
23
24
  * Valid fields per segment type, derived from SEGMENT_SCHEMAS.
@@ -1 +1 @@
1
- {"version":3,"file":"content-schema.js","sourceRoot":"","sources":["../src/content-schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"content-schema.js","sourceRoot":"","sources":["../src/content-schema.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import type { FlattenedModule, ContentError } from '../index.js';
2
+ import type { ContentTier } from '../validator/tier.js';
3
+ import { type ParsedLens } from '../parser/lens.js';
2
4
  export interface FlattenModuleResult {
3
5
  module: FlattenedModule | null;
4
6
  errors: ContentError[];
@@ -17,4 +19,22 @@ export interface FlattenModuleResult {
17
19
  * @param visitedPaths - Optional set of already-visited paths for cycle detection
18
20
  * @returns Flattened module with resolved sections and segments, plus any errors
19
21
  */
20
- export declare function flattenModule(modulePath: string, files: Map<string, string>, visitedPaths?: Set<string>): FlattenModuleResult;
22
+ export declare function flattenModule(modulePath: string, files: Map<string, string>, visitedPaths?: Set<string>, tierMap?: Map<string, ContentTier>): FlattenModuleResult;
23
+ /**
24
+ * Flatten a single Lens file into a FlattenedModule.
25
+ *
26
+ * This wraps a standalone Lens as a single-section module so it can be
27
+ * rendered by the frontend using the existing Module.tsx component.
28
+ *
29
+ * The resulting module has:
30
+ * - slug: 'lens/' + fileNameToSlug(lensPath)
31
+ * - title: extracted from source metadata or lens header
32
+ * - sections: exactly one section (lens-article, lens-video, or page)
33
+ *
34
+ * @param lensPath - Path to the lens file within the files Map
35
+ * @param files - Map of all file paths to their content
36
+ * @param tierMap - Optional tier map for filtering ignored content
37
+ * @param preParsedLens - Optional pre-parsed lens to avoid re-parsing
38
+ * @returns Flattened module with a single section, plus any errors
39
+ */
40
+ export declare function flattenLens(lensPath: string, files: Map<string, string>, tierMap?: Map<string, ContentTier>, preParsedLens?: ParsedLens): FlattenModuleResult;
@@ -1,8 +1,10 @@
1
+ import { checkTierViolation } from '../validator/tier.js';
1
2
  import { parseModule, parsePageSegments } from '../parser/module.js';
2
3
  import { parseLearningOutcome } from '../parser/learning-outcome.js';
3
4
  import { parseLens } from '../parser/lens.js';
4
5
  import { parseWikilink, resolveWikilinkPath, findFileWithExtension, findSimilarFiles, formatSuggestion } from '../parser/wikilink.js';
5
6
  import { parseFrontmatter } from '../parser/frontmatter.js';
7
+ import { fileNameToSlug } from '../utils/slug.js';
6
8
  import { extractArticleExcerpt } from '../bundler/article.js';
7
9
  import { extractVideoExcerpt } from '../bundler/video.js';
8
10
  /**
@@ -34,7 +36,7 @@ function extractVideoIdFromUrl(url) {
34
36
  * @param visitedPaths - Optional set of already-visited paths for cycle detection
35
37
  * @returns Flattened module with resolved sections and segments, plus any errors
36
38
  */
37
- export function flattenModule(modulePath, files, visitedPaths = new Set()) {
39
+ export function flattenModule(modulePath, files, visitedPaths = new Set(), tierMap) {
38
40
  // Check for circular reference
39
41
  if (visitedPaths.has(modulePath)) {
40
42
  return {
@@ -75,7 +77,7 @@ export function flattenModule(modulePath, files, visitedPaths = new Set()) {
75
77
  // This allows the same file to be referenced in different sections
76
78
  // while still detecting cycles within a single chain
77
79
  const sectionVisitedPaths = new Set(visitedPaths);
78
- const result = flattenLearningOutcomeSection(section, modulePath, files, sectionVisitedPaths);
80
+ const result = flattenLearningOutcomeSection(section, modulePath, files, sectionVisitedPaths, tierMap);
79
81
  errors.push(...result.errors);
80
82
  flattenedSections.push(...result.sections);
81
83
  }
@@ -100,7 +102,7 @@ export function flattenModule(modulePath, files, visitedPaths = new Set()) {
100
102
  // Uncategorized sections can contain ## Lens: references
101
103
  // Each lens becomes its own section (lens-video, lens-article, or page)
102
104
  const sectionVisitedPaths = new Set(visitedPaths);
103
- const result = flattenUncategorizedSection(section, modulePath, files, sectionVisitedPaths);
105
+ const result = flattenUncategorizedSection(section, modulePath, files, sectionVisitedPaths, tierMap);
104
106
  errors.push(...result.errors);
105
107
  flattenedSections.push(...result.sections);
106
108
  }
@@ -120,7 +122,7 @@ export function flattenModule(modulePath, files, visitedPaths = new Set()) {
120
122
  * Flatten a Learning Outcome section by resolving its LO file and all referenced lenses.
121
123
  * Each lens in the LO becomes its own section.
122
124
  */
123
- function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths) {
125
+ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths, tierMap) {
124
126
  const errors = [];
125
127
  const sections = [];
126
128
  // Get the source wikilink
@@ -144,7 +146,9 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
144
146
  errors.push({
145
147
  file: modulePath,
146
148
  line: section.line,
147
- message: `Invalid wikilink format: ${source}`,
149
+ message: wikilink?.error
150
+ ? `${wikilink.error}: ${source}`
151
+ : `Invalid wikilink format: ${source}`,
148
152
  suggestion,
149
153
  severity: 'error',
150
154
  });
@@ -166,6 +170,19 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
166
170
  });
167
171
  return { sections: [], errors };
168
172
  }
173
+ // Check tier violation (module → LO)
174
+ if (tierMap) {
175
+ const parentTier = tierMap.get(modulePath) ?? 'production';
176
+ const childTier = tierMap.get(loPath) ?? 'production';
177
+ const violation = checkTierViolation(modulePath, parentTier, loPath, childTier, 'learning outcome', section.line);
178
+ if (violation) {
179
+ errors.push(violation);
180
+ }
181
+ // Skip ignored children silently (they're not processed)
182
+ if (childTier === 'ignored') {
183
+ return { sections: [], errors };
184
+ }
185
+ }
169
186
  // Check for circular reference
170
187
  if (visitedPaths.has(loPath)) {
171
188
  errors.push({
@@ -200,6 +217,18 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
200
217
  });
201
218
  continue;
202
219
  }
220
+ // Check tier violation (LO → Lens)
221
+ if (tierMap) {
222
+ const parentTier = tierMap.get(loPath) ?? 'production';
223
+ const childTier = tierMap.get(lensPath) ?? 'production';
224
+ const violation = checkTierViolation(loPath, parentTier, lensPath, childTier, 'lens');
225
+ if (violation) {
226
+ errors.push(violation);
227
+ }
228
+ if (childTier === 'ignored') {
229
+ continue;
230
+ }
231
+ }
203
232
  // Check for circular reference
204
233
  if (visitedPaths.has(lensPath)) {
205
234
  errors.push({
@@ -242,7 +271,8 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
242
271
  meta.title = articleFrontmatter.frontmatter.title;
243
272
  }
244
273
  if (articleFrontmatter.frontmatter.author) {
245
- meta.author = articleFrontmatter.frontmatter.author;
274
+ const raw = articleFrontmatter.frontmatter.author;
275
+ meta.author = Array.isArray(raw) ? raw.join(', ') : String(raw);
246
276
  }
247
277
  if (articleFrontmatter.frontmatter.source_url) {
248
278
  meta.sourceUrl = articleFrontmatter.frontmatter.source_url;
@@ -289,7 +319,7 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
289
319
  }
290
320
  // Process segments
291
321
  for (const parsedSegment of lensSection.segments) {
292
- const segmentResult = convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths);
322
+ const segmentResult = convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths, tierMap);
293
323
  errors.push(...segmentResult.errors);
294
324
  if (segmentResult.segment) {
295
325
  segments.push(segmentResult.segment);
@@ -312,13 +342,46 @@ function flattenLearningOutcomeSection(section, modulePath, files, visitedPaths)
312
342
  };
313
343
  sections.push(resultSection);
314
344
  }
345
+ // After lens processing, add test section if present with inline segments
346
+ if (lo.test && lo.test.segments.length > 0) {
347
+ const testSegments = [];
348
+ for (const parsedSegment of lo.test.segments) {
349
+ // For test sections with question/chat/text segments, no source file resolution needed
350
+ // Create a minimal stub lensSection since these segment types don't need it
351
+ const stubLensSection = {
352
+ type: 'page',
353
+ title: 'Test',
354
+ segments: [],
355
+ line: 0,
356
+ };
357
+ const segmentResult = convertSegment(parsedSegment, stubLensSection, loPath, files, visitedPaths, tierMap);
358
+ errors.push(...segmentResult.errors);
359
+ if (segmentResult.segment) {
360
+ testSegments.push(segmentResult.segment);
361
+ }
362
+ }
363
+ if (testSegments.length > 0) {
364
+ const hasFeedback = testSegments.some((s) => s.type === 'question' && s.feedback);
365
+ sections.push({
366
+ type: 'test',
367
+ meta: { title: 'Test' },
368
+ segments: testSegments,
369
+ optional: false,
370
+ ...(hasFeedback && { feedback: true }),
371
+ contentId: null,
372
+ learningOutcomeId: lo.id ?? null,
373
+ learningOutcomeName: loPath.split('/').pop()?.replace(/\.md$/i, '') ?? null,
374
+ videoId: null,
375
+ });
376
+ }
377
+ }
315
378
  return { sections, errors };
316
379
  }
317
380
  /**
318
381
  * Flatten an Uncategorized section by parsing its ## Lens: references.
319
382
  * Each lens becomes its own section with the appropriate type (lens-video, lens-article, or page).
320
383
  */
321
- function flattenUncategorizedSection(section, modulePath, files, visitedPaths) {
384
+ function flattenUncategorizedSection(section, modulePath, files, visitedPaths, tierMap) {
322
385
  const errors = [];
323
386
  const sections = [];
324
387
  // Parse the section body for ## Lens: subsections
@@ -349,6 +412,18 @@ function flattenUncategorizedSection(section, modulePath, files, visitedPaths) {
349
412
  });
350
413
  continue;
351
414
  }
415
+ // Check tier violation (Uncategorized/Module → Lens)
416
+ if (tierMap) {
417
+ const parentTier = tierMap.get(modulePath) ?? 'production';
418
+ const childTier = tierMap.get(lensPath) ?? 'production';
419
+ const violation = checkTierViolation(modulePath, parentTier, lensPath, childTier, 'lens');
420
+ if (violation) {
421
+ errors.push(violation);
422
+ }
423
+ if (childTier === 'ignored') {
424
+ continue;
425
+ }
426
+ }
352
427
  // Check for circular reference
353
428
  if (visitedPaths.has(lensPath)) {
354
429
  errors.push({
@@ -391,7 +466,8 @@ function flattenUncategorizedSection(section, modulePath, files, visitedPaths) {
391
466
  meta.title = articleFrontmatter.frontmatter.title;
392
467
  }
393
468
  if (articleFrontmatter.frontmatter.author) {
394
- meta.author = articleFrontmatter.frontmatter.author;
469
+ const raw = articleFrontmatter.frontmatter.author;
470
+ meta.author = Array.isArray(raw) ? raw.join(', ') : String(raw);
395
471
  }
396
472
  if (articleFrontmatter.frontmatter.source_url) {
397
473
  meta.sourceUrl = articleFrontmatter.frontmatter.source_url;
@@ -438,7 +514,7 @@ function flattenUncategorizedSection(section, modulePath, files, visitedPaths) {
438
514
  }
439
515
  // Process segments
440
516
  for (const parsedSegment of lensSection.segments) {
441
- const segmentResult = convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths);
517
+ const segmentResult = convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths, tierMap);
442
518
  errors.push(...segmentResult.errors);
443
519
  if (segmentResult.segment) {
444
520
  segments.push(segmentResult.segment);
@@ -574,7 +650,7 @@ function parseUncategorizedLensRefs(body, parentPath) {
574
650
  * Convert a parsed lens segment into a final flattened segment.
575
651
  * For article-excerpt and video-excerpt, this involves extracting content from source files.
576
652
  */
577
- function convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths) {
653
+ function convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths, tierMap) {
578
654
  const errors = [];
579
655
  switch (parsedSegment.type) {
580
656
  case 'text': {
@@ -642,6 +718,18 @@ function convertSegment(parsedSegment, lensSection, lensPath, files, visitedPath
642
718
  });
643
719
  return { segment: null, errors };
644
720
  }
721
+ // Check tier violation (Lens → Article)
722
+ if (tierMap) {
723
+ const parentTier = tierMap.get(lensPath) ?? 'production';
724
+ const childTier = tierMap.get(articlePath) ?? 'production';
725
+ const violation = checkTierViolation(lensPath, parentTier, articlePath, childTier, 'article');
726
+ if (violation) {
727
+ errors.push(violation);
728
+ }
729
+ if (childTier === 'ignored') {
730
+ return { segment: null, errors };
731
+ }
732
+ }
645
733
  // Check if the article path points back to an already-visited structural file
646
734
  // This would indicate a circular reference (e.g., a lens source pointing back to an LO)
647
735
  // Note: We only check, we don't add article paths to visitedPaths since
@@ -707,6 +795,18 @@ function convertSegment(parsedSegment, lensSection, lensPath, files, visitedPath
707
795
  });
708
796
  return { segment: null, errors };
709
797
  }
798
+ // Check tier violation (Lens → Video)
799
+ if (tierMap) {
800
+ const parentTier = tierMap.get(lensPath) ?? 'production';
801
+ const childTier = tierMap.get(videoPath) ?? 'production';
802
+ const violation = checkTierViolation(lensPath, parentTier, videoPath, childTier, 'video transcript');
803
+ if (violation) {
804
+ errors.push(violation);
805
+ }
806
+ if (childTier === 'ignored') {
807
+ return { segment: null, errors };
808
+ }
809
+ }
710
810
  // Check if the video path points back to an already-visited structural file
711
811
  // This would indicate a circular reference
712
812
  // Note: We only check, we don't add video paths to visitedPaths since
@@ -754,8 +854,155 @@ function convertSegment(parsedSegment, lensSection, lensPath, files, visitedPath
754
854
  }
755
855
  return { segment, errors };
756
856
  }
857
+ case 'question': {
858
+ const segment = {
859
+ type: 'question',
860
+ content: parsedSegment.content,
861
+ };
862
+ if (parsedSegment.assessmentInstructions)
863
+ segment.assessmentInstructions = parsedSegment.assessmentInstructions;
864
+ if (parsedSegment.maxTime)
865
+ segment.maxTime = parsedSegment.maxTime;
866
+ if (parsedSegment.maxChars !== undefined)
867
+ segment.maxChars = parsedSegment.maxChars;
868
+ if (parsedSegment.enforceVoice)
869
+ segment.enforceVoice = true;
870
+ if (parsedSegment.optional)
871
+ segment.optional = true;
872
+ if (parsedSegment.feedback)
873
+ segment.feedback = true;
874
+ return { segment, errors };
875
+ }
757
876
  default:
758
877
  return { segment: null, errors };
759
878
  }
760
879
  }
880
+ /**
881
+ * Flatten a single Lens file into a FlattenedModule.
882
+ *
883
+ * This wraps a standalone Lens as a single-section module so it can be
884
+ * rendered by the frontend using the existing Module.tsx component.
885
+ *
886
+ * The resulting module has:
887
+ * - slug: 'lens/' + fileNameToSlug(lensPath)
888
+ * - title: extracted from source metadata or lens header
889
+ * - sections: exactly one section (lens-article, lens-video, or page)
890
+ *
891
+ * @param lensPath - Path to the lens file within the files Map
892
+ * @param files - Map of all file paths to their content
893
+ * @param tierMap - Optional tier map for filtering ignored content
894
+ * @param preParsedLens - Optional pre-parsed lens to avoid re-parsing
895
+ * @returns Flattened module with a single section, plus any errors
896
+ */
897
+ export function flattenLens(lensPath, files, tierMap, preParsedLens) {
898
+ const errors = [];
899
+ // Skip ignored lenses
900
+ if (tierMap?.get(lensPath) === 'ignored') {
901
+ return { module: null, errors };
902
+ }
903
+ const lensContent = files.get(lensPath);
904
+ if (!lensContent) {
905
+ errors.push({
906
+ file: lensPath,
907
+ message: `Lens file not found: ${lensPath}`,
908
+ severity: 'error',
909
+ });
910
+ return { module: null, errors };
911
+ }
912
+ // Use pre-parsed lens if provided, otherwise parse
913
+ const lens = preParsedLens ?? (() => {
914
+ const lensResult = parseLens(lensContent, lensPath);
915
+ errors.push(...lensResult.errors);
916
+ return lensResult.lens;
917
+ })();
918
+ if (!lens) {
919
+ return { module: null, errors };
920
+ }
921
+ const visitedPaths = new Set([lensPath]);
922
+ // Process lens sections into a single flattened Section
923
+ let sectionType = 'page';
924
+ const meta = {};
925
+ const segments = [];
926
+ let videoId;
927
+ for (const lensSection of lens.sections) {
928
+ if (lensSection.type === 'lens-article') {
929
+ sectionType = 'lens-article';
930
+ // Extract article metadata from the article file's frontmatter
931
+ if (lensSection.source) {
932
+ const articleWikilink = parseWikilink(lensSection.source);
933
+ if (articleWikilink && !articleWikilink.error) {
934
+ const articlePathResolved = resolveWikilinkPath(articleWikilink.path, lensPath);
935
+ const articlePath = findFileWithExtension(articlePathResolved, files);
936
+ if (articlePath) {
937
+ const articleContent = files.get(articlePath);
938
+ const articleFrontmatter = parseFrontmatter(articleContent, articlePath);
939
+ if (articleFrontmatter.frontmatter.title)
940
+ meta.title = articleFrontmatter.frontmatter.title;
941
+ if (articleFrontmatter.frontmatter.author)
942
+ meta.author = articleFrontmatter.frontmatter.author;
943
+ if (articleFrontmatter.frontmatter.source_url)
944
+ meta.sourceUrl = articleFrontmatter.frontmatter.source_url;
945
+ }
946
+ }
947
+ }
948
+ }
949
+ else if (lensSection.type === 'page') {
950
+ sectionType = 'page';
951
+ if (lensSection.title)
952
+ meta.title = lensSection.title;
953
+ }
954
+ else if (lensSection.type === 'lens-video') {
955
+ sectionType = 'lens-video';
956
+ // Extract video metadata from the video transcript file's frontmatter
957
+ if (lensSection.source) {
958
+ const videoWikilink = parseWikilink(lensSection.source);
959
+ if (videoWikilink && !videoWikilink.error) {
960
+ const videoPathResolved = resolveWikilinkPath(videoWikilink.path, lensPath);
961
+ const videoPath = findFileWithExtension(videoPathResolved, files);
962
+ if (videoPath) {
963
+ const videoContent = files.get(videoPath);
964
+ const videoFrontmatter = parseFrontmatter(videoContent, videoPath);
965
+ if (videoFrontmatter.frontmatter.title)
966
+ meta.title = videoFrontmatter.frontmatter.title;
967
+ if (videoFrontmatter.frontmatter.channel)
968
+ meta.channel = videoFrontmatter.frontmatter.channel;
969
+ if (videoFrontmatter.frontmatter.url) {
970
+ const extractedId = extractVideoIdFromUrl(videoFrontmatter.frontmatter.url);
971
+ if (extractedId)
972
+ videoId = extractedId;
973
+ }
974
+ }
975
+ }
976
+ }
977
+ }
978
+ // Process segments
979
+ for (const parsedSegment of lensSection.segments) {
980
+ const segmentResult = convertSegment(parsedSegment, lensSection, lensPath, files, visitedPaths, tierMap);
981
+ errors.push(...segmentResult.errors);
982
+ if (segmentResult.segment)
983
+ segments.push(segmentResult.segment);
984
+ }
985
+ }
986
+ // Fallback title from filename if not extracted from source metadata
987
+ if (!meta.title) {
988
+ meta.title = fileNameToSlug(lensPath).replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
989
+ }
990
+ const section = {
991
+ type: sectionType,
992
+ meta,
993
+ segments,
994
+ optional: false,
995
+ learningOutcomeId: null,
996
+ learningOutcomeName: null,
997
+ contentId: lens.id ?? null,
998
+ videoId: videoId ?? null,
999
+ };
1000
+ const flattenedModule = {
1001
+ slug: 'lens/' + fileNameToSlug(lensPath),
1002
+ title: meta.title ?? fileNameToSlug(lensPath),
1003
+ contentId: lens.id ?? null,
1004
+ sections: [section],
1005
+ };
1006
+ return { module: flattenedModule, errors };
1007
+ }
761
1008
  //# sourceMappingURL=index.js.map