lens-content-processor 0.27.0 → 0.33.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 (64) hide show
  1. package/dist/authoring-markup.d.ts +11 -0
  2. package/dist/authoring-markup.js +52 -0
  3. package/dist/authoring-markup.js.map +1 -1
  4. package/dist/cli.d.ts +1 -0
  5. package/dist/cli.js +6 -2
  6. package/dist/cli.js.map +1 -1
  7. package/dist/content-schema.js +17 -1
  8. package/dist/content-schema.js.map +1 -1
  9. package/dist/dedupe-errors.js +7 -1
  10. package/dist/dedupe-errors.js.map +1 -1
  11. package/dist/flattener/index.js +90 -46
  12. package/dist/flattener/index.js.map +1 -1
  13. package/dist/flattener/resolve-text-links.js +6 -2
  14. package/dist/flattener/resolve-text-links.js.map +1 -1
  15. package/dist/index.d.ts +5 -0
  16. package/dist/index.js +20 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/parser/article.js +34 -32
  19. package/dist/parser/article.js.map +1 -1
  20. package/dist/parser/course.d.ts +0 -10
  21. package/dist/parser/course.js +16 -14
  22. package/dist/parser/course.js.map +1 -1
  23. package/dist/parser/learning-outcome.d.ts +1 -0
  24. package/dist/parser/learning-outcome.js +28 -38
  25. package/dist/parser/learning-outcome.js.map +1 -1
  26. package/dist/parser/lens.d.ts +27 -10
  27. package/dist/parser/lens.js +160 -32
  28. package/dist/parser/lens.js.map +1 -1
  29. package/dist/parser/module.js +37 -18
  30. package/dist/parser/module.js.map +1 -1
  31. package/dist/parser/sections.d.ts +2 -1
  32. package/dist/parser/sections.js +5 -3
  33. package/dist/parser/sections.js.map +1 -1
  34. package/dist/parser/survey.js +16 -10
  35. package/dist/parser/survey.js.map +1 -1
  36. package/dist/source-location.d.ts +2 -0
  37. package/dist/source-location.js +12 -0
  38. package/dist/source-location.js.map +1 -0
  39. package/dist/validator/article-review-provenance.d.ts +5 -0
  40. package/dist/validator/article-review-provenance.js +57 -0
  41. package/dist/validator/article-review-provenance.js.map +1 -0
  42. package/dist/validator/article-structure.d.ts +8 -0
  43. package/dist/validator/article-structure.js +674 -0
  44. package/dist/validator/article-structure.js.map +1 -0
  45. package/dist/validator/directives.js +42 -0
  46. package/dist/validator/directives.js.map +1 -1
  47. package/dist/validator/emphasis.js +126 -2
  48. package/dist/validator/emphasis.js.map +1 -1
  49. package/dist/validator/html-tags.js +87 -2
  50. package/dist/validator/html-tags.js.map +1 -1
  51. package/dist/validator/math.js +66 -9
  52. package/dist/validator/math.js.map +1 -1
  53. package/dist/validator/output-integrity.js +7 -1
  54. package/dist/validator/output-integrity.js.map +1 -1
  55. package/dist/validator/same-lens-links.d.ts +4 -0
  56. package/dist/validator/same-lens-links.js +297 -0
  57. package/dist/validator/same-lens-links.js.map +1 -0
  58. package/dist/validator/suppressions.d.ts +42 -0
  59. package/dist/validator/suppressions.js +97 -0
  60. package/dist/validator/suppressions.js.map +1 -0
  61. package/dist/validator/uuid.d.ts +1 -0
  62. package/dist/validator/uuid.js +2 -0
  63. package/dist/validator/uuid.js.map +1 -1
  64. package/package.json +9 -1
@@ -3,6 +3,11 @@
3
3
  * Handles both inline (%% ... %% on same line) and block (multiline) comments.
4
4
  */
5
5
  export declare function stripObsidianComments(content: string): string;
6
+ /**
7
+ * Reject authoring markup while preserving source line numbers for validators.
8
+ * Publishing deliberately uses stripAuthoringMarkup() instead.
9
+ */
10
+ export declare function stripAuthoringMarkupForValidation(content: string): string;
6
11
  /**
7
12
  * Strip CriticMarkup from content using reject-all-changes behavior. Each
8
13
  * form's regex and publish replacement are defined once in CRITIC_MARKUP_FORMS
@@ -14,3 +19,9 @@ export declare function stripCriticMarkup(content: string): string;
14
19
  * Call before parsing or publishing learner-facing content.
15
20
  */
16
21
  export declare function stripAuthoringMarkup(content: string): string;
22
+ /**
23
+ * Copy learner-facing strings from a publishing parse onto the equivalent
24
+ * validation parse. Objects (and their non-enumerable source provenance) stay
25
+ * intact, as do validation-derived line numbers and other scalar metadata.
26
+ */
27
+ export declare function usePublishedStrings<T>(validationValue: T, publishedValue: T): T;
@@ -6,6 +6,28 @@ import { CRITIC_MARKUP_FORMS } from "./criticmarkup-forms.js";
6
6
  export function stripObsidianComments(content) {
7
7
  return content.replace(/%%.*?%%/gs, "");
8
8
  }
9
+ function preserveNewlines(match, replacement) {
10
+ const missing = (match.match(/\n/g)?.length ?? 0) - (replacement.match(/\n/g)?.length ?? 0);
11
+ return replacement + "\n".repeat(Math.max(0, missing));
12
+ }
13
+ /**
14
+ * Reject authoring markup while preserving source line numbers for validators.
15
+ * Publishing deliberately uses stripAuthoringMarkup() instead.
16
+ */
17
+ export function stripAuthoringMarkupForValidation(content) {
18
+ let result = content.replace(/%%.*?%%/gs, (match) => match.replace(/[^\n]/g, " "));
19
+ for (const form of CRITIC_MARKUP_FORMS) {
20
+ result = result.replace(form.re, (...args) => {
21
+ const match = String(args[0]);
22
+ const kept = form.rejected === "$1" ? String(args[1] ?? "") : "";
23
+ return preserveNewlines(match, kept);
24
+ });
25
+ }
26
+ return result
27
+ .split("\n")
28
+ .map((line) => line.trimEnd())
29
+ .join("\n");
30
+ }
9
31
  /**
10
32
  * Strip CriticMarkup from content using reject-all-changes behavior. Each
11
33
  * form's regex and publish replacement are defined once in CRITIC_MARKUP_FORMS
@@ -26,4 +48,34 @@ export function stripAuthoringMarkup(content) {
26
48
  .map((line) => line.trimEnd())
27
49
  .join("\n");
28
50
  }
51
+ /**
52
+ * Copy learner-facing strings from a publishing parse onto the equivalent
53
+ * validation parse. Objects (and their non-enumerable source provenance) stay
54
+ * intact, as do validation-derived line numbers and other scalar metadata.
55
+ */
56
+ export function usePublishedStrings(validationValue, publishedValue) {
57
+ if (typeof validationValue === "string")
58
+ return publishedValue;
59
+ if (validationValue === null ||
60
+ publishedValue === null ||
61
+ typeof validationValue !== "object" ||
62
+ typeof publishedValue !== "object") {
63
+ return validationValue;
64
+ }
65
+ if (Array.isArray(validationValue) && Array.isArray(publishedValue)) {
66
+ const count = Math.min(validationValue.length, publishedValue.length);
67
+ for (let index = 0; index < count; index += 1) {
68
+ validationValue[index] = usePublishedStrings(validationValue[index], publishedValue[index]);
69
+ }
70
+ return validationValue;
71
+ }
72
+ const validationRecord = validationValue;
73
+ const publishedRecord = publishedValue;
74
+ for (const key of Object.keys(validationRecord)) {
75
+ if (key in publishedRecord) {
76
+ validationRecord[key] = usePublishedStrings(validationRecord[key], publishedRecord[key]);
77
+ }
78
+ }
79
+ return validationValue;
80
+ }
29
81
  //# sourceMappingURL=authoring-markup.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"authoring-markup.js","sourceRoot":"","sources":["../src/authoring-markup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,mBAAmB,CAAC,MAAM,CAC/B,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,EACpD,OAAO,CACR,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IACnE,0DAA0D;IAC1D,OAAO,QAAQ;SACZ,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;SAC7B,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"authoring-markup.js","sourceRoot":"","sources":["../src/authoring-markup.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts CHANGED
@@ -6,6 +6,7 @@ export interface CliOptions {
6
6
  stdin: boolean;
7
7
  deferUrls: boolean;
8
8
  checkUrlsOnly: boolean;
9
+ skipUrls: boolean;
9
10
  }
10
11
  /**
11
12
  * The CLI's JSON output: the core ProcessResult plus a course-reachability map
package/dist/cli.js CHANGED
@@ -14,6 +14,7 @@ export function parseArgs(argv) {
14
14
  let stdin = false;
15
15
  let deferUrls = false;
16
16
  let checkUrlsOnly = false;
17
+ let skipUrls = false;
17
18
  for (let i = 0; i < args.length; i++) {
18
19
  if (args[i] === "--output" || args[i] === "-o") {
19
20
  outputPath = args[i + 1] || null;
@@ -28,11 +29,14 @@ export function parseArgs(argv) {
28
29
  else if (args[i] === "--check-urls-only") {
29
30
  checkUrlsOnly = true;
30
31
  }
32
+ else if (args[i] === "--skip-urls") {
33
+ skipUrls = true;
34
+ }
31
35
  else if (!args[i].startsWith("-")) {
32
36
  vaultPath = args[i];
33
37
  }
34
38
  }
35
- return { vaultPath, outputPath, stdin, deferUrls, checkUrlsOnly };
39
+ return { vaultPath, outputPath, stdin, deferUrls, checkUrlsOnly, skipUrls };
36
40
  }
37
41
  async function readStdin() {
38
42
  const chunks = [];
@@ -121,7 +125,7 @@ async function main() {
121
125
  staleUrlCount: cache.staleCount(result.urlsToValidate),
122
126
  };
123
127
  }
124
- else if (result.urlsToValidate.length > 0) {
128
+ else if (!options.skipUrls && result.urlsToValidate.length > 0) {
125
129
  const urlWarnings = await validateUrls(result.urlsToValidate, UrlCache.load());
126
130
  // Re-dedupe: urlWarnings are appended after processContent already
127
131
  // deduped, and can themselves repeat (same unreachable URL twice).
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,cAAc,GAIf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,mBAAmB,GACpB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoBxC,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/C,UAAU,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;YACjC,CAAC,EAAE,CAAC,CAAC,gBAAgB;QACvB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YACjC,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;YACtC,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,mBAAmB,EAAE,CAAC;YAC3C,aAAa,GAAG,IAAI,CAAC;QACvB,CAAC;aAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;AACpE,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAmB;IAC3C,IAAI,KAA0B,CAAC;IAE/B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,mDAAmD;QACnD,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAA2B,CAAC;QAC3D,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAErC,wEAAwE;IACxE,yEAAyE;IACzE,0EAA0E;IAC1E,wEAAwE;IACxE,2DAA2D;IAC3D,IAAI,aAAa,GAA6B,EAAE,CAAC;IACjD,IAAI,CAAC;QACH,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,0EAA0E,EAC1E,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC/C,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC3E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,SAAS,EAAE,CAAoB,CAAC;YAC9D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACzC,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC;QAElC,IAAI,MAAM,GAGN,MAAM,CAAC;QAEX,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,sEAAsE;YACtE,oEAAoE;YACpE,gEAAgE;YAChE,gEAAgE;YAChE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAmB,EAAE,CAAC;YACxC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;gBAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC1C,IAAI,CAAC,OAAO;oBAAE,SAAS;gBACvB,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAClD,IAAI,KAAK;oBAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;YACD,yEAAyE;YACzE,sEAAsE;YACtE,gCAAgC;YAChC,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CACvE,MAAM,CAAC,MAAM,CAAC,MAAM,CACrB,CAAC;YACF,MAAM,GAAG;gBACP,GAAG,MAAM;gBACT,SAAS;gBACT,aAAa,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC;aACvD,CAAC;QACJ,CAAC;aAAM,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,WAAW,GAAG,MAAM,YAAY,CACpC,MAAM,CAAC,cAAc,EACrB,QAAQ,CAAC,IAAI,EAAE,CAChB,CAAC;YACF,mEAAmE;YACnE,mEAAmE;YACnE,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAE7C,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,cAAc,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,sDAAsD;AACtD,+EAA+E;AAC/E,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,MAAM,YAAY,GAChB,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC7B,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC7B,UAAU,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;AAChD,IAAI,YAAY,EAAE,CAAC;IACjB,IAAI,EAAE,CAAC;AACT,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,16 @@ export const CONTENT_SCHEMAS = {
25
25
  "partner-logo-small",
26
26
  "partner-url",
27
27
  ]),
28
- lens: contentSchema(["id"], ["title", "tldr", "summary_for_tutor", "tags", "min_chat_messages"]),
28
+ lens: contentSchema(["id"], [
29
+ "title",
30
+ "tldr",
31
+ "summary_for_tutor",
32
+ "tags",
33
+ "min_chat_messages",
34
+ "duration_minutes",
35
+ "reading_minutes",
36
+ "tutor_minutes",
37
+ ]),
29
38
  "learning-outcome": contentSchema(["id"], ["discussion", "learning-outcome", "tags", "domain", "stage", "requires"]),
30
39
  article: contentSchema(["title", "author", "source_url", "published"], [
31
40
  "created",
@@ -34,6 +43,13 @@ export const CONTENT_SCHEMAS = {
34
43
  "url",
35
44
  "allowAuthorInTitle",
36
45
  "allowUnreachableUrl",
46
+ "llm_reviewed",
47
+ "llm_review_version",
48
+ "llm_review_model",
49
+ "llm_review_digest",
50
+ "llm_review_source_digest",
51
+ "llm_review_source_fetched",
52
+ "llm_review_source_kind",
37
53
  ]),
38
54
  "video-transcript": contentSchema(["title", "channel", "url"],
39
55
  // from/to: default excerpt range applied when an embedding lens omits
@@ -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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"}
@@ -14,6 +14,12 @@ export function dedupeErrors(errors) {
14
14
  const seen = new Set();
15
15
  const deduped = [];
16
16
  for (const error of errors) {
17
+ // Output-integrity validation can see the same flattened segment with a
18
+ // resolved section title in the standalone pass and an empty title in an
19
+ // embedding module pass. The title is presentation context, not problem
20
+ // identity; retain the segment kind and ordinal so distinct segments are
21
+ // still reported independently.
22
+ const messageKey = error.message.replace(/^(Empty (?:text|article) segment|Empty video transcript) in ".*" (\(segment \d+\))$/, "$1 $2");
17
23
  // \x1f (unit separator) joins the fields: file paths and messages can
18
24
  // themselves contain spaces, so a printable separator could let two
19
25
  // distinct errors collapse to the same key.
@@ -21,7 +27,7 @@ export function dedupeErrors(errors) {
21
27
  error.file,
22
28
  error.line ?? "",
23
29
  error.severity,
24
- error.message,
30
+ messageKey,
25
31
  ].join("\x1f");
26
32
  if (seen.has(key))
27
33
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"dedupe-errors.js","sourceRoot":"","sources":["../src/dedupe-errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,sEAAsE;QACtE,oEAAoE;QACpE,4CAA4C;QAC5C,MAAM,GAAG,GAAG;YACV,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,IAAI,IAAI,EAAE;YAChB,KAAK,CAAC,QAAQ;YACd,KAAK,CAAC,OAAO;SACd,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACf,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"dedupe-errors.js","sourceRoot":"","sources":["../src/dedupe-errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,wEAAwE;QACxE,yEAAyE;QACzE,wEAAwE;QACxE,yEAAyE;QACzE,gCAAgC;QAChC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CACtC,qFAAqF,EACrF,OAAO,CACR,CAAC;QACF,sEAAsE;QACtE,oEAAoE;QACpE,4CAA4C;QAC5C,MAAM,GAAG,GAAG;YACV,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,IAAI,IAAI,EAAE;YAChB,KAAK,CAAC,QAAQ;YACd,UAAU;SACX,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACf,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -9,6 +9,7 @@ import { parseFrontmatter } from "../parser/frontmatter.js";
9
9
  import { fileNameToSlug } from "../utils/slug.js";
10
10
  import { extractArticleExcerpt, bundleArticleWithCollapsed, } from "../bundler/article.js";
11
11
  import { extractVideoExcerpt, resolveVideoRange, } from "../bundler/video.js";
12
+ import { attachSourceLine, getSourceLine } from "../source-location.js";
12
13
  function countWords(text) {
13
14
  return text.trim().split(/\s+/).filter(Boolean).length;
14
15
  }
@@ -56,6 +57,43 @@ function videoSegmentSeconds(seg) {
56
57
  return lastTimestamp - seg.from;
57
58
  return Math.round((transcriptWords / SPOKEN_WORDS_PER_MINUTE) * 60);
58
59
  }
60
+ /** The Section fields every lens read path copies verbatim from the parsed
61
+ * lens: identity, authored metadata, and segment-derived stats. Keeping them
62
+ * in one place means a new lens-level field is carried on all three paths
63
+ * (inline lens, module-referenced lens, standalone lens) by one change. */
64
+ function lensSectionFields(lens, segments, file, line, errors) {
65
+ const stats = computeSectionStats(segments);
66
+ // reading_minutes covers ALL content time including watching; a value
67
+ // below the lens's own video length is almost certainly "reading on top
68
+ // of the video" and would silently shrink the badge below the watch time
69
+ const videoMin = Math.ceil((stats.videoDurationSeconds ?? 0) / 60);
70
+ if (lens.readingMinutes !== undefined &&
71
+ videoMin > 0 &&
72
+ lens.readingMinutes < videoMin) {
73
+ errors.push({
74
+ file,
75
+ line,
76
+ message: `Field 'reading_minutes' is ${lens.readingMinutes}, less than the lens's ${videoMin} min of video (reading_minutes covers watch time too)`,
77
+ suggestion: "Set reading_minutes to the full content time including the video, or remove it to keep the computed estimate",
78
+ severity: "warning",
79
+ });
80
+ }
81
+ return {
82
+ segments,
83
+ learningOutcomeId: null,
84
+ learningOutcomeName: null,
85
+ contentId: lens.id ?? null,
86
+ tldr: lens.tldr,
87
+ summaryForTutor: lens.summaryForTutor,
88
+ minChatMessages: lens.minChatMessages,
89
+ durationMinutes: lens.durationMinutes,
90
+ readingMinutes: lens.readingMinutes,
91
+ tutorMinutes: lens.tutorMinutes,
92
+ addToAiContext: lens.addToAiContext,
93
+ ...stats,
94
+ displayType: computeDisplayType(segments),
95
+ };
96
+ }
59
97
  /** Compute word count and video duration from a section's segments. */
60
98
  function computeSectionStats(segments) {
61
99
  let words = 0;
@@ -646,23 +684,14 @@ function flattenLensSection(section, modulePath, files, visitedPaths, tierMap, i
646
684
  const hideConflict = checkHideOptionalConflict(effectiveOptional, effectiveHide, modulePath, section.line);
647
685
  if (hideConflict)
648
686
  errors.push(hideConflict);
649
- const resultSection = {
687
+ const resultSection = attachSourceLine({
650
688
  type: "lens",
651
689
  meta: { title: inlineLens.title || section.title },
652
- segments,
653
690
  sourcePath: modulePath,
654
691
  optional: effectiveOptional,
655
692
  ...(effectiveHide && { hide: true }),
656
- learningOutcomeId: null,
657
- learningOutcomeName: null,
658
- contentId: inlineLens.id ?? null,
659
- tldr: inlineLens.tldr,
660
- summaryForTutor: inlineLens.summaryForTutor,
661
- minChatMessages: inlineLens.minChatMessages,
662
- addToAiContext: inlineLens.addToAiContext,
663
- ...computeSectionStats(segments),
664
- displayType: computeDisplayType(segments),
665
- };
693
+ ...lensSectionFields(inlineLens, segments, modulePath, section.line, errors),
694
+ }, section.line);
666
695
  sections.push(resultSection);
667
696
  return { sections, errors };
668
697
  }
@@ -746,23 +775,14 @@ function flattenLensSection(section, modulePath, files, visitedPaths, tierMap, i
746
775
  const hideConflict = checkHideOptionalConflict(effectiveOptional, effectiveHide, modulePath, section.line);
747
776
  if (hideConflict)
748
777
  errors.push(hideConflict);
749
- const resultSection = {
778
+ const resultSection = attachSourceLine({
750
779
  type: "lens",
751
780
  meta: { title: lens.title || section.title },
752
- segments,
753
781
  sourcePath: lensPath,
754
782
  optional: effectiveOptional,
755
783
  ...(effectiveHide && { hide: true }),
756
- learningOutcomeId: null,
757
- learningOutcomeName: null,
758
- contentId: lens.id ?? null,
759
- tldr: lens.tldr,
760
- summaryForTutor: lens.summaryForTutor,
761
- minChatMessages: lens.minChatMessages,
762
- addToAiContext: lens.addToAiContext,
763
- ...computeSectionStats(segments),
764
- displayType: computeDisplayType(segments),
765
- };
784
+ ...lensSectionFields(lens, segments, lensPath, section.line, errors),
785
+ }, getSourceLine(lens));
766
786
  sections.push(resultSection);
767
787
  return { sections, errors };
768
788
  }
@@ -989,7 +1009,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
989
1009
  if (parsedSegment.optional) {
990
1010
  segment.optional = true;
991
1011
  }
992
- return { segment, errors };
1012
+ return {
1013
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1014
+ errors,
1015
+ };
993
1016
  }
994
1017
  case "chat": {
995
1018
  let instructions = parsedSegment.instructions;
@@ -1013,7 +1036,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1013
1036
  if (parsedSegment.hidePreviousContentFromTutor) {
1014
1037
  segment.hidePreviousContentFromTutor = true;
1015
1038
  }
1016
- return { segment, errors };
1039
+ return {
1040
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1041
+ errors,
1042
+ };
1017
1043
  }
1018
1044
  case "article": {
1019
1045
  // Source comes from the parsed segment (set via inheritance in parseLens)
@@ -1079,7 +1105,11 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1079
1105
  // Extract the excerpt
1080
1106
  const excerptResult = extractArticleExcerpt(articleContent, parsedSegment.fromAnchor, parsedSegment.toAnchor, articlePath);
1081
1107
  if (excerptResult.error) {
1082
- errors.push({ ...excerptResult.error, file: lensPath });
1108
+ errors.push({
1109
+ ...excerptResult.error,
1110
+ file: lensPath,
1111
+ line: getSourceLine(parsedSegment),
1112
+ });
1083
1113
  return { segment: null, errors };
1084
1114
  }
1085
1115
  const segment = {
@@ -1101,7 +1131,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1101
1131
  if (parsedSegment.optional) {
1102
1132
  segment.optional = true;
1103
1133
  }
1104
- return { segment, errors };
1134
+ return {
1135
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1136
+ errors,
1137
+ };
1105
1138
  }
1106
1139
  case "video": {
1107
1140
  // Source comes from the parsed segment (set via inheritance in parseLens)
@@ -1180,7 +1213,11 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1180
1213
  const { fromTime, toTime } = resolveVideoRange(parsedSegment.fromTimeStr, parsedSegment.toTimeStr, vfm);
1181
1214
  const excerptResult = extractVideoExcerpt(transcriptContent, fromTime, toTime, videoPath, timestamps);
1182
1215
  if (excerptResult.error) {
1183
- errors.push({ ...excerptResult.error, file: lensPath });
1216
+ errors.push({
1217
+ ...excerptResult.error,
1218
+ file: lensPath,
1219
+ line: getSourceLine(parsedSegment),
1220
+ });
1184
1221
  return { segment: null, errors };
1185
1222
  }
1186
1223
  const segment = {
@@ -1205,7 +1242,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1205
1242
  if (parsedSegment.optional) {
1206
1243
  segment.optional = true;
1207
1244
  }
1208
- return { segment, errors };
1245
+ return {
1246
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1247
+ errors,
1248
+ };
1209
1249
  }
1210
1250
  case "question": {
1211
1251
  let assessmentInstructions = parsedSegment.assessmentInstructions;
@@ -1235,7 +1275,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1235
1275
  segment.feedback = parsedSegment.feedback;
1236
1276
  if (parsedSegment.optional)
1237
1277
  segment.optional = true;
1238
- return { segment, errors };
1278
+ return {
1279
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1280
+ errors,
1281
+ };
1239
1282
  }
1240
1283
  case "roleplay": {
1241
1284
  let aiInstructions = parsedSegment.aiInstructions;
@@ -1272,7 +1315,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1272
1315
  segment.optional = true;
1273
1316
  if (parsedSegment.feedback)
1274
1317
  segment.feedback = true;
1275
- return { segment, errors };
1318
+ return {
1319
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1320
+ errors,
1321
+ };
1276
1322
  }
1277
1323
  case "embed": {
1278
1324
  if (!parsedSegment.source) {
@@ -1343,7 +1389,11 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1343
1389
  }
1344
1390
  const excerptResult = extractArticleExcerpt(articleContent, parsedSegment.fromAnchor, parsedSegment.toAnchor, articlePath);
1345
1391
  if (excerptResult.error) {
1346
- errors.push({ ...excerptResult.error, file: lensPath });
1392
+ errors.push({
1393
+ ...excerptResult.error,
1394
+ file: lensPath,
1395
+ line: getSourceLine(parsedSegment),
1396
+ });
1347
1397
  return { segment: null, errors };
1348
1398
  }
1349
1399
  const segment = {
@@ -1371,7 +1421,10 @@ function convertSegment(parsedSegment, lensPath, files, visitedPaths, tierMap) {
1371
1421
  segment.sandbox = parsedSegment.sandbox;
1372
1422
  if (parsedSegment.optional)
1373
1423
  segment.optional = true;
1374
- return { segment, errors };
1424
+ return {
1425
+ segment: attachSourceLine(segment, getSourceLine(parsedSegment)),
1426
+ errors,
1427
+ };
1375
1428
  }
1376
1429
  default:
1377
1430
  return { segment: null, errors };
@@ -1431,22 +1484,13 @@ export function flattenLens(lensPath, files, tierMap, preParsedLens) {
1431
1484
  .replace(/\b\w/g, (c) => c.toUpperCase());
1432
1485
  }
1433
1486
  }
1434
- const section = {
1487
+ const section = attachSourceLine({
1435
1488
  type: "lens",
1436
1489
  meta,
1437
- segments,
1438
1490
  sourcePath: lensPath,
1439
1491
  optional: false,
1440
- learningOutcomeId: null,
1441
- learningOutcomeName: null,
1442
- contentId: lens.id ?? null,
1443
- tldr: lens.tldr,
1444
- summaryForTutor: lens.summaryForTutor,
1445
- minChatMessages: lens.minChatMessages,
1446
- addToAiContext: lens.addToAiContext,
1447
- ...computeSectionStats(segments),
1448
- displayType: computeDisplayType(segments),
1449
- };
1492
+ ...lensSectionFields(lens, segments, lensPath, 1, errors),
1493
+ }, getSourceLine(lens));
1450
1494
  const flattenedModule = {
1451
1495
  slug: "lens/" + fileNameToSlug(lensPath),
1452
1496
  title: meta.title ?? fileNameToSlug(lensPath),