@bendyline/squisq 2.1.0 → 2.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 (442) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +24 -0
  3. package/README.md +8 -8
  4. package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
  5. package/dist/{Doc-DynJleo-.d.ts → Doc-COe-rPQB.d.ts} +7 -5
  6. package/dist/{ImageEditDoc-Ca4Tr9uN.d.ts → ImageEditDoc-dtKahVyD.d.ts} +1 -1
  7. package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
  8. package/dist/{chunk-VWCJ2WXC.js → chunk-2ZWIXGAC.js} +0 -1
  9. package/dist/{chunk-VYFRI7R6.js → chunk-32R2RZAO.js} +72 -3
  10. package/dist/chunk-3IGPAPQ7.js +645 -0
  11. package/dist/{chunk-QE7TWGVT.js → chunk-4VOD55SX.js} +0 -1
  12. package/dist/{chunk-3E5F2XMR.js → chunk-67L6WRJN.js} +0 -1
  13. package/dist/{chunk-5DKBFXPY.js → chunk-6ECMNUIP.js} +26 -18
  14. package/dist/{chunk-DBS6RIFL.js → chunk-7N4G32LG.js} +0 -1
  15. package/dist/{chunk-JOQYPRDZ.js → chunk-7YEZFHLS.js} +10 -8
  16. package/dist/{chunk-2UQOHYE2.js → chunk-7ZAAICW4.js} +0 -1
  17. package/dist/{chunk-66QO7XFB.js → chunk-ACZOVWX3.js} +117 -7
  18. package/dist/{chunk-5J4HKRJF.js → chunk-BAOV476U.js} +0 -1
  19. package/dist/chunk-BCCXTMN5.js +699 -0
  20. package/dist/{chunk-JHZWYRSW.js → chunk-C33GTPUZ.js} +11 -4
  21. package/dist/{chunk-XNLB57UD.js → chunk-EK446BUE.js} +18 -2
  22. package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
  23. package/dist/{chunk-JI77MGAK.js → chunk-GIIOY6XR.js} +2178 -1291
  24. package/dist/{chunk-Q7LROV2H.js → chunk-NKNMGIIN.js} +0 -1
  25. package/dist/chunk-OPO5K4DZ.js +241 -0
  26. package/dist/{chunk-TUWMK62B.js → chunk-PUS54YU6.js} +45 -2
  27. package/dist/{chunk-OTKVFVL6.js → chunk-QNTQIEIV.js} +130 -47
  28. package/dist/{chunk-5UYI3RJB.js → chunk-QWCFK5FN.js} +55 -40
  29. package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
  30. package/dist/{chunk-ILWDXLUK.js → chunk-RS5AP3J4.js} +49 -10
  31. package/dist/{chunk-QUUPYOSP.js → chunk-SPTY4C6F.js} +136 -5
  32. package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
  33. package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
  34. package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
  35. package/dist/doc/index.d.ts +311 -13
  36. package/dist/doc/index.js +25 -17
  37. package/dist/generate/index.d.ts +2 -2
  38. package/dist/generate/index.js +1 -3
  39. package/dist/icons/index.js +2 -4
  40. package/dist/icons/inlineIconMarker.js +1 -2
  41. package/dist/imageEdit/index.d.ts +48 -17
  42. package/dist/imageEdit/index.js +3 -4
  43. package/dist/index.d.ts +13 -13
  44. package/dist/index.js +67 -33
  45. package/dist/jsonForm/index.d.ts +10 -3
  46. package/dist/jsonForm/index.js +8 -7
  47. package/dist/markdown/index.d.ts +75 -11
  48. package/dist/markdown/index.js +32 -7
  49. package/dist/{materializePageSection-DDzubQXo.d.ts → materializePageSection-BSMOocve.d.ts} +2 -2
  50. package/dist/narration/index.d.ts +16 -3
  51. package/dist/narration/index.js +12 -14
  52. package/dist/random/index.d.ts +11 -2
  53. package/dist/random/index.js +1 -3
  54. package/dist/recommend/index.d.ts +1 -1
  55. package/dist/recommend/index.js +2 -4
  56. package/dist/schemas/index.d.ts +18 -6
  57. package/dist/schemas/index.js +7 -6
  58. package/dist/spatial/index.d.ts +2 -1
  59. package/dist/spatial/index.js +1 -2
  60. package/dist/storage/index.d.ts +4 -2
  61. package/dist/storage/index.js +1 -2
  62. package/dist/{themeLibrary-B72m0W1y.d.ts → themeLibrary-BUTWjufL.d.ts} +1 -1
  63. package/dist/timing/index.js +2 -4
  64. package/dist/transform/index.d.ts +3 -3
  65. package/dist/transform/index.js +6 -7
  66. package/dist/{types-C4kiRn_k.d.ts → types-8QjefM9J.d.ts} +38 -2
  67. package/dist/{types-BwMPl2CB.d.ts → types-CUNc9biN.d.ts} +24 -1
  68. package/dist/versions/index.d.ts +14 -11
  69. package/dist/versions/index.js +2 -3
  70. package/package.json +8 -3
  71. package/dist/chunk-2UQOHYE2.js.map +0 -1
  72. package/dist/chunk-3E5F2XMR.js.map +0 -1
  73. package/dist/chunk-4X3JQXNM.js.map +0 -1
  74. package/dist/chunk-5DKBFXPY.js.map +0 -1
  75. package/dist/chunk-5J4HKRJF.js.map +0 -1
  76. package/dist/chunk-5UYI3RJB.js.map +0 -1
  77. package/dist/chunk-66QO7XFB.js.map +0 -1
  78. package/dist/chunk-AMIR72JP.js +0 -380
  79. package/dist/chunk-AMIR72JP.js.map +0 -1
  80. package/dist/chunk-DBS6RIFL.js.map +0 -1
  81. package/dist/chunk-DNJKBAI7.js +0 -1
  82. package/dist/chunk-DNJKBAI7.js.map +0 -1
  83. package/dist/chunk-ET53IIEP.js +0 -1
  84. package/dist/chunk-ET53IIEP.js.map +0 -1
  85. package/dist/chunk-FVTQSNR7.js.map +0 -1
  86. package/dist/chunk-GZY66SDN.js.map +0 -1
  87. package/dist/chunk-ILWDXLUK.js.map +0 -1
  88. package/dist/chunk-JHZWYRSW.js.map +0 -1
  89. package/dist/chunk-JI77MGAK.js.map +0 -1
  90. package/dist/chunk-JOQYPRDZ.js.map +0 -1
  91. package/dist/chunk-OTKVFVL6.js.map +0 -1
  92. package/dist/chunk-PGGGKYWG.js +0 -1
  93. package/dist/chunk-PGGGKYWG.js.map +0 -1
  94. package/dist/chunk-Q7LROV2H.js.map +0 -1
  95. package/dist/chunk-QE7TWGVT.js.map +0 -1
  96. package/dist/chunk-QUUPYOSP.js.map +0 -1
  97. package/dist/chunk-R2GC6RLD.js +0 -344
  98. package/dist/chunk-R2GC6RLD.js.map +0 -1
  99. package/dist/chunk-R2YZTCLO.js.map +0 -1
  100. package/dist/chunk-S7A5D7ZJ.js +0 -174
  101. package/dist/chunk-S7A5D7ZJ.js.map +0 -1
  102. package/dist/chunk-TUWMK62B.js.map +0 -1
  103. package/dist/chunk-V543AI2F.js +0 -1
  104. package/dist/chunk-V543AI2F.js.map +0 -1
  105. package/dist/chunk-VR7UPJ7C.js.map +0 -1
  106. package/dist/chunk-VWCJ2WXC.js.map +0 -1
  107. package/dist/chunk-VYFRI7R6.js.map +0 -1
  108. package/dist/chunk-XNLB57UD.js.map +0 -1
  109. package/dist/chunk-ZLQKNOZQ.js +0 -1
  110. package/dist/chunk-ZLQKNOZQ.js.map +0 -1
  111. package/dist/doc/index.js.map +0 -1
  112. package/dist/generate/index.js.map +0 -1
  113. package/dist/icons/index.js.map +0 -1
  114. package/dist/icons/inlineIconMarker.js.map +0 -1
  115. package/dist/imageEdit/index.js.map +0 -1
  116. package/dist/index.js.map +0 -1
  117. package/dist/jsonForm/index.js.map +0 -1
  118. package/dist/markdown/index.js.map +0 -1
  119. package/dist/narration/index.js.map +0 -1
  120. package/dist/random/index.js.map +0 -1
  121. package/dist/recommend/index.js.map +0 -1
  122. package/dist/schemas/index.js.map +0 -1
  123. package/dist/spatial/index.js.map +0 -1
  124. package/dist/storage/index.js.map +0 -1
  125. package/dist/timing/index.js.map +0 -1
  126. package/dist/transform/index.js.map +0 -1
  127. package/dist/versions/index.js.map +0 -1
  128. package/src/__tests__/animationUtils.test.ts +0 -117
  129. package/src/__tests__/annotationCoercion.test.ts +0 -243
  130. package/src/__tests__/applyNarrationTiming.test.ts +0 -190
  131. package/src/__tests__/applyRenderStyle.test.ts +0 -146
  132. package/src/__tests__/asciiDiagramBattle.test.ts +0 -246
  133. package/src/__tests__/asciiDiagramDetect.test.ts +0 -162
  134. package/src/__tests__/asciiDiagramMapping.test.ts +0 -38
  135. package/src/__tests__/asciiDiagramParse.test.ts +0 -233
  136. package/src/__tests__/asciiDiagramPipeline.test.ts +0 -273
  137. package/src/__tests__/asciiDiagramRender.test.ts +0 -162
  138. package/src/__tests__/asciiDiagramRepair.test.ts +0 -84
  139. package/src/__tests__/asciiTimelineDetect.test.ts +0 -157
  140. package/src/__tests__/asciiTimelineParse.test.ts +0 -205
  141. package/src/__tests__/asciiTimelinePipeline.test.ts +0 -349
  142. package/src/__tests__/asciiTimelineRender.test.ts +0 -376
  143. package/src/__tests__/atmosphereLayers.test.ts +0 -108
  144. package/src/__tests__/attrTokens.test.ts +0 -167
  145. package/src/__tests__/colorUtils.test.ts +0 -112
  146. package/src/__tests__/contentContainer.test.ts +0 -325
  147. package/src/__tests__/contentExtractor.test.ts +0 -243
  148. package/src/__tests__/coverBlock.test.ts +0 -310
  149. package/src/__tests__/customTemplateSample.test.ts +0 -144
  150. package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -221
  151. package/src/__tests__/customThemesFrontmatter.test.ts +0 -146
  152. package/src/__tests__/dataTable.test.ts +0 -145
  153. package/src/__tests__/diagramBlock.test.ts +0 -122
  154. package/src/__tests__/diagramLayout.test.ts +0 -134
  155. package/src/__tests__/diagramText.test.ts +0 -26
  156. package/src/__tests__/docToMarkdownMedia.test.ts +0 -83
  157. package/src/__tests__/drawing.test.ts +0 -109
  158. package/src/__tests__/drawingBlock.test.ts +0 -124
  159. package/src/__tests__/drawingLayout.test.ts +0 -171
  160. package/src/__tests__/fixtures/asciiDiagramBattle.ts +0 -512
  161. package/src/__tests__/fixtures/asciiDiagrams.ts +0 -287
  162. package/src/__tests__/fixtures/asciiTimelines.ts +0 -35
  163. package/src/__tests__/fixtures/treeviewFixtures.ts +0 -243
  164. package/src/__tests__/geohash.test.ts +0 -110
  165. package/src/__tests__/getLayers.test.ts +0 -243
  166. package/src/__tests__/getLayersFallback.test.ts +0 -103
  167. package/src/__tests__/haversine.test.ts +0 -63
  168. package/src/__tests__/iconResolve.test.ts +0 -122
  169. package/src/__tests__/imageEditExportSvg.test.ts +0 -70
  170. package/src/__tests__/imageEditState.test.ts +0 -74
  171. package/src/__tests__/imageEditVersions.test.ts +0 -243
  172. package/src/__tests__/inferDocumentTitle.test.ts +0 -50
  173. package/src/__tests__/inlineIconMarker.test.ts +0 -36
  174. package/src/__tests__/inputDescriptors.test.ts +0 -162
  175. package/src/__tests__/jsonForm.chooseControl.test.ts +0 -86
  176. package/src/__tests__/jsonForm.evaluateWhen.test.ts +0 -59
  177. package/src/__tests__/jsonForm.inferSchema.test.ts +0 -25
  178. package/src/__tests__/jsonForm.pointer.test.ts +0 -149
  179. package/src/__tests__/jsonForm.tokens.test.ts +0 -84
  180. package/src/__tests__/layoutBlock.test.ts +0 -83
  181. package/src/__tests__/layoutLayout.test.ts +0 -169
  182. package/src/__tests__/localForageAdapter.test.ts +0 -155
  183. package/src/__tests__/majorApiTypes.test.ts +0 -18
  184. package/src/__tests__/markdown.test.ts +0 -1009
  185. package/src/__tests__/markdownIcons.test.ts +0 -104
  186. package/src/__tests__/markdownSanitize.test.ts +0 -81
  187. package/src/__tests__/markdownToDoc.test.ts +0 -957
  188. package/src/__tests__/matchFontFamily.test.ts +0 -114
  189. package/src/__tests__/materializeBlockLayers.test.ts +0 -167
  190. package/src/__tests__/materializePageSections.test.ts +0 -404
  191. package/src/__tests__/materializeTestUtils.ts +0 -17
  192. package/src/__tests__/mediaAnnotations.test.ts +0 -91
  193. package/src/__tests__/mediaSchedule.test.ts +0 -118
  194. package/src/__tests__/narrationAlign.test.ts +0 -150
  195. package/src/__tests__/narrationFeatures.test.ts +0 -71
  196. package/src/__tests__/narrationNuclei.test.ts +0 -45
  197. package/src/__tests__/narrationPacing.test.ts +0 -189
  198. package/src/__tests__/narrationScript.test.ts +0 -149
  199. package/src/__tests__/narrationSessionRepro.test.ts +0 -62
  200. package/src/__tests__/narrationSidecar.test.ts +0 -88
  201. package/src/__tests__/narrationSyllables.test.ts +0 -65
  202. package/src/__tests__/narrationTestSignals.ts +0 -167
  203. package/src/__tests__/narrationVad.test.ts +0 -66
  204. package/src/__tests__/pageStyle.test.ts +0 -258
  205. package/src/__tests__/pandocAttrParse.test.ts +0 -187
  206. package/src/__tests__/recommendTemplates.test.ts +0 -183
  207. package/src/__tests__/resolveDocTheme.test.ts +0 -69
  208. package/src/__tests__/rootExports.test.ts +0 -61
  209. package/src/__tests__/scopedContentContainer.test.ts +0 -109
  210. package/src/__tests__/seededRandom.test.ts +0 -142
  211. package/src/__tests__/shapeGeometry.test.ts +0 -138
  212. package/src/__tests__/shapeVocabulary.test.ts +0 -133
  213. package/src/__tests__/storage.test.ts +0 -60
  214. package/src/__tests__/structuredData.test.ts +0 -249
  215. package/src/__tests__/surface.test.ts +0 -68
  216. package/src/__tests__/templateAnnotationParse.test.ts +0 -173
  217. package/src/__tests__/templateInputs.test.ts +0 -69
  218. package/src/__tests__/templateMetadata.test.ts +0 -32
  219. package/src/__tests__/templates.test.ts +0 -710
  220. package/src/__tests__/themeCompile.test.ts +0 -225
  221. package/src/__tests__/themeValidator.test.ts +0 -131
  222. package/src/__tests__/timing.test.ts +0 -167
  223. package/src/__tests__/transformProvenance.test.ts +0 -160
  224. package/src/__tests__/transformV2.test.ts +0 -163
  225. package/src/__tests__/transitionNormalize.test.ts +0 -61
  226. package/src/__tests__/treeviewBattle.test.ts +0 -76
  227. package/src/__tests__/treeviewDetect.test.ts +0 -168
  228. package/src/__tests__/treeviewParse.test.ts +0 -118
  229. package/src/__tests__/treeviewPipeline.test.ts +0 -183
  230. package/src/__tests__/treeviewRender.test.ts +0 -91
  231. package/src/__tests__/validateDoc.test.ts +0 -260
  232. package/src/__tests__/versions.test.ts +0 -459
  233. package/src/doc/annotationBlocks.ts +0 -117
  234. package/src/doc/applyNarrationTiming.ts +0 -244
  235. package/src/doc/asciiDiagram/chars.ts +0 -210
  236. package/src/doc/asciiDiagram/detect.ts +0 -175
  237. package/src/doc/asciiDiagram/index.ts +0 -38
  238. package/src/doc/asciiDiagram/mapping.ts +0 -225
  239. package/src/doc/asciiDiagram/parse.ts +0 -1095
  240. package/src/doc/asciiDiagram/render.ts +0 -963
  241. package/src/doc/asciiDiagram/repair.ts +0 -400
  242. package/src/doc/asciiDiagram/types.ts +0 -65
  243. package/src/doc/asciiTimeline/detect.ts +0 -138
  244. package/src/doc/asciiTimeline/index.ts +0 -26
  245. package/src/doc/asciiTimeline/mapping.ts +0 -43
  246. package/src/doc/asciiTimeline/parse.ts +0 -870
  247. package/src/doc/asciiTimeline/render.ts +0 -427
  248. package/src/doc/asciiTimeline/types.ts +0 -73
  249. package/src/doc/asciiTimeline/wrappedFlow.ts +0 -427
  250. package/src/doc/audioMapping.ts +0 -442
  251. package/src/doc/customTemplatesFrontmatter.ts +0 -273
  252. package/src/doc/customThemesFrontmatter.ts +0 -95
  253. package/src/doc/docToMarkdown.ts +0 -284
  254. package/src/doc/index.ts +0 -161
  255. package/src/doc/markdownToDoc.ts +0 -1054
  256. package/src/doc/materializeBlockLayers.ts +0 -465
  257. package/src/doc/mediaAnnotations.ts +0 -120
  258. package/src/doc/page/PageSection.ts +0 -174
  259. package/src/doc/page/materializePageSection.ts +0 -616
  260. package/src/doc/page/resolvePageBlock.ts +0 -108
  261. package/src/doc/page/sectionExtractors.ts +0 -466
  262. package/src/doc/pageCss.ts +0 -628
  263. package/src/doc/resolveDocTheme.ts +0 -56
  264. package/src/doc/standaloneAnnotation.ts +0 -58
  265. package/src/doc/structuredData.ts +0 -301
  266. package/src/doc/templateInputs.ts +0 -424
  267. package/src/doc/templates/__tests__/customTemplate.test.ts +0 -170
  268. package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +0 -124
  269. package/src/doc/templates/__tests__/listBlock.test.ts +0 -64
  270. package/src/doc/templates/accentImage.ts +0 -362
  271. package/src/doc/templates/captionUtils.ts +0 -56
  272. package/src/doc/templates/comparisonBar.ts +0 -173
  273. package/src/doc/templates/coverBlock.ts +0 -255
  274. package/src/doc/templates/customTemplate.ts +0 -51
  275. package/src/doc/templates/dataTable.ts +0 -102
  276. package/src/doc/templates/dateEvent.ts +0 -147
  277. package/src/doc/templates/definitionCard.ts +0 -140
  278. package/src/doc/templates/diagramBlock.ts +0 -403
  279. package/src/doc/templates/diagramLayout.ts +0 -159
  280. package/src/doc/templates/drawingBlock.ts +0 -325
  281. package/src/doc/templates/drawingLayout.ts +0 -539
  282. package/src/doc/templates/factCard.ts +0 -146
  283. package/src/doc/templates/fallbackBlock.ts +0 -123
  284. package/src/doc/templates/featureBlock.ts +0 -209
  285. package/src/doc/templates/fullBleedQuote.ts +0 -83
  286. package/src/doc/templates/imageWithCaption.ts +0 -186
  287. package/src/doc/templates/index.ts +0 -642
  288. package/src/doc/templates/inputDescriptors.ts +0 -451
  289. package/src/doc/templates/layoutBlock.ts +0 -43
  290. package/src/doc/templates/layoutLayout.ts +0 -243
  291. package/src/doc/templates/listBlock.ts +0 -207
  292. package/src/doc/templates/mapBlock.ts +0 -138
  293. package/src/doc/templates/metadata.ts +0 -130
  294. package/src/doc/templates/persistentLayers.ts +0 -526
  295. package/src/doc/templates/photoGrid.ts +0 -190
  296. package/src/doc/templates/pullQuote.ts +0 -141
  297. package/src/doc/templates/quoteBlock.ts +0 -141
  298. package/src/doc/templates/registry.ts +0 -88
  299. package/src/doc/templates/sectionHeader.ts +0 -120
  300. package/src/doc/templates/statHighlight.ts +0 -146
  301. package/src/doc/templates/templateNames.ts +0 -22
  302. package/src/doc/templates/timelineBlock.ts +0 -613
  303. package/src/doc/templates/titleBlock.ts +0 -150
  304. package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +0 -487
  305. package/src/doc/templates/tokens/resolveTokens.ts +0 -453
  306. package/src/doc/templates/treeBlock.ts +0 -131
  307. package/src/doc/templates/twoColumn.ts +0 -263
  308. package/src/doc/templates/videoPullQuote.ts +0 -142
  309. package/src/doc/templates/videoWithCaption.ts +0 -135
  310. package/src/doc/treeview/chars.ts +0 -72
  311. package/src/doc/treeview/detect.ts +0 -145
  312. package/src/doc/treeview/index.ts +0 -30
  313. package/src/doc/treeview/mapping.ts +0 -95
  314. package/src/doc/treeview/parse.ts +0 -201
  315. package/src/doc/treeview/render.ts +0 -41
  316. package/src/doc/treeview/types.ts +0 -43
  317. package/src/doc/utils/animationUtils.ts +0 -399
  318. package/src/doc/utils/applyRenderStyle.ts +0 -106
  319. package/src/doc/utils/diagramText.ts +0 -78
  320. package/src/doc/utils/imageTreatment.ts +0 -70
  321. package/src/doc/utils/nearest.ts +0 -59
  322. package/src/doc/utils/shapeGeometry.ts +0 -614
  323. package/src/doc/utils/themeUtils.ts +0 -243
  324. package/src/doc/validate.ts +0 -575
  325. package/src/generate/contentExtractor.ts +0 -921
  326. package/src/generate/index.ts +0 -18
  327. package/src/generate/templateMapper.ts +0 -177
  328. package/src/icons/iconData.ts +0 -31
  329. package/src/icons/index.ts +0 -26
  330. package/src/icons/inlineIconMarker.ts +0 -73
  331. package/src/icons/resolve.ts +0 -139
  332. package/src/imageEdit/ImageEditVersionManager.ts +0 -73
  333. package/src/imageEdit/export.ts +0 -410
  334. package/src/imageEdit/index.ts +0 -72
  335. package/src/imageEdit/persistence.ts +0 -113
  336. package/src/imageEdit/state.ts +0 -112
  337. package/src/imageEdit/versionPaths.ts +0 -44
  338. package/src/imageEdit/versions.ts +0 -152
  339. package/src/index.ts +0 -15
  340. package/src/internal/immutable.ts +0 -58
  341. package/src/jsonForm/chooseControl.ts +0 -88
  342. package/src/jsonForm/evaluateWhen.ts +0 -59
  343. package/src/jsonForm/index.ts +0 -32
  344. package/src/jsonForm/inferSchema.ts +0 -25
  345. package/src/jsonForm/pointer.ts +0 -154
  346. package/src/jsonForm/tokens.ts +0 -78
  347. package/src/jsonForm/types.ts +0 -167
  348. package/src/markdown/annotationCoercion.ts +0 -295
  349. package/src/markdown/attrTokens.ts +0 -243
  350. package/src/markdown/convert.ts +0 -1353
  351. package/src/markdown/htmlParse.ts +0 -212
  352. package/src/markdown/index.ts +0 -152
  353. package/src/markdown/parse.ts +0 -103
  354. package/src/markdown/sanitize.ts +0 -318
  355. package/src/markdown/stringify.ts +0 -207
  356. package/src/markdown/types.ts +0 -710
  357. package/src/markdown/utils.ts +0 -459
  358. package/src/narration/align.ts +0 -514
  359. package/src/narration/features.ts +0 -231
  360. package/src/narration/index.ts +0 -86
  361. package/src/narration/nuclei.ts +0 -118
  362. package/src/narration/pacing.ts +0 -211
  363. package/src/narration/script.ts +0 -239
  364. package/src/narration/session.ts +0 -100
  365. package/src/narration/sidecar.ts +0 -187
  366. package/src/narration/syllables.ts +0 -85
  367. package/src/narration/trace.ts +0 -50
  368. package/src/narration/types.ts +0 -299
  369. package/src/narration/vad.ts +0 -131
  370. package/src/ngeohash.d.ts +0 -11
  371. package/src/random/SeededRandom.ts +0 -127
  372. package/src/random/index.ts +0 -1
  373. package/src/recommend/index.ts +0 -16
  374. package/src/recommend/numberHighlight.ts +0 -25
  375. package/src/recommend/templates.ts +0 -393
  376. package/src/schemas/BlockTemplates.ts +0 -1046
  377. package/src/schemas/CustomTemplates.ts +0 -126
  378. package/src/schemas/Doc.ts +0 -1073
  379. package/src/schemas/ImageEditDoc.ts +0 -102
  380. package/src/schemas/LayoutStrategy.ts +0 -178
  381. package/src/schemas/Media.ts +0 -179
  382. package/src/schemas/MediaProvider.ts +0 -70
  383. package/src/schemas/PageStyle.ts +0 -213
  384. package/src/schemas/Theme.ts +0 -413
  385. package/src/schemas/Transitions.ts +0 -224
  386. package/src/schemas/Types.ts +0 -15
  387. package/src/schemas/Viewport.ts +0 -91
  388. package/src/schemas/colorUtils.ts +0 -219
  389. package/src/schemas/fontStacks.ts +0 -339
  390. package/src/schemas/index.ts +0 -31
  391. package/src/schemas/pageStyleDefaults.ts +0 -204
  392. package/src/schemas/themeCompile.ts +0 -244
  393. package/src/schemas/themeConstants.ts +0 -2
  394. package/src/schemas/themeLibrary.ts +0 -60
  395. package/src/schemas/themeValidator.ts +0 -609
  396. package/src/schemas/themes/bold.json +0 -77
  397. package/src/schemas/themes/cinematic.json +0 -143
  398. package/src/schemas/themes/documentary.json +0 -125
  399. package/src/schemas/themes/gezellig.json +0 -123
  400. package/src/schemas/themes/index.ts +0 -53
  401. package/src/schemas/themes/magazine.json +0 -126
  402. package/src/schemas/themes/minimalist.json +0 -74
  403. package/src/schemas/themes/morning-light.json +0 -117
  404. package/src/schemas/themes/standard-dark.json +0 -109
  405. package/src/schemas/themes/standard.json +0 -98
  406. package/src/schemas/themes/tech-dark.json +0 -143
  407. package/src/schemas/themes/warm-earth.json +0 -74
  408. package/src/spatial/Geohash.ts +0 -196
  409. package/src/spatial/Haversine.ts +0 -59
  410. package/src/spatial/index.ts +0 -2
  411. package/src/storage/ContentContainer.ts +0 -220
  412. package/src/storage/LocalForageAdapter.ts +0 -103
  413. package/src/storage/LocalStorageAdapter.ts +0 -57
  414. package/src/storage/MediaProviderFromContainer.ts +0 -92
  415. package/src/storage/MemoryStorageAdapter.ts +0 -37
  416. package/src/storage/ScopedContentContainer.ts +0 -143
  417. package/src/storage/Storage.ts +0 -28
  418. package/src/storage/index.ts +0 -9
  419. package/src/timing/index.ts +0 -17
  420. package/src/timing/narrationTiming.ts +0 -220
  421. package/src/timing/readingTime.ts +0 -94
  422. package/src/transform/applyTransform.ts +0 -122
  423. package/src/transform/blockAnalyzer.ts +0 -181
  424. package/src/transform/index.ts +0 -23
  425. package/src/transform/registry.ts +0 -217
  426. package/src/transform/styles/dataDriven.ts +0 -18
  427. package/src/transform/styles/documentary.ts +0 -18
  428. package/src/transform/styles/index.ts +0 -5
  429. package/src/transform/styles/magazine.ts +0 -19
  430. package/src/transform/styles/minimal.ts +0 -18
  431. package/src/transform/styles/narrative.ts +0 -19
  432. package/src/transform/templateSelector.ts +0 -389
  433. package/src/transform/timingAllocator.ts +0 -257
  434. package/src/transform/types.ts +0 -158
  435. package/src/versions/DocumentVersionManager.ts +0 -70
  436. package/src/versions/gitignore.ts +0 -34
  437. package/src/versions/index.ts +0 -56
  438. package/src/versions/operations.ts +0 -144
  439. package/src/versions/paths.ts +0 -51
  440. package/src/versions/snapshotStore.ts +0 -202
  441. package/src/versions/timestamp.ts +0 -48
  442. package/src/versions/types.ts +0 -93
@@ -1,921 +0,0 @@
1
- /**
2
- * Content Extractor
3
- *
4
- * Pattern-based extraction of compelling content from plain text.
5
- * Identifies statistics, dates, quotes, comparisons, facts, impact lines,
6
- * lists, and definitions that can be turned into slideshow slides.
7
- *
8
- * Extraction is purely regex-based — no AI calls, no runtime costs,
9
- * deterministic and reproducible.
10
- */
11
-
12
- // ── Types ──────────────────────────────────────────────────────────
13
-
14
- /** Kinds of content the extractor recognises. */
15
- export type ExtractionType =
16
- | 'stat'
17
- | 'date'
18
- | 'quote'
19
- | 'comparison'
20
- | 'fact'
21
- | 'impactLine'
22
- | 'list'
23
- | 'definition';
24
-
25
- /** An extracted content element with source position. */
26
- export interface ExtractedElement {
27
- type: ExtractionType;
28
- /** Full extracted text (usually the surrounding sentence). */
29
- text: string;
30
- /** Confidence score 0–1. */
31
- confidence: number;
32
- /** Character offset in the source text. */
33
- sourcePosition: number;
34
- /** Character offset where element ends. */
35
- endPosition: number;
36
- /** Type-specific structured payload. */
37
- data:
38
- | StatData
39
- | DateData
40
- | QuoteData
41
- | ComparisonData
42
- | FactData
43
- | ImpactLineData
44
- | ListData
45
- | DefinitionData;
46
- }
47
-
48
- export interface StatData {
49
- type: 'stat';
50
- value: string;
51
- unit?: string;
52
- description: string;
53
- }
54
-
55
- export interface DateData {
56
- type: 'date';
57
- date: string;
58
- description: string;
59
- mood?: 'neutral' | 'somber' | 'celebratory';
60
- }
61
-
62
- export interface QuoteData {
63
- type: 'quote';
64
- quote: string;
65
- attribution?: string;
66
- }
67
-
68
- export interface ComparisonData {
69
- type: 'comparison';
70
- left: { label: string; sublabel?: string };
71
- right: { label: string; sublabel?: string };
72
- header?: string;
73
- }
74
-
75
- export interface FactData {
76
- type: 'fact';
77
- fact: string;
78
- explanation?: string;
79
- }
80
-
81
- export interface ImpactLineData {
82
- type: 'impactLine';
83
- text: string;
84
- }
85
-
86
- export interface ListData {
87
- type: 'list';
88
- items: string[];
89
- title?: string;
90
- }
91
-
92
- export interface DefinitionData {
93
- type: 'definition';
94
- term: string;
95
- definition: string;
96
- origin?: string;
97
- }
98
-
99
- /** Options for `extractContent`. */
100
- export interface ExtractionOptions {
101
- /** Minimum confidence threshold (default: 0.3). */
102
- minConfidence?: number;
103
- /** Which types to extract (default: all). */
104
- types?: ExtractionType[];
105
- /** Maximum extractions per type (default: unlimited). */
106
- maxPerType?: number;
107
- }
108
-
109
- /** Result of `extractContent`. */
110
- export interface ExtractionResult {
111
- elements: ExtractedElement[];
112
- sourceLength: number;
113
- stats: {
114
- statCount: number;
115
- dateCount: number;
116
- quoteCount: number;
117
- comparisonCount: number;
118
- factCount: number;
119
- impactLineCount: number;
120
- listCount: number;
121
- definitionCount: number;
122
- totalCount: number;
123
- };
124
- }
125
-
126
- // ── Patterns ───────────────────────────────────────────────────────
127
-
128
- const STAT_PATTERNS = [
129
- /\b(roughly |about |approximately |nearly |over |under |more than |less than )?([\d,]+(?:\.\d+)?)\s*%/gi,
130
- /\b([\d,]+(?:\.\d+)?)\s*(million|billion|trillion|thousand|hundred)\b/gi,
131
- /\b([\d,]+(?:\.\d+)?)\s*(miles?|feet|ft|meters?|m|kilometers?|km|acres?|square miles?|sq mi|hectares?)\b/gi,
132
- /\b([\d,]+(?:\.\d+)?)\s*(x|times)\b/gi,
133
- /\b([$€£¥])\s*([\d,]+(?:\.\d+)?)\s*(million|billion|thousand)?\b/gi,
134
- /\b(\d+)(st|nd|rd|th)\s+(largest|smallest|oldest|newest|most|least)/gi,
135
- ];
136
-
137
- const DATE_PATTERNS = [
138
- /\b(January|February|March|April|May|June|July|August|September|October|November|December)\s+(\d{1,2},?\s+)?(\d{4})\b/gi,
139
- /\b(\d{4})s\b|\b(\d{1,2})(st|nd|rd|th)\s+century\b/gi,
140
- /\b(from\s+)?(\d{4})\s*(to|–|-|through)\s*(\d{4})\b/gi,
141
- /\b(in|by|since|after|before|during)\s+(\d{4})\b/gi,
142
- ];
143
-
144
- const QUOTE_PATTERNS = [
145
- /"([^"]{15,200})"/g,
146
- /\u201c([^\u201d]{15,200})\u201d/g,
147
- /(\w+(?:\s+\w+)?)\s+(?:said|stated|wrote|noted|observed|commented),?\s*"([^"]+)"/gi,
148
- ];
149
-
150
- // A single side of a comparison ("X" in "from X to Y"). Deliberately excludes
151
- // sentence/clause terminators (. ! ? ;) and newlines so a capture group can
152
- // never swallow text from an adjacent sentence. Without this, greedy `.{2,30}`
153
- // matches across a period — e.g. "…contradicted from witness to witness.
154
- // Robertson said…" yields right="witness. Robertson", producing a nonsensical
155
- // "witness → witness. Robertson" slide. Commas and colons are allowed (ranges
156
- // like "9:00 to 17:00", ratios); downstream label truncation trims commas.
157
- const COMPARISON_SIDE = '[^.!?;\\r\\n]{2,30}';
158
-
159
- const COMPARISON_PATTERNS = [
160
- new RegExp(`from\\s+(${COMPARISON_SIDE})\\s+to\\s+(${COMPARISON_SIDE})`, 'gi'),
161
- new RegExp(`(${COMPARISON_SIDE})\\s+(?:vs\\.?|versus)\\s+(${COMPARISON_SIDE})`, 'gi'),
162
- new RegExp(`(${COMPARISON_SIDE})\\s+compared\\s+to\\s+(${COMPARISON_SIDE})`, 'gi'),
163
- ];
164
-
165
- // Words whose trailing period is an abbreviation, not a sentence end. Used by
166
- // isSentenceBoundary() so names like "George W. Tibbetts" or "Quong Chong & Co."
167
- // don't get split into fragments. Matched only when the entire preceding word
168
- // equals one of these (case-insensitive), so "canal." / "taco." are unaffected.
169
- const SENTENCE_ABBREVIATIONS = new Set([
170
- 'mr',
171
- 'mrs',
172
- 'ms',
173
- 'dr',
174
- 'prof',
175
- 'st',
176
- 'mt',
177
- 'jr',
178
- 'sr',
179
- 'gen',
180
- 'col',
181
- 'capt',
182
- 'lt',
183
- 'sgt',
184
- 'rev',
185
- 'hon',
186
- 'sen',
187
- 'rep',
188
- 'gov',
189
- 'pres',
190
- 'vs',
191
- 'etc',
192
- 'inc',
193
- 'co',
194
- 'ltd',
195
- 'corp',
196
- 'al',
197
- 'fig',
198
- 'eg',
199
- 'ie',
200
- 'approx',
201
- 'dept',
202
- 'univ',
203
- 'assn',
204
- 'bros',
205
- 'ave',
206
- 'blvd',
207
- 'rd',
208
- ]);
209
-
210
- const FACT_INDICATORS = [
211
- 'largest',
212
- 'smallest',
213
- 'oldest',
214
- 'newest',
215
- 'first',
216
- 'last',
217
- 'most',
218
- 'least',
219
- 'only',
220
- 'unique',
221
- 'rare',
222
- 'famous',
223
- 'important',
224
- 'significant',
225
- 'notable',
226
- 'remarkable',
227
- 'extraordinary',
228
- 'crucial',
229
- 'essential',
230
- 'critical',
231
- 'major',
232
- 'key',
233
- 'discovered',
234
- 'founded',
235
- 'established',
236
- 'created',
237
- 'built',
238
- 'invented',
239
- 'developed',
240
- 'introduced',
241
- 'pioneered',
242
- 'transformed',
243
- 'revolutionized',
244
- 'changed',
245
- 'shaped',
246
- ];
247
-
248
- const SOMBER_INDICATORS = [
249
- 'disaster',
250
- 'tragedy',
251
- 'death',
252
- 'died',
253
- 'killed',
254
- 'destroyed',
255
- 'devastated',
256
- 'collapsed',
257
- 'lost',
258
- 'abandoned',
259
- 'declined',
260
- 'war',
261
- 'battle',
262
- 'conflict',
263
- 'earthquake',
264
- 'fire',
265
- 'flood',
266
- ];
267
-
268
- const CELEBRATORY_INDICATORS = [
269
- 'celebration',
270
- 'victory',
271
- 'success',
272
- 'achievement',
273
- 'triumph',
274
- 'opened',
275
- 'completed',
276
- 'inaugurated',
277
- 'launched',
278
- 'won',
279
- 'record',
280
- 'breakthrough',
281
- 'milestone',
282
- 'golden',
283
- 'grand',
284
- ];
285
-
286
- const IMPACT_VERBS = [
287
- 'check',
288
- 'watch',
289
- 'stop',
290
- 'prepare',
291
- 'imagine',
292
- 'consider',
293
- 'look',
294
- 'listen',
295
- 'notice',
296
- 'remember',
297
- 'discover',
298
- 'explore',
299
- 'visit',
300
- 'try',
301
- 'experience',
302
- 'avoid',
303
- 'beware',
304
- 'enjoy',
305
- ];
306
-
307
- const LIST_PATTERNS = [
308
- /(?:including|such as|namely|like|features?|offers?)\s+([^.]{10,150})/gi,
309
- /(?:three|four|five|six|several|many|various)\s+(?:main|key|primary|notable|popular|important)?\s*\w+(?:\s+\w+)?:\s*([^.]{10,150})/gi,
310
- ];
311
-
312
- const DEFINITION_PATTERNS = [
313
- /\b([A-Z][a-z]+(?:\s+[A-Z]?[a-z]+){0,3})\s+is\s+(?:a|an|the)\s+([^.]{10,120})/g,
314
- /known\s+as\s+([A-Z][a-z]+(?:\s+[A-Z]?[a-z]+){0,3}),\s+([^.]{10,120})/gi,
315
- /\b([A-Z][a-z]+(?:\s+[A-Z]?[a-z]+){0,3})\s+refers?\s+to\s+([^.]{10,120})/g,
316
- /called\s+([A-Z][a-z]+(?:\s+[A-Z]?[a-z]+){0,3}),?\s+(?:which|meaning|a)\s+([^.]{10,120})/gi,
317
- ];
318
-
319
- // ── Main ───────────────────────────────────────────────────────────
320
-
321
- /**
322
- * Extract compelling content from plain text.
323
- *
324
- * Call `stripMarkdown(text)` first if the input contains markdown.
325
- */
326
- export function extractContent(text: string, options: ExtractionOptions = {}): ExtractionResult {
327
- const {
328
- minConfidence = 0.3,
329
- types = ['stat', 'date', 'quote', 'comparison', 'fact', 'impactLine', 'list', 'definition'],
330
- maxPerType,
331
- } = options;
332
-
333
- const elements: ExtractedElement[] = [];
334
-
335
- if (types.includes('stat')) elements.push(...extractStats(text));
336
- if (types.includes('date')) elements.push(...extractDates(text));
337
- if (types.includes('quote')) elements.push(...extractQuotes(text));
338
- if (types.includes('comparison')) elements.push(...extractComparisons(text));
339
- if (types.includes('fact')) elements.push(...extractFacts(text));
340
- if (types.includes('impactLine')) elements.push(...extractImpactLines(text));
341
- if (types.includes('list')) elements.push(...extractLists(text));
342
- if (types.includes('definition')) elements.push(...extractDefinitions(text));
343
-
344
- let filtered = elements.filter((e) => e.confidence >= minConfidence);
345
-
346
- if (maxPerType !== undefined) {
347
- const byType = new Map<ExtractionType, ExtractedElement[]>();
348
- for (const elem of filtered) {
349
- const list = byType.get(elem.type) || [];
350
- list.push(elem);
351
- byType.set(elem.type, list);
352
- }
353
- filtered = [];
354
- for (const [, list] of byType) {
355
- list.sort((a, b) => b.confidence - a.confidence);
356
- filtered.push(...list.slice(0, maxPerType));
357
- }
358
- }
359
-
360
- filtered.sort((a, b) => a.sourcePosition - b.sourcePosition);
361
- filtered = deduplicateOverlapping(filtered);
362
-
363
- return {
364
- elements: filtered,
365
- sourceLength: text.length,
366
- stats: {
367
- statCount: filtered.filter((e) => e.type === 'stat').length,
368
- dateCount: filtered.filter((e) => e.type === 'date').length,
369
- quoteCount: filtered.filter((e) => e.type === 'quote').length,
370
- comparisonCount: filtered.filter((e) => e.type === 'comparison').length,
371
- factCount: filtered.filter((e) => e.type === 'fact').length,
372
- impactLineCount: filtered.filter((e) => e.type === 'impactLine').length,
373
- listCount: filtered.filter((e) => e.type === 'list').length,
374
- definitionCount: filtered.filter((e) => e.type === 'definition').length,
375
- totalCount: filtered.length,
376
- },
377
- };
378
- }
379
-
380
- // ── Per-type extractors ────────────────────────────────────────────
381
-
382
- function extractStats(text: string): ExtractedElement[] {
383
- const elements: ExtractedElement[] = [];
384
- const seen = new Set<number>();
385
-
386
- for (const pattern of STAT_PATTERNS) {
387
- pattern.lastIndex = 0;
388
- let match;
389
- while ((match = pattern.exec(text)) !== null) {
390
- const position = match.index;
391
- if (seen.has(position)) continue;
392
- seen.add(position);
393
-
394
- const context = getSentenceContext(text, position, match[0].length);
395
- const value = match[0].trim();
396
-
397
- elements.push({
398
- type: 'stat',
399
- text: context.sentence,
400
- confidence: calculateStatConfidence(value, context.sentence),
401
- sourcePosition: context.start,
402
- endPosition: context.end,
403
- data: { type: 'stat', value, description: cleanDescription(context.sentence, value) },
404
- });
405
- }
406
- }
407
- return elements;
408
- }
409
-
410
- function extractDates(text: string): ExtractedElement[] {
411
- const elements: ExtractedElement[] = [];
412
- const seen = new Set<number>();
413
-
414
- for (const pattern of DATE_PATTERNS) {
415
- pattern.lastIndex = 0;
416
- let match;
417
- while ((match = pattern.exec(text)) !== null) {
418
- const position = match.index;
419
- if (seen.has(position)) continue;
420
- seen.add(position);
421
-
422
- const context = getSentenceContext(text, position, match[0].length);
423
- const dateStr = match[0].trim();
424
-
425
- elements.push({
426
- type: 'date',
427
- text: context.sentence,
428
- confidence: calculateDateConfidence(dateStr, context.sentence),
429
- sourcePosition: context.start,
430
- endPosition: context.end,
431
- data: {
432
- type: 'date',
433
- date: dateStr,
434
- description: cleanDescription(context.sentence, dateStr),
435
- mood: detectMood(context.sentence),
436
- },
437
- });
438
- }
439
- }
440
- return elements;
441
- }
442
-
443
- function extractQuotes(text: string): ExtractedElement[] {
444
- const elements: ExtractedElement[] = [];
445
- const seen = new Set<number>();
446
-
447
- for (const pattern of QUOTE_PATTERNS) {
448
- pattern.lastIndex = 0;
449
- let match;
450
- while ((match = pattern.exec(text)) !== null) {
451
- const position = match.index;
452
- if (seen.has(position)) continue;
453
- seen.add(position);
454
-
455
- const quote = match.length > 2 ? match[2] : match[1];
456
- const attribution = match.length > 2 ? match[1] : undefined;
457
- if (quote.length < 15 || quote.length > 200) continue;
458
-
459
- elements.push({
460
- type: 'quote',
461
- text: match[0],
462
- confidence: calculateQuoteConfidence(quote),
463
- sourcePosition: position,
464
- endPosition: position + match[0].length,
465
- data: { type: 'quote', quote: quote.trim(), attribution: attribution?.trim() },
466
- });
467
- }
468
- }
469
- return elements;
470
- }
471
-
472
- function extractComparisons(text: string): ExtractedElement[] {
473
- const elements: ExtractedElement[] = [];
474
- const seen = new Set<number>();
475
-
476
- for (const pattern of COMPARISON_PATTERNS) {
477
- pattern.lastIndex = 0;
478
- let match;
479
- while ((match = pattern.exec(text)) !== null) {
480
- const position = match.index;
481
- if (seen.has(position)) continue;
482
- seen.add(position);
483
-
484
- // Trim a trailing clause introduced by a comma + space ("retired
485
- // airliners, arranged in rows" → "retired airliners"). A greedy side
486
- // match often swallows the words after the compared thing; the comma is a
487
- // clause boundary, not part of the value. Numeric grouping commas
488
- // ("4,000") survive because those are comma+digit, not comma+space.
489
- const trimClause = (s: string) => s.replace(/,\s+.*$/, '').trim();
490
- const left = trimClause(match[1].trim());
491
- const right = trimClause(match[2].trim());
492
- if (left.length < 2 || left.length > 30) continue;
493
- if (right.length < 2 || right.length > 30) continue;
494
- // Reject "from X to X"-style idioms — "from witness to witness",
495
- // "from day to day", "from generation to generation". These mean "it
496
- // varied", not "A versus B", and render as a pointless "X → X" card.
497
- // The signature is a word repeated across the connector: the last word
498
- // of the left side equals the first word of the right side. (Greedy
499
- // matching may append trailing context to the right side, so a whole-
500
- // string equality check is not enough.)
501
- const wordsOf = (s: string) =>
502
- s
503
- .toLowerCase()
504
- .split(/\s+/)
505
- .map((w) => w.replace(/[^a-z0-9]+/g, ''))
506
- .filter(Boolean);
507
- const leftWords = wordsOf(left);
508
- const rightWords = wordsOf(right);
509
- if (
510
- leftWords.length > 0 &&
511
- rightWords.length > 0 &&
512
- leftWords[leftWords.length - 1] === rightWords[0]
513
- ) {
514
- continue;
515
- }
516
-
517
- const context = getSentenceContext(text, position, match[0].length);
518
-
519
- elements.push({
520
- type: 'comparison',
521
- text: context.sentence,
522
- confidence: 0.6,
523
- sourcePosition: context.start,
524
- endPosition: context.end,
525
- data: { type: 'comparison', left: { label: left }, right: { label: right } },
526
- });
527
- }
528
- }
529
- return elements;
530
- }
531
-
532
- /**
533
- * Whether the `. ! ?` at `index` is a real sentence terminator rather than a
534
- * period inside an abbreviation ("George W. Tibbetts", "M. DeWitt", "Mr.",
535
- * "U.S."), a single-letter initial, a decimal ("3.5"), or an ellipsis. Naive
536
- * splitting on every period produces broken fragments — e.g. the standalone
537
- * slide "They were met at George W" from "…at George W. Tibbetts' store…".
538
- * Returns false for any non-terminator character so callers can scan freely.
539
- */
540
- function isSentenceBoundary(text: string, index: number): boolean {
541
- const ch = text[index];
542
- if (ch === '!' || ch === '?') return true;
543
- if (ch !== '.') return false;
544
-
545
- // Ellipsis: defer the boundary to the final dot in a run of dots.
546
- if (text[index + 1] === '.') return false;
547
- // Decimal number: digit "." digit → "3.5".
548
- if (/[0-9]/.test(text[index - 1] ?? '') && /[0-9]/.test(text[index + 1] ?? '')) return false;
549
-
550
- // The run of letters immediately preceding the period.
551
- let w = index - 1;
552
- while (w >= 0 && /[A-Za-z]/.test(text[w])) w--;
553
- const word = text.slice(w + 1, index);
554
- if (word.length === 1) return false; // single-letter initial: "George W."
555
- if (word && SENTENCE_ABBREVIATIONS.has(word.toLowerCase())) return false;
556
-
557
- // A genuine sentence starts with an uppercase letter, digit, or opening
558
- // quote/bracket. A lowercase continuation means the period was mid-sentence
559
- // (an abbreviation we didn't enumerate).
560
- let j = index + 1;
561
- while (j < text.length && /\s/.test(text[j])) j++;
562
- if (j >= text.length) return true; // end of text
563
- return !/[a-z]/.test(text[j]);
564
- }
565
-
566
- /**
567
- * Iterate over sentence-like spans in the text, yielding trimmed text and
568
- * accurate start/end indices within the original string.
569
- *
570
- * Boundaries are detected by isSentenceBoundary() so abbreviations, initials,
571
- * decimals, and ellipses do not split a sentence. Leading whitespace and
572
- * trailing whitespace/terminators are excluded from each span.
573
- */
574
- function forEachSentenceSpan(
575
- text: string,
576
- callback: (trimmed: string, start: number, end: number) => void,
577
- ): void {
578
- const emit = (rawStart: number, rawEnd: number) => {
579
- let start = rawStart;
580
- while (start < rawEnd && /\s/.test(text[start])) start++;
581
- let end = rawEnd;
582
- while (end > start && /[\s.!?]/.test(text[end - 1])) end--;
583
- if (end <= start) return;
584
- const trimmed = text.slice(start, end);
585
- if (trimmed) callback(trimmed, start, end);
586
- };
587
-
588
- let spanStart = 0;
589
- let i = 0;
590
- while (i < text.length) {
591
- if (isSentenceBoundary(text, i)) {
592
- // Consume any consecutive terminators ("?!", "…") as one boundary.
593
- let end = i + 1;
594
- while (end < text.length && /[.!?]/.test(text[end])) end++;
595
- emit(spanStart, end);
596
- spanStart = end;
597
- i = end;
598
- } else {
599
- i++;
600
- }
601
- }
602
- if (spanStart < text.length) emit(spanStart, text.length);
603
- }
604
-
605
- function extractFacts(text: string): ExtractedElement[] {
606
- const elements: ExtractedElement[] = [];
607
-
608
- forEachSentenceSpan(text, (trimmed, start, end) => {
609
- if (trimmed.length <= 20) return;
610
-
611
- const score = scoreSentenceAsFact(trimmed);
612
- if (score < 0.4) return;
613
-
614
- elements.push({
615
- type: 'fact',
616
- text: trimmed,
617
- confidence: score,
618
- sourcePosition: start,
619
- endPosition: end,
620
- data: { type: 'fact', fact: trimmed },
621
- });
622
- });
623
-
624
- return elements;
625
- }
626
-
627
- function extractImpactLines(text: string): ExtractedElement[] {
628
- const elements: ExtractedElement[] = [];
629
-
630
- forEachSentenceSpan(text, (trimmed, start, end) => {
631
- if (trimmed.length < 8 || trimmed.length > 60) return;
632
-
633
- let score = 0.3;
634
- const lower = trimmed.toLowerCase();
635
-
636
- for (const verb of IMPACT_VERBS) {
637
- if (lower.startsWith(verb)) {
638
- score += 0.25;
639
- break;
640
- }
641
- }
642
-
643
- if (end < text.length && text[end] === '!') score += 0.15;
644
- if (trimmed.length < 30) score += 0.1;
645
- if (trimmed.includes(',')) score -= 0.1;
646
- if (/^(and|but|or|the|a|an)\b/i.test(trimmed)) score -= 0.15;
647
- if (score < 0.5) return;
648
-
649
- elements.push({
650
- type: 'impactLine',
651
- text: trimmed,
652
- confidence: Math.min(1, score),
653
- sourcePosition: start,
654
- endPosition: end,
655
- data: { type: 'impactLine', text: trimmed },
656
- });
657
- });
658
-
659
- return elements;
660
- }
661
-
662
- function extractLists(text: string): ExtractedElement[] {
663
- const elements: ExtractedElement[] = [];
664
- const seen = new Set<number>();
665
-
666
- for (const pattern of LIST_PATTERNS) {
667
- pattern.lastIndex = 0;
668
- let match;
669
- while ((match = pattern.exec(text)) !== null) {
670
- const position = match.index;
671
- if (seen.has(position)) continue;
672
- seen.add(position);
673
-
674
- const listContent = match[1].trim();
675
- const items = listContent
676
- .split(/,\s*(?:and|or)\s+|,\s+|\s+and\s+|\s+or\s+/)
677
- .map((item) => item.trim())
678
- .filter((item) => item.length >= 2 && item.length <= 60);
679
-
680
- if (items.length < 3 || items.length > 5) continue;
681
-
682
- const context = getSentenceContext(text, position, match[0].length);
683
-
684
- elements.push({
685
- type: 'list',
686
- text: context.sentence,
687
- confidence: 0.65,
688
- sourcePosition: context.start,
689
- endPosition: context.end,
690
- data: { type: 'list', items },
691
- });
692
- }
693
- }
694
- return elements;
695
- }
696
-
697
- function extractDefinitions(text: string): ExtractedElement[] {
698
- const elements: ExtractedElement[] = [];
699
- const seen = new Set<number>();
700
-
701
- for (const pattern of DEFINITION_PATTERNS) {
702
- pattern.lastIndex = 0;
703
- let match;
704
- while ((match = pattern.exec(text)) !== null) {
705
- const position = match.index;
706
- if (seen.has(position)) continue;
707
- seen.add(position);
708
-
709
- const term = match[1].trim();
710
- const definition = match[2].trim();
711
- if (term.length < 3 || term.length > 30) continue;
712
- if (definition.length < 10 || definition.length > 120) continue;
713
-
714
- const context = getSentenceContext(text, position, match[0].length);
715
-
716
- elements.push({
717
- type: 'definition',
718
- text: context.sentence,
719
- confidence: 0.6,
720
- sourcePosition: context.start,
721
- endPosition: context.end,
722
- data: { type: 'definition', term, definition },
723
- });
724
- }
725
- }
726
- return elements;
727
- }
728
-
729
- // ── Helpers ────────────────────────────────────────────────────────
730
-
731
- function getSentenceContext(
732
- text: string,
733
- matchStart: number,
734
- matchLength: number,
735
- ): { sentence: string; start: number; end: number } {
736
- let start = matchStart;
737
- while (start > 0 && !isSentenceBoundary(text, start - 1)) start--;
738
- while (start < matchStart && /\s/.test(text[start])) start++;
739
-
740
- let end = matchStart + matchLength;
741
- while (end < text.length && !isSentenceBoundary(text, end)) end++;
742
- if (end < text.length) end++;
743
-
744
- return { sentence: text.slice(start, end).trim(), start, end };
745
- }
746
-
747
- function calculateStatConfidence(value: string, context: string): number {
748
- let score = 0.5;
749
- if (value.includes('%')) score += 0.2;
750
- if (/million|billion|trillion/i.test(value)) score += 0.15;
751
- if (/increased|decreased|grew|dropped|rose|fell/i.test(context)) score += 0.15;
752
- if (context.length < 30) score -= 0.2;
753
- return Math.min(1, Math.max(0, score));
754
- }
755
-
756
- function calculateDateConfidence(date: string, context: string): number {
757
- let score = 0.5;
758
- if (
759
- /January|February|March|April|May|June|July|August|September|October|November|December/i.test(
760
- date,
761
- )
762
- )
763
- score += 0.2;
764
- if (/founded|established|built|opened|discovered|created/i.test(context)) score += 0.2;
765
- if (/happened|occurred|took place|began|ended/i.test(context)) score += 0.15;
766
- return Math.min(1, Math.max(0, score));
767
- }
768
-
769
- function calculateQuoteConfidence(quote: string): number {
770
- let score = 0.5;
771
- if (quote.length >= 30 && quote.length <= 150) score += 0.2;
772
- if (/\b(I|we|our|my)\b/i.test(quote)) score += 0.1;
773
- if (!/[.!?]$/.test(quote)) score -= 0.1;
774
- return Math.min(1, Math.max(0, score));
775
- }
776
-
777
- function scoreSentenceAsFact(sentence: string): number {
778
- let score = 0.3;
779
- const lower = sentence.toLowerCase();
780
- for (const indicator of FACT_INDICATORS) {
781
- if (lower.includes(indicator)) {
782
- score += 0.1;
783
- break;
784
- }
785
- }
786
- const properNouns = sentence.match(/\b[A-Z][a-z]+\b/g);
787
- if (properNouns && properNouns.length >= 2) score += 0.15;
788
- if (/\d/.test(sentence)) score += 0.1;
789
- if (sentence.endsWith('?')) score -= 0.3;
790
- if (sentence.length > 200) score -= 0.15;
791
- return Math.min(1, Math.max(0, score));
792
- }
793
-
794
- function detectMood(sentence: string): 'neutral' | 'somber' | 'celebratory' {
795
- const lower = sentence.toLowerCase();
796
- for (const word of SOMBER_INDICATORS) {
797
- if (lower.includes(word)) return 'somber';
798
- }
799
- for (const word of CELEBRATORY_INDICATORS) {
800
- if (lower.includes(word)) return 'celebratory';
801
- }
802
- return 'neutral';
803
- }
804
-
805
- function cleanDescription(sentence: string, value: string): string {
806
- const prepositionPatterns = [
807
- new RegExp(`\\b[Ii]n\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
808
- new RegExp(`\\b[Oo]n\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
809
- new RegExp(`\\b[Dd]uring\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
810
- new RegExp(`\\b[Bb]y\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
811
- new RegExp(`\\b[Ss]ince\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
812
- new RegExp(`\\b[Ff]rom\\s+${escapeRegex(value)}[,.]?\\s*`, 'g'),
813
- ];
814
-
815
- let desc = sentence;
816
- for (const pattern of prepositionPatterns) {
817
- desc = desc.replace(pattern, '');
818
- }
819
- if (desc === sentence) {
820
- desc = sentence.replace(value, '').trim();
821
- }
822
-
823
- desc = desc.replace(/^[,:\-–—]+\s*/, '').replace(/\s*[,:\-–—]+$/, '');
824
- desc = desc.replace(
825
- /\s+(?:of|on|in|at|by|to|for|from|with|about|over|under|between|than|into|onto|upon)\s*([,.])/gi,
826
- '$1',
827
- );
828
- desc = desc.replace(
829
- /\s+(?:for|of|to|in|at|by|with|from|about|over|under|between|than|into|onto|upon)\s*[.!?]?\s*$/i,
830
- '.',
831
- );
832
- desc = desc.replace(/\s{2,}/g, ' ').replace(/\s+([,.])/g, '$1');
833
- desc = desc.charAt(0).toUpperCase() + desc.slice(1);
834
- return desc.trim();
835
- }
836
-
837
- function escapeRegex(str: string): string {
838
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
839
- }
840
-
841
- const TYPE_SPECIFICITY: Record<ExtractionType, number> = {
842
- stat: 5,
843
- date: 4,
844
- quote: 3,
845
- definition: 3,
846
- comparison: 2,
847
- list: 2,
848
- impactLine: 2,
849
- fact: 1,
850
- };
851
-
852
- function deduplicateOverlapping(elements: ExtractedElement[]): ExtractedElement[] {
853
- if (elements.length <= 1) return elements;
854
-
855
- const toRemove = new Set<number>();
856
-
857
- for (let i = 0; i < elements.length; i++) {
858
- if (toRemove.has(i)) continue;
859
- const a = elements[i];
860
-
861
- for (let j = i + 1; j < elements.length; j++) {
862
- if (toRemove.has(j)) continue;
863
- const b = elements[j];
864
-
865
- if (elementsOverlap(a, b)) {
866
- const aSpec = TYPE_SPECIFICITY[a.type];
867
- const bSpec = TYPE_SPECIFICITY[b.type];
868
- if (aSpec >= bSpec) {
869
- toRemove.add(j);
870
- } else {
871
- toRemove.add(i);
872
- break;
873
- }
874
- }
875
- }
876
- }
877
-
878
- return elements.filter((_, index) => !toRemove.has(index));
879
- }
880
-
881
- function elementsOverlap(a: ExtractedElement, b: ExtractedElement): boolean {
882
- if (a.sourcePosition === b.sourcePosition) return true;
883
- if (a.sourcePosition <= b.sourcePosition && a.endPosition >= b.endPosition) return true;
884
- if (b.sourcePosition <= a.sourcePosition && b.endPosition >= a.endPosition) return true;
885
-
886
- const overlapStart = Math.max(a.sourcePosition, b.sourcePosition);
887
- const overlapEnd = Math.min(a.endPosition, b.endPosition);
888
- if (overlapEnd > overlapStart) {
889
- const overlapLength = overlapEnd - overlapStart;
890
- const minLength = Math.min(a.endPosition - a.sourcePosition, b.endPosition - b.sourcePosition);
891
- if (overlapLength > minLength * 0.5) return true;
892
- }
893
-
894
- return false;
895
- }
896
-
897
- /**
898
- * Strip markdown formatting from text, returning plain prose.
899
- * Call this before `extractContent` if the input is markdown.
900
- */
901
- export function stripMarkdown(markdown: string): string {
902
- return (
903
- markdown
904
- // Remove code blocks (before inline code)
905
- .replace(/```[\s\S]*?```/g, '')
906
- // Remove images (before links — `![` prefix distinguishes them)
907
- .replace(/!\[([^\]]*)\]\([^)]+\)/g, '')
908
- // Remove links, keeping text
909
- .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
910
- .replace(/^#{1,6}\s+/gm, '')
911
- .replace(/\*\*([^*]+)\*\*/g, '$1')
912
- .replace(/\*([^*]+)\*/g, '$1')
913
- .replace(/__([^_]+)__/g, '$1')
914
- .replace(/_([^_]+)_/g, '$1')
915
- .replace(/`([^`]+)`/g, '$1')
916
- .replace(/^>\s+/gm, '')
917
- .replace(/^[-*_]{3,}$/gm, '')
918
- .replace(/\n{3,}/g, '\n\n')
919
- .trim()
920
- );
921
- }