@bendyline/squisq 1.3.0 → 1.4.1

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 (533) hide show
  1. package/dist/{Doc-Ch4tc3vv.d.ts → Doc-BeSeH2iX.d.ts} +118 -41
  2. package/dist/ImageEditDoc-BTIvw0oq.d.ts +84 -0
  3. package/dist/{chunk-CYQHG27J.js → chunk-2TMAWB4Y.js} +74 -1
  4. package/dist/chunk-2TMAWB4Y.js.map +1 -0
  5. package/dist/{chunk-OASJKWO5.js → chunk-3K5OG6KI.js} +92 -7
  6. package/dist/chunk-3K5OG6KI.js.map +1 -0
  7. package/dist/chunk-57CVQCFX.js +193 -0
  8. package/dist/chunk-57CVQCFX.js.map +1 -0
  9. package/dist/{chunk-QM5PKNPW.js → chunk-5WFRKURX.js} +1 -1
  10. package/dist/chunk-5WFRKURX.js.map +1 -0
  11. package/dist/chunk-B4EEON3N.js +1317 -0
  12. package/dist/chunk-B4EEON3N.js.map +1 -0
  13. package/dist/chunk-DBS6RIFL.js +81 -0
  14. package/dist/chunk-DBS6RIFL.js.map +1 -0
  15. package/dist/{chunk-MIBRIRGJ.js → chunk-FR2RBTKO.js} +3 -3
  16. package/dist/{chunk-MIBRIRGJ.js.map → chunk-FR2RBTKO.js.map} +1 -1
  17. package/dist/chunk-H3AXU4MJ.js +179 -0
  18. package/dist/chunk-H3AXU4MJ.js.map +1 -0
  19. package/dist/chunk-JELIRVDP.js +24 -0
  20. package/dist/chunk-JELIRVDP.js.map +1 -0
  21. package/dist/chunk-K32VJONL.js +193 -0
  22. package/dist/chunk-K32VJONL.js.map +1 -0
  23. package/dist/{chunk-6BAVXFYC.js → chunk-KSWJR66U.js} +218 -42
  24. package/dist/chunk-KSWJR66U.js.map +1 -0
  25. package/dist/{chunk-TSG2OSE6.js → chunk-MYIH7FWD.js} +3 -3
  26. package/dist/chunk-MYIH7FWD.js.map +1 -0
  27. package/dist/chunk-VLJJHDAC.js +218 -0
  28. package/dist/chunk-VLJJHDAC.js.map +1 -0
  29. package/dist/chunk-WMOI7FN3.js +182 -0
  30. package/dist/chunk-WMOI7FN3.js.map +1 -0
  31. package/dist/chunk-ZTX4PFFT.js +520 -0
  32. package/dist/chunk-ZTX4PFFT.js.map +1 -0
  33. package/dist/doc/index.d.ts +5 -10
  34. package/dist/doc/index.js +145 -7
  35. package/dist/doc/index.js.map +1 -1
  36. package/dist/generate/index.d.ts +99 -7
  37. package/dist/generate/index.js +16 -3
  38. package/dist/generate/index.js.map +1 -1
  39. package/dist/icons/index.d.ts +87 -0
  40. package/dist/icons/index.js +17 -0
  41. package/dist/icons/index.js.map +1 -0
  42. package/dist/imageEdit/index.d.ts +216 -0
  43. package/dist/imageEdit/index.js +54 -0
  44. package/dist/imageEdit/index.js.map +1 -0
  45. package/dist/index.d.ts +21 -9
  46. package/dist/index.js +461 -8
  47. package/dist/index.js.map +1 -1
  48. package/dist/jsonForm/index.d.ts +191 -0
  49. package/dist/jsonForm/index.js +27 -0
  50. package/dist/jsonForm/index.js.map +1 -0
  51. package/dist/markdown/index.d.ts +265 -19
  52. package/dist/markdown/index.js +39 -33
  53. package/dist/markdown/index.js.map +1 -1
  54. package/dist/random/index.d.ts +51 -2
  55. package/dist/random/index.js +9 -1
  56. package/dist/random/index.js.map +1 -1
  57. package/dist/recommend/index.d.ts +42 -0
  58. package/dist/recommend/index.js +10 -0
  59. package/dist/recommend/index.js.map +1 -0
  60. package/dist/schemas/index.d.ts +188 -10
  61. package/dist/schemas/index.js +120 -7
  62. package/dist/schemas/index.js.map +1 -1
  63. package/dist/spatial/index.d.ts +111 -3
  64. package/dist/spatial/index.js +24 -2
  65. package/dist/spatial/index.js.map +1 -1
  66. package/dist/storage/index.d.ts +159 -9
  67. package/dist/storage/index.js +20 -5
  68. package/dist/storage/index.js.map +1 -1
  69. package/dist/story/index.d.ts +53 -13
  70. package/dist/story/index.js +12 -4
  71. package/dist/themeLibrary-BHjJ0Qx6.d.ts +40 -0
  72. package/dist/timing/index.d.ts +109 -4
  73. package/dist/timing/index.js +23 -2
  74. package/dist/timing/index.js.map +1 -1
  75. package/dist/transform/index.d.ts +175 -6
  76. package/dist/transform/index.js +490 -3
  77. package/dist/transform/index.js.map +1 -1
  78. package/dist/{types-CkNttVSF.d.ts → types-BdZkdJ3z.d.ts} +17 -2
  79. package/dist/types-D98li1gV.d.ts +93 -0
  80. package/dist/versions/index.d.ts +128 -0
  81. package/dist/versions/index.js +35 -0
  82. package/dist/versions/index.js.map +1 -0
  83. package/package.json +28 -1
  84. package/src/__tests__/colorUtils.test.ts +112 -0
  85. package/src/__tests__/getLayers.test.ts +32 -7
  86. package/src/__tests__/iconResolve.test.ts +122 -0
  87. package/src/__tests__/imageEditState.test.ts +74 -0
  88. package/src/__tests__/imageEditVersions.test.ts +169 -0
  89. package/src/__tests__/inferDocumentTitle.test.ts +50 -0
  90. package/src/__tests__/jsonForm.chooseControl.test.ts +86 -0
  91. package/src/__tests__/jsonForm.evaluateWhen.test.ts +59 -0
  92. package/src/__tests__/jsonForm.inferSchema.test.ts +25 -0
  93. package/src/__tests__/jsonForm.pointer.test.ts +103 -0
  94. package/src/__tests__/markdownIcons.test.ts +104 -0
  95. package/src/__tests__/markdownToDoc.test.ts +19 -4
  96. package/src/__tests__/recommendTemplates.test.ts +183 -0
  97. package/src/__tests__/scopedContentContainer.test.ts +89 -0
  98. package/src/__tests__/slideshowGenerator.test.ts +1 -1
  99. package/src/__tests__/templateAnnotationParse.test.ts +42 -0
  100. package/src/__tests__/templates.test.ts +93 -9
  101. package/src/__tests__/themeCompile.test.ts +156 -0
  102. package/src/__tests__/themeValidator.test.ts +125 -0
  103. package/src/__tests__/versions.test.ts +415 -0
  104. package/src/doc/audioMapping.ts +55 -11
  105. package/src/doc/getLayers.ts +32 -21
  106. package/src/doc/markdownToDoc.ts +45 -7
  107. package/src/doc/templates/featureBlock.ts +202 -0
  108. package/src/doc/templates/fullBleedQuote.ts +13 -0
  109. package/src/doc/templates/index.ts +50 -16
  110. package/src/doc/templates/listBlock.ts +24 -5
  111. package/src/doc/templates/statHighlight.ts +13 -0
  112. package/src/doc/templates/titleBlock.ts +9 -0
  113. package/src/doc/utils/themeUtils.ts +8 -7
  114. package/src/generate/slideshowGenerator.ts +1 -1
  115. package/src/generate/templateMapper.ts +2 -2
  116. package/src/icons/iconData.ts +31 -0
  117. package/src/icons/index.ts +18 -0
  118. package/src/icons/resolve.ts +139 -0
  119. package/src/imageEdit/ImageEditVersionManager.ts +73 -0
  120. package/src/imageEdit/export.ts +326 -0
  121. package/src/imageEdit/index.ts +71 -0
  122. package/src/imageEdit/persistence.ts +62 -0
  123. package/src/imageEdit/state.ts +112 -0
  124. package/src/imageEdit/versionPaths.ts +57 -0
  125. package/src/imageEdit/versions.ts +231 -0
  126. package/src/index.ts +4 -0
  127. package/src/jsonForm/chooseControl.ts +88 -0
  128. package/src/jsonForm/evaluateWhen.ts +59 -0
  129. package/src/jsonForm/index.ts +22 -0
  130. package/src/jsonForm/inferSchema.ts +25 -0
  131. package/src/jsonForm/pointer.ts +109 -0
  132. package/src/jsonForm/types.ts +167 -0
  133. package/src/markdown/convert.ts +145 -5
  134. package/src/markdown/index.ts +3 -0
  135. package/src/markdown/types.ts +19 -2
  136. package/src/markdown/utils.ts +159 -0
  137. package/src/recommend/index.ts +16 -0
  138. package/src/recommend/templates.ts +273 -0
  139. package/src/schemas/BlockTemplates.ts +50 -7
  140. package/src/schemas/ImageEditDoc.ts +95 -0
  141. package/src/schemas/Theme.ts +98 -31
  142. package/src/schemas/colorUtils.ts +186 -0
  143. package/src/schemas/fontStacks.ts +257 -0
  144. package/src/schemas/index.ts +12 -0
  145. package/src/schemas/themeCompile.ts +203 -0
  146. package/src/schemas/themeLibrary.ts +18 -597
  147. package/src/schemas/themeValidator.ts +388 -0
  148. package/src/schemas/themes/bold.json +48 -0
  149. package/src/schemas/themes/cinematic.json +54 -0
  150. package/src/schemas/themes/documentary.json +49 -0
  151. package/src/schemas/themes/gezellig.json +44 -0
  152. package/src/schemas/themes/index.ts +53 -0
  153. package/src/schemas/themes/magazine.json +44 -0
  154. package/src/schemas/themes/minimalist.json +45 -0
  155. package/src/schemas/themes/morning-light.json +42 -0
  156. package/src/schemas/themes/standard-dark.json +50 -0
  157. package/src/schemas/themes/standard.json +42 -0
  158. package/src/schemas/themes/tech-dark.json +48 -0
  159. package/src/schemas/themes/warm-earth.json +50 -0
  160. package/src/storage/ScopedContentContainer.ts +113 -0
  161. package/src/storage/index.ts +1 -0
  162. package/src/versions/DocumentVersionManager.ts +70 -0
  163. package/src/versions/index.ts +54 -0
  164. package/src/versions/operations.ts +230 -0
  165. package/src/versions/paths.ts +66 -0
  166. package/src/versions/timestamp.ts +48 -0
  167. package/src/versions/types.ts +91 -0
  168. package/dist/__tests__/animationUtils.test.d.ts +0 -2
  169. package/dist/__tests__/animationUtils.test.d.ts.map +0 -1
  170. package/dist/__tests__/animationUtils.test.js +0 -60
  171. package/dist/__tests__/animationUtils.test.js.map +0 -1
  172. package/dist/__tests__/contentContainer.test.d.ts +0 -2
  173. package/dist/__tests__/contentContainer.test.d.ts.map +0 -1
  174. package/dist/__tests__/contentContainer.test.js +0 -234
  175. package/dist/__tests__/contentContainer.test.js.map +0 -1
  176. package/dist/__tests__/contentExtractor.test.d.ts +0 -2
  177. package/dist/__tests__/contentExtractor.test.d.ts.map +0 -1
  178. package/dist/__tests__/contentExtractor.test.js +0 -151
  179. package/dist/__tests__/contentExtractor.test.js.map +0 -1
  180. package/dist/__tests__/coverBlock.test.d.ts +0 -2
  181. package/dist/__tests__/coverBlock.test.d.ts.map +0 -1
  182. package/dist/__tests__/coverBlock.test.js +0 -197
  183. package/dist/__tests__/coverBlock.test.js.map +0 -1
  184. package/dist/__tests__/dataTable.test.d.ts +0 -2
  185. package/dist/__tests__/dataTable.test.d.ts.map +0 -1
  186. package/dist/__tests__/dataTable.test.js +0 -110
  187. package/dist/__tests__/dataTable.test.js.map +0 -1
  188. package/dist/__tests__/geohash.test.d.ts +0 -2
  189. package/dist/__tests__/geohash.test.d.ts.map +0 -1
  190. package/dist/__tests__/geohash.test.js +0 -87
  191. package/dist/__tests__/geohash.test.js.map +0 -1
  192. package/dist/__tests__/getLayers.test.d.ts +0 -2
  193. package/dist/__tests__/getLayers.test.d.ts.map +0 -1
  194. package/dist/__tests__/getLayers.test.js +0 -167
  195. package/dist/__tests__/getLayers.test.js.map +0 -1
  196. package/dist/__tests__/haversine.test.d.ts +0 -2
  197. package/dist/__tests__/haversine.test.d.ts.map +0 -1
  198. package/dist/__tests__/haversine.test.js +0 -56
  199. package/dist/__tests__/haversine.test.js.map +0 -1
  200. package/dist/__tests__/localForageAdapter.test.d.ts +0 -8
  201. package/dist/__tests__/localForageAdapter.test.d.ts.map +0 -1
  202. package/dist/__tests__/localForageAdapter.test.js +0 -130
  203. package/dist/__tests__/localForageAdapter.test.js.map +0 -1
  204. package/dist/__tests__/markdown.test.d.ts +0 -2
  205. package/dist/__tests__/markdown.test.d.ts.map +0 -1
  206. package/dist/__tests__/markdown.test.js +0 -715
  207. package/dist/__tests__/markdown.test.js.map +0 -1
  208. package/dist/__tests__/markdownToDoc.test.d.ts +0 -2
  209. package/dist/__tests__/markdownToDoc.test.d.ts.map +0 -1
  210. package/dist/__tests__/markdownToDoc.test.js +0 -447
  211. package/dist/__tests__/markdownToDoc.test.js.map +0 -1
  212. package/dist/__tests__/seededRandom.test.d.ts +0 -2
  213. package/dist/__tests__/seededRandom.test.d.ts.map +0 -1
  214. package/dist/__tests__/seededRandom.test.js +0 -125
  215. package/dist/__tests__/seededRandom.test.js.map +0 -1
  216. package/dist/__tests__/slideshowGenerator.test.d.ts +0 -2
  217. package/dist/__tests__/slideshowGenerator.test.d.ts.map +0 -1
  218. package/dist/__tests__/slideshowGenerator.test.js +0 -114
  219. package/dist/__tests__/slideshowGenerator.test.js.map +0 -1
  220. package/dist/__tests__/storage.test.d.ts +0 -2
  221. package/dist/__tests__/storage.test.d.ts.map +0 -1
  222. package/dist/__tests__/storage.test.js +0 -51
  223. package/dist/__tests__/storage.test.js.map +0 -1
  224. package/dist/__tests__/surface.test.d.ts +0 -2
  225. package/dist/__tests__/surface.test.d.ts.map +0 -1
  226. package/dist/__tests__/surface.test.js +0 -57
  227. package/dist/__tests__/surface.test.js.map +0 -1
  228. package/dist/__tests__/templates.test.d.ts +0 -2
  229. package/dist/__tests__/templates.test.d.ts.map +0 -1
  230. package/dist/__tests__/templates.test.js +0 -217
  231. package/dist/__tests__/templates.test.js.map +0 -1
  232. package/dist/__tests__/timing.test.d.ts +0 -2
  233. package/dist/__tests__/timing.test.d.ts.map +0 -1
  234. package/dist/__tests__/timing.test.js +0 -131
  235. package/dist/__tests__/timing.test.js.map +0 -1
  236. package/dist/chunk-6BAVXFYC.js.map +0 -1
  237. package/dist/chunk-7GF6RDED.js +0 -82
  238. package/dist/chunk-7GF6RDED.js.map +0 -1
  239. package/dist/chunk-CYQHG27J.js.map +0 -1
  240. package/dist/chunk-F22AE6BY.js +0 -121
  241. package/dist/chunk-F22AE6BY.js.map +0 -1
  242. package/dist/chunk-FIQR4AJG.js +0 -517
  243. package/dist/chunk-FIQR4AJG.js.map +0 -1
  244. package/dist/chunk-OASJKWO5.js.map +0 -1
  245. package/dist/chunk-QM5PKNPW.js.map +0 -1
  246. package/dist/chunk-TSG2OSE6.js.map +0 -1
  247. package/dist/doc/audioMapping.d.ts +0 -36
  248. package/dist/doc/audioMapping.d.ts.map +0 -1
  249. package/dist/doc/audioMapping.js +0 -315
  250. package/dist/doc/audioMapping.js.map +0 -1
  251. package/dist/doc/docToMarkdown.d.ts +0 -41
  252. package/dist/doc/docToMarkdown.d.ts.map +0 -1
  253. package/dist/doc/docToMarkdown.js +0 -88
  254. package/dist/doc/docToMarkdown.js.map +0 -1
  255. package/dist/doc/getLayers.d.ts +0 -65
  256. package/dist/doc/getLayers.d.ts.map +0 -1
  257. package/dist/doc/getLayers.js +0 -103
  258. package/dist/doc/getLayers.js.map +0 -1
  259. package/dist/doc/index.d.ts.map +0 -1
  260. package/dist/doc/markdownToDoc.d.ts +0 -75
  261. package/dist/doc/markdownToDoc.d.ts.map +0 -1
  262. package/dist/doc/markdownToDoc.js +0 -398
  263. package/dist/doc/markdownToDoc.js.map +0 -1
  264. package/dist/doc/templates/accentImage.d.ts +0 -59
  265. package/dist/doc/templates/accentImage.d.ts.map +0 -1
  266. package/dist/doc/templates/accentImage.js +0 -275
  267. package/dist/doc/templates/accentImage.js.map +0 -1
  268. package/dist/doc/templates/captionUtils.d.ts +0 -20
  269. package/dist/doc/templates/captionUtils.d.ts.map +0 -1
  270. package/dist/doc/templates/captionUtils.js +0 -29
  271. package/dist/doc/templates/captionUtils.js.map +0 -1
  272. package/dist/doc/templates/comparisonBar.d.ts +0 -13
  273. package/dist/doc/templates/comparisonBar.d.ts.map +0 -1
  274. package/dist/doc/templates/comparisonBar.js +0 -145
  275. package/dist/doc/templates/comparisonBar.js.map +0 -1
  276. package/dist/doc/templates/coverBlock.d.ts +0 -51
  277. package/dist/doc/templates/coverBlock.d.ts.map +0 -1
  278. package/dist/doc/templates/coverBlock.js +0 -153
  279. package/dist/doc/templates/coverBlock.js.map +0 -1
  280. package/dist/doc/templates/dataTable.d.ts +0 -14
  281. package/dist/doc/templates/dataTable.d.ts.map +0 -1
  282. package/dist/doc/templates/dataTable.js +0 -73
  283. package/dist/doc/templates/dataTable.js.map +0 -1
  284. package/dist/doc/templates/dateEvent.d.ts +0 -15
  285. package/dist/doc/templates/dateEvent.d.ts.map +0 -1
  286. package/dist/doc/templates/dateEvent.js +0 -114
  287. package/dist/doc/templates/dateEvent.js.map +0 -1
  288. package/dist/doc/templates/definitionCard.d.ts +0 -13
  289. package/dist/doc/templates/definitionCard.d.ts.map +0 -1
  290. package/dist/doc/templates/definitionCard.js +0 -117
  291. package/dist/doc/templates/definitionCard.js.map +0 -1
  292. package/dist/doc/templates/factCard.d.ts +0 -15
  293. package/dist/doc/templates/factCard.d.ts.map +0 -1
  294. package/dist/doc/templates/factCard.js +0 -104
  295. package/dist/doc/templates/factCard.js.map +0 -1
  296. package/dist/doc/templates/fullBleedQuote.d.ts +0 -13
  297. package/dist/doc/templates/fullBleedQuote.d.ts.map +0 -1
  298. package/dist/doc/templates/fullBleedQuote.js +0 -55
  299. package/dist/doc/templates/fullBleedQuote.js.map +0 -1
  300. package/dist/doc/templates/imageWithCaption.d.ts +0 -13
  301. package/dist/doc/templates/imageWithCaption.d.ts.map +0 -1
  302. package/dist/doc/templates/imageWithCaption.js +0 -146
  303. package/dist/doc/templates/imageWithCaption.js.map +0 -1
  304. package/dist/doc/templates/index.d.ts +0 -105
  305. package/dist/doc/templates/index.d.ts.map +0 -1
  306. package/dist/doc/templates/index.js +0 -445
  307. package/dist/doc/templates/index.js.map +0 -1
  308. package/dist/doc/templates/listBlock.d.ts +0 -13
  309. package/dist/doc/templates/listBlock.d.ts.map +0 -1
  310. package/dist/doc/templates/listBlock.js +0 -92
  311. package/dist/doc/templates/listBlock.js.map +0 -1
  312. package/dist/doc/templates/mapBlock.d.ts +0 -17
  313. package/dist/doc/templates/mapBlock.d.ts.map +0 -1
  314. package/dist/doc/templates/mapBlock.js +0 -115
  315. package/dist/doc/templates/mapBlock.js.map +0 -1
  316. package/dist/doc/templates/persistentLayers.d.ts +0 -39
  317. package/dist/doc/templates/persistentLayers.d.ts.map +0 -1
  318. package/dist/doc/templates/persistentLayers.js +0 -447
  319. package/dist/doc/templates/persistentLayers.js.map +0 -1
  320. package/dist/doc/templates/photoGrid.d.ts +0 -20
  321. package/dist/doc/templates/photoGrid.d.ts.map +0 -1
  322. package/dist/doc/templates/photoGrid.js +0 -175
  323. package/dist/doc/templates/photoGrid.js.map +0 -1
  324. package/dist/doc/templates/pullQuote.d.ts +0 -13
  325. package/dist/doc/templates/pullQuote.d.ts.map +0 -1
  326. package/dist/doc/templates/pullQuote.js +0 -113
  327. package/dist/doc/templates/pullQuote.js.map +0 -1
  328. package/dist/doc/templates/quoteBlock.d.ts +0 -15
  329. package/dist/doc/templates/quoteBlock.d.ts.map +0 -1
  330. package/dist/doc/templates/quoteBlock.js +0 -101
  331. package/dist/doc/templates/quoteBlock.js.map +0 -1
  332. package/dist/doc/templates/sectionHeader.d.ts +0 -14
  333. package/dist/doc/templates/sectionHeader.d.ts.map +0 -1
  334. package/dist/doc/templates/sectionHeader.js +0 -97
  335. package/dist/doc/templates/sectionHeader.js.map +0 -1
  336. package/dist/doc/templates/statHighlight.d.ts +0 -15
  337. package/dist/doc/templates/statHighlight.d.ts.map +0 -1
  338. package/dist/doc/templates/statHighlight.js +0 -102
  339. package/dist/doc/templates/statHighlight.js.map +0 -1
  340. package/dist/doc/templates/titleBlock.d.ts +0 -13
  341. package/dist/doc/templates/titleBlock.d.ts.map +0 -1
  342. package/dist/doc/templates/titleBlock.js +0 -95
  343. package/dist/doc/templates/titleBlock.js.map +0 -1
  344. package/dist/doc/templates/twoColumn.d.ts +0 -15
  345. package/dist/doc/templates/twoColumn.d.ts.map +0 -1
  346. package/dist/doc/templates/twoColumn.js +0 -225
  347. package/dist/doc/templates/twoColumn.js.map +0 -1
  348. package/dist/doc/templates/videoPullQuote.d.ts +0 -20
  349. package/dist/doc/templates/videoPullQuote.d.ts.map +0 -1
  350. package/dist/doc/templates/videoPullQuote.js +0 -122
  351. package/dist/doc/templates/videoPullQuote.js.map +0 -1
  352. package/dist/doc/templates/videoWithCaption.d.ts +0 -20
  353. package/dist/doc/templates/videoWithCaption.d.ts.map +0 -1
  354. package/dist/doc/templates/videoWithCaption.js +0 -107
  355. package/dist/doc/templates/videoWithCaption.js.map +0 -1
  356. package/dist/doc/utils/animationUtils.d.ts +0 -34
  357. package/dist/doc/utils/animationUtils.d.ts.map +0 -1
  358. package/dist/doc/utils/animationUtils.js +0 -110
  359. package/dist/doc/utils/animationUtils.js.map +0 -1
  360. package/dist/doc/utils/themeUtils.d.ts +0 -64
  361. package/dist/doc/utils/themeUtils.d.ts.map +0 -1
  362. package/dist/doc/utils/themeUtils.js +0 -135
  363. package/dist/doc/utils/themeUtils.js.map +0 -1
  364. package/dist/generate/contentExtractor.d.ts +0 -112
  365. package/dist/generate/contentExtractor.d.ts.map +0 -1
  366. package/dist/generate/contentExtractor.js +0 -638
  367. package/dist/generate/contentExtractor.js.map +0 -1
  368. package/dist/generate/index.d.ts.map +0 -1
  369. package/dist/generate/slideshowGenerator.d.ts +0 -72
  370. package/dist/generate/slideshowGenerator.d.ts.map +0 -1
  371. package/dist/generate/slideshowGenerator.js +0 -159
  372. package/dist/generate/slideshowGenerator.js.map +0 -1
  373. package/dist/generate/templateMapper.d.ts +0 -23
  374. package/dist/generate/templateMapper.d.ts.map +0 -1
  375. package/dist/generate/templateMapper.js +0 -114
  376. package/dist/generate/templateMapper.js.map +0 -1
  377. package/dist/index.d.ts.map +0 -1
  378. package/dist/markdown/convert.d.ts +0 -71
  379. package/dist/markdown/convert.d.ts.map +0 -1
  380. package/dist/markdown/convert.js +0 -845
  381. package/dist/markdown/convert.js.map +0 -1
  382. package/dist/markdown/htmlParse.d.ts +0 -26
  383. package/dist/markdown/htmlParse.d.ts.map +0 -1
  384. package/dist/markdown/htmlParse.js +0 -195
  385. package/dist/markdown/htmlParse.js.map +0 -1
  386. package/dist/markdown/index.d.ts.map +0 -1
  387. package/dist/markdown/parse.d.ts +0 -27
  388. package/dist/markdown/parse.d.ts.map +0 -1
  389. package/dist/markdown/parse.js +0 -90
  390. package/dist/markdown/parse.js.map +0 -1
  391. package/dist/markdown/stringify.d.ts +0 -32
  392. package/dist/markdown/stringify.d.ts.map +0 -1
  393. package/dist/markdown/stringify.js +0 -108
  394. package/dist/markdown/stringify.js.map +0 -1
  395. package/dist/markdown/types.d.ts +0 -516
  396. package/dist/markdown/types.d.ts.map +0 -1
  397. package/dist/markdown/types.js +0 -17
  398. package/dist/markdown/types.js.map +0 -1
  399. package/dist/markdown/utils.d.ts +0 -78
  400. package/dist/markdown/utils.d.ts.map +0 -1
  401. package/dist/markdown/utils.js +0 -153
  402. package/dist/markdown/utils.js.map +0 -1
  403. package/dist/random/SeededRandom.d.ts +0 -50
  404. package/dist/random/SeededRandom.d.ts.map +0 -1
  405. package/dist/random/SeededRandom.js +0 -115
  406. package/dist/random/SeededRandom.js.map +0 -1
  407. package/dist/random/index.d.ts.map +0 -1
  408. package/dist/schemas/BlockTemplates.d.ts +0 -600
  409. package/dist/schemas/BlockTemplates.d.ts.map +0 -1
  410. package/dist/schemas/BlockTemplates.js +0 -72
  411. package/dist/schemas/BlockTemplates.js.map +0 -1
  412. package/dist/schemas/Doc.d.ts +0 -503
  413. package/dist/schemas/Doc.d.ts.map +0 -1
  414. package/dist/schemas/Doc.js +0 -90
  415. package/dist/schemas/Doc.js.map +0 -1
  416. package/dist/schemas/LayoutStrategy.d.ts +0 -84
  417. package/dist/schemas/LayoutStrategy.d.ts.map +0 -1
  418. package/dist/schemas/LayoutStrategy.js +0 -123
  419. package/dist/schemas/LayoutStrategy.js.map +0 -1
  420. package/dist/schemas/MediaProvider.d.ts +0 -65
  421. package/dist/schemas/MediaProvider.d.ts.map +0 -1
  422. package/dist/schemas/MediaProvider.js +0 -13
  423. package/dist/schemas/MediaProvider.js.map +0 -1
  424. package/dist/schemas/Theme.d.ts +0 -194
  425. package/dist/schemas/Theme.d.ts.map +0 -1
  426. package/dist/schemas/Theme.js +0 -97
  427. package/dist/schemas/Theme.js.map +0 -1
  428. package/dist/schemas/Types.d.ts +0 -14
  429. package/dist/schemas/Types.d.ts.map +0 -1
  430. package/dist/schemas/Types.js +0 -5
  431. package/dist/schemas/Types.js.map +0 -1
  432. package/dist/schemas/Viewport.d.ts +0 -74
  433. package/dist/schemas/Viewport.d.ts.map +0 -1
  434. package/dist/schemas/Viewport.js +0 -63
  435. package/dist/schemas/Viewport.js.map +0 -1
  436. package/dist/schemas/index.d.ts.map +0 -1
  437. package/dist/schemas/themeLibrary.d.ts +0 -41
  438. package/dist/schemas/themeLibrary.d.ts.map +0 -1
  439. package/dist/schemas/themeLibrary.js +0 -597
  440. package/dist/schemas/themeLibrary.js.map +0 -1
  441. package/dist/spatial/Geohash.d.ts +0 -85
  442. package/dist/spatial/Geohash.d.ts.map +0 -1
  443. package/dist/spatial/Geohash.js +0 -142
  444. package/dist/spatial/Geohash.js.map +0 -1
  445. package/dist/spatial/Haversine.d.ts +0 -24
  446. package/dist/spatial/Haversine.d.ts.map +0 -1
  447. package/dist/spatial/Haversine.js +0 -48
  448. package/dist/spatial/Haversine.js.map +0 -1
  449. package/dist/spatial/index.d.ts.map +0 -1
  450. package/dist/storage/ContentContainer.d.ts +0 -87
  451. package/dist/storage/ContentContainer.d.ts.map +0 -1
  452. package/dist/storage/ContentContainer.js +0 -131
  453. package/dist/storage/ContentContainer.js.map +0 -1
  454. package/dist/storage/LocalForageAdapter.d.ts +0 -36
  455. package/dist/storage/LocalForageAdapter.d.ts.map +0 -1
  456. package/dist/storage/LocalForageAdapter.js +0 -82
  457. package/dist/storage/LocalForageAdapter.js.map +0 -1
  458. package/dist/storage/LocalStorageAdapter.d.ts +0 -16
  459. package/dist/storage/LocalStorageAdapter.d.ts.map +0 -1
  460. package/dist/storage/LocalStorageAdapter.js +0 -50
  461. package/dist/storage/LocalStorageAdapter.js.map +0 -1
  462. package/dist/storage/MediaProviderFromContainer.d.ts +0 -21
  463. package/dist/storage/MediaProviderFromContainer.d.ts.map +0 -1
  464. package/dist/storage/MediaProviderFromContainer.js +0 -79
  465. package/dist/storage/MediaProviderFromContainer.js.map +0 -1
  466. package/dist/storage/MemoryStorageAdapter.d.ts +0 -15
  467. package/dist/storage/MemoryStorageAdapter.d.ts.map +0 -1
  468. package/dist/storage/MemoryStorageAdapter.js +0 -34
  469. package/dist/storage/MemoryStorageAdapter.js.map +0 -1
  470. package/dist/storage/Storage.d.ts +0 -23
  471. package/dist/storage/Storage.d.ts.map +0 -1
  472. package/dist/storage/Storage.js +0 -9
  473. package/dist/storage/Storage.js.map +0 -1
  474. package/dist/storage/index.d.ts.map +0 -1
  475. package/dist/themeLibrary-CEo2D4b6.d.ts +0 -44
  476. package/dist/timing/index.d.ts.map +0 -1
  477. package/dist/timing/narrationTiming.d.ts +0 -54
  478. package/dist/timing/narrationTiming.d.ts.map +0 -1
  479. package/dist/timing/narrationTiming.js +0 -190
  480. package/dist/timing/narrationTiming.js.map +0 -1
  481. package/dist/timing/readingTime.d.ts +0 -54
  482. package/dist/timing/readingTime.d.ts.map +0 -1
  483. package/dist/timing/readingTime.js +0 -49
  484. package/dist/timing/readingTime.js.map +0 -1
  485. package/dist/transform/applyTransform.d.ts +0 -22
  486. package/dist/transform/applyTransform.d.ts.map +0 -1
  487. package/dist/transform/applyTransform.js +0 -68
  488. package/dist/transform/applyTransform.js.map +0 -1
  489. package/dist/transform/blockAnalyzer.d.ts +0 -48
  490. package/dist/transform/blockAnalyzer.d.ts.map +0 -1
  491. package/dist/transform/blockAnalyzer.js +0 -135
  492. package/dist/transform/blockAnalyzer.js.map +0 -1
  493. package/dist/transform/index.d.ts.map +0 -1
  494. package/dist/transform/registry.d.ts +0 -19
  495. package/dist/transform/registry.d.ts.map +0 -1
  496. package/dist/transform/registry.js +0 -41
  497. package/dist/transform/registry.js.map +0 -1
  498. package/dist/transform/styles/dataDriven.d.ts +0 -4
  499. package/dist/transform/styles/dataDriven.d.ts.map +0 -1
  500. package/dist/transform/styles/dataDriven.js +0 -15
  501. package/dist/transform/styles/dataDriven.js.map +0 -1
  502. package/dist/transform/styles/documentary.d.ts +0 -4
  503. package/dist/transform/styles/documentary.d.ts.map +0 -1
  504. package/dist/transform/styles/documentary.js +0 -15
  505. package/dist/transform/styles/documentary.js.map +0 -1
  506. package/dist/transform/styles/index.d.ts +0 -6
  507. package/dist/transform/styles/index.d.ts.map +0 -1
  508. package/dist/transform/styles/index.js +0 -6
  509. package/dist/transform/styles/index.js.map +0 -1
  510. package/dist/transform/styles/magazine.d.ts +0 -4
  511. package/dist/transform/styles/magazine.d.ts.map +0 -1
  512. package/dist/transform/styles/magazine.js +0 -15
  513. package/dist/transform/styles/magazine.js.map +0 -1
  514. package/dist/transform/styles/minimal.d.ts +0 -4
  515. package/dist/transform/styles/minimal.d.ts.map +0 -1
  516. package/dist/transform/styles/minimal.js +0 -15
  517. package/dist/transform/styles/minimal.js.map +0 -1
  518. package/dist/transform/styles/narrative.d.ts +0 -4
  519. package/dist/transform/styles/narrative.d.ts.map +0 -1
  520. package/dist/transform/styles/narrative.js +0 -15
  521. package/dist/transform/styles/narrative.js.map +0 -1
  522. package/dist/transform/templateSelector.d.ts +0 -30
  523. package/dist/transform/templateSelector.d.ts.map +0 -1
  524. package/dist/transform/templateSelector.js +0 -218
  525. package/dist/transform/templateSelector.js.map +0 -1
  526. package/dist/transform/timingAllocator.d.ts +0 -21
  527. package/dist/transform/timingAllocator.d.ts.map +0 -1
  528. package/dist/transform/timingAllocator.js +0 -111
  529. package/dist/transform/timingAllocator.js.map +0 -1
  530. package/dist/transform/types.d.ts +0 -86
  531. package/dist/transform/types.d.ts.map +0 -1
  532. package/dist/transform/types.js +0 -9
  533. package/dist/transform/types.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transform/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAYvB,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"sources":["../../src/transform/styles/documentary.ts","../../src/transform/styles/magazine.ts","../../src/transform/styles/dataDriven.ts","../../src/transform/styles/narrative.ts","../../src/transform/styles/minimal.ts","../../src/transform/registry.ts","../../src/transform/blockAnalyzer.ts","../../src/transform/templateSelector.ts","../../src/transform/timingAllocator.ts","../../src/transform/applyTransform.ts"],"sourcesContent":["import type { TransformStyleConfig } from '../types.js';\n\n/** Conservative style — sparse highlights, preserves most text as-is. */\nexport const documentaryStyle: TransformStyleConfig = {\n id: 'documentary',\n name: 'Documentary',\n description: 'Conservative — highlights only the strongest stats, dates, and quotes',\n minConfidence: 0.5,\n transformRatio: 0.3,\n preferredTypes: ['stat', 'date', 'quote', 'fact'],\n colorSchemes: ['blue', 'green', 'purple'],\n insertSectionHeaders: false,\n interleaveImages: true,\n blocksPerSection: { min: 1, max: 3 },\n transitionStyle: 'fade',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Visual variety — pull quotes, definitions, image-heavy layout. */\nexport const magazineStyle: TransformStyleConfig = {\n id: 'magazine',\n name: 'Magazine',\n description: 'Visual variety with pull quotes, facts, and rich image layouts',\n minConfidence: 0.4,\n transformRatio: 0.6,\n preferredTypes: ['quote', 'fact', 'list', 'definition', 'stat', 'impactLine'],\n colorSchemes: ['blue', 'green', 'purple', 'orange', 'red'],\n insertSectionHeaders: true,\n interleaveImages: true,\n blocksPerSection: { min: 2, max: 5 },\n transitionStyle: 'dissolve',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Numbers-forward — aggressively extracts stats, comparisons, and dates. */\nexport const dataDrivenStyle: TransformStyleConfig = {\n id: 'data-driven',\n name: 'Data-Driven',\n description: 'Aggressively highlights statistics, comparisons, and timelines',\n minConfidence: 0.3,\n transformRatio: 0.8,\n preferredTypes: ['stat', 'comparison', 'date', 'list', 'fact'],\n colorSchemes: ['blue', 'orange', 'green', 'purple', 'red'],\n insertSectionHeaders: true,\n interleaveImages: false,\n blocksPerSection: { min: 2, max: 6 },\n transitionStyle: 'cut',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Timeline-focused — emphasizes dates, quotes, and story arc. */\nexport const narrativeStyle: TransformStyleConfig = {\n id: 'narrative',\n name: 'Narrative',\n description: 'Story-driven with timeline events, quotes, and impact moments',\n minConfidence: 0.4,\n transformRatio: 0.5,\n preferredTypes: ['date', 'quote', 'impactLine', 'fact', 'stat'],\n colorSchemes: ['blue', 'purple', 'green'],\n insertSectionHeaders: true,\n interleaveImages: true,\n blocksPerSection: { min: 1, max: 4 },\n transitionStyle: 'fade',\n};\n","import type { TransformStyleConfig } from '../types.js';\n\n/** Light touch — only the highest-confidence items get transformed. */\nexport const minimalStyle: TransformStyleConfig = {\n id: 'minimal',\n name: 'Minimal',\n description: 'Light touch — only the strongest highlights, mostly text',\n minConfidence: 0.6,\n transformRatio: 0.2,\n preferredTypes: ['stat', 'quote'],\n colorSchemes: ['blue', 'green'],\n insertSectionHeaders: false,\n interleaveImages: false,\n blocksPerSection: { min: 1, max: 2 },\n transitionStyle: 'fade',\n};\n","/**\n * Transform Style Registry\n *\n * Central registry of built-in transform styles. Follows the same pattern\n * as themeLibrary.ts — a record of configs with lookup/summary helpers.\n */\n\nimport type { TransformStyleConfig, TransformStyleSummary } from './types.js';\nimport { documentaryStyle } from './styles/documentary.js';\nimport { magazineStyle } from './styles/magazine.js';\nimport { dataDrivenStyle } from './styles/dataDriven.js';\nimport { narrativeStyle } from './styles/narrative.js';\nimport { minimalStyle } from './styles/minimal.js';\n\n/** All registered transform styles, keyed by id. */\nconst TRANSFORM_STYLES: Record<string, TransformStyleConfig> = {\n [documentaryStyle.id]: documentaryStyle,\n [magazineStyle.id]: magazineStyle,\n [dataDrivenStyle.id]: dataDrivenStyle,\n [narrativeStyle.id]: narrativeStyle,\n [minimalStyle.id]: minimalStyle,\n};\n\n/** Default style used when no id is provided. */\nexport const DEFAULT_TRANSFORM_STYLE_ID = 'documentary';\n\n/**\n * Resolve a transform style by id.\n * Returns the default style if the id is not found.\n */\nexport function resolveTransformStyle(id: string): TransformStyleConfig {\n return TRANSFORM_STYLES[id] ?? TRANSFORM_STYLES[DEFAULT_TRANSFORM_STYLE_ID];\n}\n\n/** Get all registered style ids. */\nexport function getTransformStyleIds(): string[] {\n return Object.keys(TRANSFORM_STYLES);\n}\n\n/** Get summary info for all styles (for UI dropdowns). */\nexport function getTransformStyleSummaries(): TransformStyleSummary[] {\n return Object.values(TRANSFORM_STYLES).map(({ id, name, description }) => ({\n id,\n name,\n description,\n }));\n}\n","/**\n * Block Analyzer\n *\n * Walks Doc blocks, extracts plain text from their markdown contents,\n * and runs the content extractor on each block to identify stats, dates,\n * quotes, etc. that can be promoted to visual template blocks.\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type { MarkdownBlockNode, MarkdownNode } from '../markdown/types.js';\nimport type { ExtractedElement, ExtractionOptions } from '../generate/contentExtractor.js';\nimport type { TransformImage } from './types.js';\nimport { extractContent, stripMarkdown } from '../generate/contentExtractor.js';\nimport { extractPlainText, getChildren } from '../markdown/utils.js';\n\n/** An image found in a block's markdown contents. */\nexport interface BlockImage {\n /** Image URL (relative or absolute). */\n src: string;\n /** Alt text. */\n alt: string;\n /** Index of the source block in the analyzed array. */\n sourceBlockIndex: number;\n}\n\n/** A block enriched with extraction analysis. */\nexport interface AnalyzedBlock {\n /** The original block. */\n block: Block;\n /** Plain text extracted from the block's contents. */\n plainText: string;\n /** Content extractions found in the block's text. */\n extractions: ExtractedElement[];\n /** Whether this block has child blocks. */\n hasChildren: boolean;\n /** Word count of the block's body text. */\n bodyWordCount: number;\n /** Images found in this block's markdown contents. */\n images: BlockImage[];\n}\n\n/**\n * Extract plain text from an array of MarkdownBlockNodes.\n */\nfunction contentsToPlainText(contents: MarkdownBlockNode[]): string {\n return contents.map((node) => extractPlainText(node)).join('\\n');\n}\n\n/**\n * Recursively walk a markdown node tree and collect all images.\n */\nfunction collectImages(node: MarkdownNode): Array<{ src: string; alt: string }> {\n const results: Array<{ src: string; alt: string }> = [];\n\n if ('type' in node && node.type === 'image' && 'url' in node) {\n const img = node as { url: string; alt?: string };\n if (img.url) {\n results.push({ src: img.url, alt: img.alt ?? '' });\n }\n }\n\n for (const child of getChildren(node)) {\n results.push(...collectImages(child));\n }\n\n return results;\n}\n\n/**\n * Extract images from a block's markdown contents.\n */\nfunction extractBlockImages(block: Block, blockIndex: number): BlockImage[] {\n if (!block.contents || block.contents.length === 0) return [];\n\n const images: BlockImage[] = [];\n for (const node of block.contents) {\n for (const img of collectImages(node)) {\n images.push({ ...img, sourceBlockIndex: blockIndex });\n }\n }\n return images;\n}\n\n/**\n * Collect all unique images from all blocks in a Doc.\n * Returns them as TransformImages for use in the transform pipeline.\n */\nexport function extractDocImages(blocks: Block[]): TransformImage[] {\n const seen = new Set<string>();\n const images: TransformImage[] = [];\n\n function walk(blockList: Block[]): void {\n for (const block of blockList) {\n if (block.contents) {\n for (const node of block.contents) {\n for (const img of collectImages(node)) {\n if (!seen.has(img.src)) {\n seen.add(img.src);\n images.push({ src: img.src, alt: img.alt });\n }\n }\n }\n }\n if (block.children) {\n walk(block.children);\n }\n }\n }\n\n walk(blocks);\n return images;\n}\n\n/**\n * Collect leaf blocks from a nested block tree.\n * Only returns blocks that have their own `contents` but no children,\n * preventing parent blocks from duplicating text that also appears\n * in their children. Parent-only blocks (with a title but no body\n * content) are included as structural placeholders.\n */\nfunction collectLeafBlocks(blocks: Block[]): Block[] {\n const result: Block[] = [];\n for (const block of blocks) {\n if (block.children && block.children.length > 0) {\n // Parent block — only include it as a structural marker\n // (title only, no body extraction) if it has no contents of its own.\n // Then recurse into children for the actual content.\n if (!block.contents || block.contents.length === 0) {\n result.push(block);\n }\n result.push(...collectLeafBlocks(block.children));\n } else {\n // Leaf block — include for content analysis\n result.push(block);\n }\n }\n return result;\n}\n\n/**\n * Analyze all blocks in a Doc, extracting text and running content extraction.\n *\n * @param blocks - The Doc's block array (may be nested via children).\n * @param options - Extraction options (minConfidence, types filter).\n * @returns Analyzed blocks with extractions, in flattened order.\n */\nexport function analyzeBlocks(blocks: Block[], options?: ExtractionOptions): AnalyzedBlock[] {\n const flat = collectLeafBlocks(blocks);\n const results: AnalyzedBlock[] = [];\n\n for (const block of flat) {\n let plainText = '';\n\n if (block.contents && block.contents.length > 0) {\n plainText = contentsToPlainText(block.contents);\n } else if (block.title) {\n plainText = block.title;\n }\n\n // Strip any remaining markdown syntax\n const stripped = stripMarkdown(plainText);\n const bodyWordCount = stripped.split(/\\s+/).filter((w) => w.length > 0).length;\n\n // Run content extraction\n const extraction = extractContent(stripped, options);\n\n // Extract images from markdown contents\n const images = extractBlockImages(block, results.length);\n\n results.push({\n block,\n plainText: stripped,\n extractions: extraction.elements,\n hasChildren: !!(block.children && block.children.length > 0),\n bodyWordCount,\n images,\n });\n }\n\n return results;\n}\n","/**\n * Template Selector\n *\n * Selects which extracted elements to promote to visual template blocks\n * and handles color scheme rotation, image interleaving, and template\n * variety. Ported and generalized from qualla-internal's TemplateSelector.\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type {\n TemplateBlock,\n AccentImage,\n AccentPosition,\n ImageWithCaptionInput,\n SectionHeaderInput,\n} from '../schemas/BlockTemplates.js';\nimport type { ExtractedElement } from '../generate/contentExtractor.js';\nimport type { TransformStyleConfig, TransformImage } from './types.js';\nimport type { AnalyzedBlock } from './blockAnalyzer.js';\nimport { mapElementToBlock } from '../generate/templateMapper.js';\nimport { SeededRandom } from '../random/SeededRandom.js';\n\n/** Accent positions to rotate through. */\nconst ACCENT_POSITIONS: AccentPosition[] = [\n 'left-strip',\n 'right-strip',\n 'bottom-strip',\n 'corner-inset',\n];\n\n/** Ambient motions to rotate on image blocks. */\nconst AMBIENT_MOTIONS: Array<'zoomIn' | 'zoomOut' | 'panLeft' | 'panRight'> = [\n 'zoomIn',\n 'zoomOut',\n 'panLeft',\n 'panRight',\n];\n\n/** A selected element paired with its source block. */\ninterface SelectedExtraction {\n element: ExtractedElement;\n sourceBlock: Block;\n /** Index in the original analyzed blocks array. */\n sourceIndex: number;\n}\n\n/** Result of template selection. */\nexport interface SelectionResult {\n /** Replacement blocks: a mix of original blocks and new template blocks. */\n blocks: Array<Block | TemplateBlock>;\n /** How many blocks were transformed. */\n transformedCount: number;\n /** How many blocks were inserted (images, section headers). */\n insertedCount: number;\n}\n\n/**\n * Select extractions and build a transformed block sequence.\n *\n * @param analyzed - Analyzed blocks from blockAnalyzer.\n * @param config - The transform style configuration.\n * @param images - Available images for interleaving.\n * @param seed - Random seed for deterministic output.\n */\nexport function selectAndBuild(\n analyzed: AnalyzedBlock[],\n config: TransformStyleConfig,\n images: TransformImage[],\n seed: number,\n): SelectionResult {\n const rng = new SeededRandom(seed);\n\n // 1. Collect all extractions across all blocks, filtered by config\n const candidates = collectCandidates(analyzed, config);\n\n // 2. Determine how many blocks to transform\n const maxTransforms = Math.max(1, Math.floor(analyzed.length * config.transformRatio));\n const selected = candidates.slice(0, maxTransforms);\n\n // 3. Build the output block sequence\n const result = buildBlockSequence(analyzed, selected, config, images, rng);\n\n return result;\n}\n\n/**\n * Collect candidate extractions from all analyzed blocks, sorted by\n * a combined score of confidence and type preference.\n */\nfunction collectCandidates(\n analyzed: AnalyzedBlock[],\n config: TransformStyleConfig,\n): SelectedExtraction[] {\n const candidates: SelectedExtraction[] = [];\n\n for (let i = 0; i < analyzed.length; i++) {\n const ab = analyzed[i];\n // Skip blocks with no meaningful text\n if (ab.bodyWordCount < 5) continue;\n\n for (const element of ab.extractions) {\n if (element.confidence < config.minConfidence) continue;\n\n candidates.push({\n element,\n sourceBlock: ab.block,\n sourceIndex: i,\n });\n }\n }\n\n // Sort by: preferred type rank (lower = better), then confidence (higher = better)\n const typeRank = new Map(config.preferredTypes.map((t, i) => [t, i]));\n const maxRank = config.preferredTypes.length;\n\n candidates.sort((a, b) => {\n const rankA = typeRank.get(a.element.type) ?? maxRank;\n const rankB = typeRank.get(b.element.type) ?? maxRank;\n if (rankA !== rankB) return rankA - rankB;\n return b.element.confidence - a.element.confidence;\n });\n\n // Deduplicate: if the same extracted text appears multiple times\n // (e.g., from overlapping parent/child blocks), keep only the\n // highest-ranked occurrence.\n const seenTexts = new Set<string>();\n const deduplicated: SelectedExtraction[] = [];\n for (const candidate of candidates) {\n const key = candidate.element.text.trim().toLowerCase();\n if (seenTexts.has(key)) continue;\n seenTexts.add(key);\n deduplicated.push(candidate);\n }\n\n return deduplicated;\n}\n\n/**\n * Build the output block sequence, replacing source blocks with template\n * blocks where extractions were selected, and interleaving images.\n */\nfunction buildBlockSequence(\n analyzed: AnalyzedBlock[],\n selected: SelectedExtraction[],\n config: TransformStyleConfig,\n images: TransformImage[],\n rng: SeededRandom,\n): SelectionResult {\n // Map: sourceIndex → list of selected extractions for that block\n const blockExtractions = new Map<number, SelectedExtraction[]>();\n for (const sel of selected) {\n const list = blockExtractions.get(sel.sourceIndex) ?? [];\n list.push(sel);\n blockExtractions.set(sel.sourceIndex, list);\n }\n\n // Limit extractions per block: cap at blocksPerSection.max and ensure\n // template type variety within each block (no two same-type extractions).\n for (const [idx, list] of blockExtractions) {\n const diverse: SelectedExtraction[] = [];\n const usedTypes = new Set<string>();\n for (const sel of list) {\n if (usedTypes.has(sel.element.type)) continue;\n usedTypes.add(sel.element.type);\n diverse.push(sel);\n if (diverse.length >= config.blocksPerSection.max) break;\n }\n blockExtractions.set(idx, diverse);\n }\n\n const blocks: Array<Block | TemplateBlock> = [];\n let transformedCount = 0;\n let insertedCount = 0;\n let colorIndex = 0;\n let blockIdCounter = 0;\n let imageIndex = 0;\n let accentPositionIndex = 0;\n let elementsSinceImage = 0;\n let prevTemplateType = '';\n\n // Calculate image interleaving interval\n const totalTransformed = Array.from(blockExtractions.values()).reduce(\n (sum, list) => sum + list.length,\n 0,\n );\n const imageInterval =\n config.interleaveImages && images.length > 0 && totalTransformed > 0\n ? Math.max(2, Math.floor(totalTransformed / (images.length + 1)))\n : Infinity;\n\n for (let i = 0; i < analyzed.length; i++) {\n const ab = analyzed[i];\n const extractions = blockExtractions.get(i);\n\n if (!extractions || extractions.length === 0) {\n // Keep the original block unchanged\n blocks.push(ab.block);\n continue;\n }\n\n // Insert section header before a group of transformed blocks (if enabled)\n if (config.insertSectionHeaders && ab.block.title) {\n const headerBlock: SectionHeaderInput = {\n template: 'sectionHeader',\n id: `transform-header-${blockIdCounter++}`,\n duration: ab.block.duration > 0 ? Math.min(3, ab.block.duration * 0.2) : 3,\n audioSegment: ab.block.audioSegment,\n title: ab.block.title,\n colorScheme: config.colorSchemes[colorIndex % config.colorSchemes.length],\n };\n blocks.push(headerBlock);\n insertedCount++;\n }\n\n // Convert each selected extraction to a template block.\n // Track the last template used globally (not just within this block)\n // to avoid consecutive same-template slides across the entire output.\n for (const sel of extractions) {\n const colorScheme = config.colorSchemes[colorIndex % config.colorSchemes.length];\n\n // Build accent image if we have images in the pool\n let accentImage: AccentImage | undefined;\n if (images.length > 0 && config.interleaveImages) {\n const img = images[imageIndex % images.length];\n accentImage = {\n src: img.src,\n alt: img.alt ?? '',\n position: ACCENT_POSITIONS[accentPositionIndex % ACCENT_POSITIONS.length],\n ambientMotion: rng.pick(AMBIENT_MOTIONS) ?? 'zoomIn',\n credit: img.credit,\n license: img.license,\n };\n accentPositionIndex++;\n }\n\n const templateBlock = mapElementToBlock(sel.element, {\n id: `transform-${blockIdCounter++}`,\n duration: ab.block.duration > 0 ? ab.block.duration / extractions.length : 6,\n audioSegment: ab.block.audioSegment,\n colorScheme,\n accentImage,\n sourceStartTime: sel.element.sourcePosition,\n });\n\n // Apply transition based on style\n if (config.transitionStyle !== 'cut') {\n (\n templateBlock as TemplateBlock & { transition?: { type: string; duration: number } }\n ).transition = {\n type:\n config.transitionStyle === 'mixed'\n ? (rng.pick(['fade', 'dissolve']) ?? 'fade')\n : config.transitionStyle,\n duration: 0.5,\n };\n }\n\n // Avoid consecutive same-template blocks by bumping color for variety\n if (templateBlock.template === prevTemplateType) {\n colorIndex++;\n }\n prevTemplateType = templateBlock.template;\n\n blocks.push(templateBlock);\n transformedCount++;\n colorIndex++;\n elementsSinceImage++;\n\n // Interleave standalone image at intervals\n if (\n config.interleaveImages &&\n imageIndex < images.length &&\n elementsSinceImage >= imageInterval\n ) {\n const img = images[imageIndex];\n const imageBlock: ImageWithCaptionInput = {\n template: 'imageWithCaption',\n id: `transform-img-${blockIdCounter++}`,\n duration: 4,\n audioSegment: ab.block.audioSegment,\n imageSrc: img.src,\n imageAlt: img.alt ?? '',\n ambientMotion: rng.pick(AMBIENT_MOTIONS) ?? 'zoomIn',\n };\n blocks.push(imageBlock);\n imageIndex++;\n insertedCount++;\n elementsSinceImage = 0;\n }\n }\n }\n\n return { blocks, transformedCount, insertedCount };\n}\n","/**\n * Timing Allocator\n *\n * Distributes timing (startTime, duration) across transformed blocks.\n * When the source Doc has audio, blocks are fitted to the overall duration.\n * When no audio is present, uses reading-time estimation.\n */\n\nimport type { Block } from '../schemas/Doc.js';\nimport type { TemplateBlock } from '../schemas/BlockTemplates.js';\nimport { isTemplateBlock } from '../schemas/BlockTemplates.js';\n\n/** Minimum block duration in seconds. */\nconst MIN_BLOCK_DURATION = 3;\n/** Maximum block duration in seconds. */\nconst MAX_BLOCK_DURATION = 20;\n/** Default duration when no timing info is available. */\nconst DEFAULT_BLOCK_DURATION = 6;\n\n/**\n * Allocate startTime and duration across a mixed array of blocks and\n * template blocks. Template blocks get timing assigned; existing blocks\n * retain their original timing when possible.\n *\n * @param blocks - The output from templateSelector (mixed Block | TemplateBlock).\n * @param totalDuration - The Doc's total duration (from audio or estimation).\n * @returns A new array of Blocks with consistent timing. Template blocks\n * are returned as Blocks (with startTime/duration set, layers empty).\n */\nexport function allocateTiming(\n blocks: Array<Block | TemplateBlock>,\n totalDuration: number,\n): Block[] {\n if (blocks.length === 0) return [];\n\n const effectiveDuration = totalDuration > 0 ? totalDuration : estimateDefaultDuration(blocks);\n\n // First pass: assign raw durations\n const durations = blocks.map((block) => {\n if (!isTemplateBlock(block) && block.duration > 0) {\n // Existing block with known duration — keep it\n return block.duration;\n }\n if (isTemplateBlock(block) && block.duration > 0) {\n return block.duration;\n }\n return DEFAULT_BLOCK_DURATION;\n });\n\n // Scale durations to fit the total\n const rawTotal = durations.reduce((sum, d) => sum + d, 0);\n if (rawTotal > 0 && effectiveDuration > 0) {\n const scale = effectiveDuration / rawTotal;\n for (let i = 0; i < durations.length; i++) {\n durations[i] = clampDuration(durations[i] * scale);\n }\n }\n\n // Second pass: assign startTimes and build output Blocks\n let currentTime = 0;\n const result: Block[] = [];\n\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n const duration = durations[i];\n\n if (isTemplateBlock(block)) {\n // Convert TemplateBlock to Block shell, preserving all template-specific\n // fields (stat, quote, description, etc.) so they survive through to\n // the player's template expansion step.\n const outputBlock = {\n ...block,\n startTime: currentTime,\n duration,\n title: getTemplateTitle(block),\n } as unknown as Block;\n result.push(outputBlock);\n } else {\n // Existing block — update timing\n result.push({\n ...block,\n startTime: currentTime,\n duration,\n });\n }\n\n currentTime += duration;\n }\n\n return result;\n}\n\n/** Clamp a duration to the min/max range. */\nfunction clampDuration(d: number): number {\n return Math.max(MIN_BLOCK_DURATION, Math.min(MAX_BLOCK_DURATION, d));\n}\n\n/** Estimate a total duration from block contents when no audio is available. */\nfunction estimateDefaultDuration(blocks: Array<Block | TemplateBlock>): number {\n let totalSeconds = 0;\n for (const block of blocks) {\n if (!isTemplateBlock(block) && block.duration > 0) {\n totalSeconds += block.duration;\n } else {\n totalSeconds += DEFAULT_BLOCK_DURATION;\n }\n }\n return Math.max(totalSeconds, blocks.length * MIN_BLOCK_DURATION);\n}\n\n/** Extract a display title from a template block if available. */\nfunction getTemplateTitle(block: TemplateBlock): string | undefined {\n if ('title' in block && typeof block.title === 'string') {\n return block.title;\n }\n if ('stat' in block && typeof block.stat === 'string') {\n return block.stat;\n }\n if ('fact' in block && typeof block.fact === 'string') {\n return block.fact;\n }\n if ('quote' in block && typeof block.quote === 'string') {\n return block.quote.slice(0, 60);\n }\n return undefined;\n}\n","/**\n * Apply Transform\n *\n * Main entry point for the transform module. Takes a Doc and a style,\n * analyzes block content, selects extractions to promote, and returns\n * a new Doc with blocks optimized for visual presentation.\n *\n * The input Doc is never mutated — a fresh Doc is always returned.\n */\n\nimport type { Doc } from '../schemas/Doc.js';\nimport type { TransformStyleId, TransformOptions, TransformResult } from './types.js';\nimport { resolveTransformStyle } from './registry.js';\nimport { analyzeBlocks, extractDocImages } from './blockAnalyzer.js';\nimport { selectAndBuild } from './templateSelector.js';\nimport { allocateTiming } from './timingAllocator.js';\nimport { hashString } from '../random/SeededRandom.js';\n\n/**\n * Apply a transform style to a Doc, producing a new Doc with blocks\n * optimized for visual presentation.\n *\n * @param doc - The source Doc (not mutated).\n * @param styleId - Registered transform style id (e.g. 'documentary', 'magazine').\n * @param options - Optional seed, images, theme override.\n * @returns TransformResult with the new Doc and stats.\n */\nexport function applyTransform(\n doc: Doc,\n styleId: TransformStyleId,\n options?: TransformOptions,\n): TransformResult {\n const baseConfig = resolveTransformStyle(styleId);\n const config = options?.overrides\n ? { ...baseConfig, ...options.overrides, id: baseConfig.id }\n : baseConfig;\n\n const seed = options?.seed ?? hashString(doc.articleId || 'transform');\n\n // Use provided images or auto-extract from the doc's markdown content\n const images = options?.images ?? extractDocImages(doc.blocks);\n\n // 1. Analyze blocks\n const analyzed = analyzeBlocks(doc.blocks, {\n minConfidence: config.minConfidence,\n types: config.preferredTypes,\n });\n\n // If no blocks have meaningful content, return the doc unchanged\n const hasContent = analyzed.some((ab) => ab.bodyWordCount >= 5);\n if (!hasContent) {\n return {\n doc: { ...doc },\n stats: {\n totalInputBlocks: doc.blocks.length,\n transformedBlocks: 0,\n insertedBlocks: 0,\n },\n };\n }\n\n // 2. Select extractions and build template blocks\n const selection = selectAndBuild(analyzed, config, images, seed);\n\n // 3. Allocate timing across the new block sequence\n const timedBlocks = allocateTiming(selection.blocks, doc.duration);\n\n // 4. Assemble the output Doc\n const transformedDoc: Doc = {\n ...doc,\n blocks: timedBlocks,\n themeId: options?.themeId ?? doc.themeId,\n };\n\n return {\n doc: transformedDoc,\n stats: {\n totalInputBlocks: doc.blocks.length,\n transformedBlocks: selection.transformedCount,\n insertedBlocks: selection.insertedCount,\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -394,6 +394,21 @@ interface MarkdownInlineMath extends MarkdownNodeBase {
394
394
  /** Math content (without $ delimiters) */
395
395
  value: string;
396
396
  }
397
+ /**
398
+ * Inline FontAwesome icon. Authored as `{[name]}` (bare) or
399
+ * `{[fa-<family>:name]}` (qualified) in markdown source. The parser
400
+ * resolves the token against the FA Free catalog and emits this node;
401
+ * unknown / ambiguous tokens stay as literal text.
402
+ */
403
+ interface MarkdownInlineIcon extends MarkdownNodeBase {
404
+ type: 'inlineIcon';
405
+ /** Token exactly as authored — e.g. `github` or `fa-solid:user`. */
406
+ token: string;
407
+ /** Resolved icon family. */
408
+ family: 'brands' | 'solid' | 'regular';
409
+ /** Resolved icon name (without the `fa-` prefix). */
410
+ name: string;
411
+ }
397
412
  /**
398
413
  * A footnote reference [^id]. GFM extension.
399
414
  */
@@ -455,7 +470,7 @@ interface MarkdownTextDirective extends MarkdownNodeBase {
455
470
  */
456
471
  interface MarkdownMention extends MarkdownNodeBase {
457
472
  type: 'mention';
458
- /** Namespace for the mentioned entity (e.g. `"gezel"`, `"user"`). */
473
+ /** Namespace for the mentioned entity (e.g. `"user"`). */
459
474
  targetKind: string;
460
475
  /** Stable identifier within the namespace. */
461
476
  targetId: string;
@@ -465,7 +480,7 @@ interface MarkdownMention extends MarkdownNodeBase {
465
480
  /** Block-level content that can appear as direct children of the document root, blockquotes, list items, etc. */
466
481
  type MarkdownBlockNode = MarkdownHeading | MarkdownParagraph | MarkdownBlockquote | MarkdownList | MarkdownCodeBlock | MarkdownThematicBreak | MarkdownTable | MarkdownHtmlBlock | MarkdownMathBlock | MarkdownLinkDefinition | MarkdownFootnoteDefinition | MarkdownContainerDirective | MarkdownLeafDirective | MarkdownDefinitionList;
467
482
  /** Inline/phrasing content that appears inside paragraphs, headings, links, etc. */
468
- type MarkdownInlineNode = MarkdownText | MarkdownEmphasis | MarkdownStrong | MarkdownStrikethrough | MarkdownInlineCode | MarkdownLink | MarkdownImage | MarkdownBreak | MarkdownInlineHtml | MarkdownInlineMath | MarkdownFootnoteReference | MarkdownLinkReference | MarkdownImageReference | MarkdownTextDirective | MarkdownMention;
483
+ type MarkdownInlineNode = MarkdownText | MarkdownEmphasis | MarkdownStrong | MarkdownStrikethrough | MarkdownInlineCode | MarkdownLink | MarkdownImage | MarkdownBreak | MarkdownInlineHtml | MarkdownInlineMath | MarkdownFootnoteReference | MarkdownLinkReference | MarkdownImageReference | MarkdownTextDirective | MarkdownMention | MarkdownInlineIcon;
469
484
  /**
470
485
  * Any node in the markdown tree. Includes structural nodes (listItem,
471
486
  * tableRow, tableCell, etc.) that only appear as children of specific parents.
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Public types for the document version-history feature.
3
+ *
4
+ * Versions are snapshots of the primary markdown document stored alongside
5
+ * the document inside the same {@link ContentContainer}. They live under
6
+ * `.versions/<docBasename>.<sortableTimestamp>.md`. The container is the
7
+ * unit of persistence — when the host serializes the container to a ZIP,
8
+ * a real folder, or anywhere else, the version snapshots ride along.
9
+ */
10
+ /**
11
+ * A single version snapshot record.
12
+ */
13
+ interface Version {
14
+ /** Container-relative path, e.g. `.versions/index.20260430T152030Z.md`. */
15
+ path: string;
16
+ /** Document basename without extension, e.g. `index`. */
17
+ basename: string;
18
+ /** Parsed timestamp from the filename, in UTC. */
19
+ timestamp: Date;
20
+ /** Snapshot size in bytes. */
21
+ size: number;
22
+ /**
23
+ * Collision suffix index. `0` for a path with no `-N` suffix, `1` for `-2`,
24
+ * `2` for `-3`, and so on. Used as the tie-break for ordering snapshots
25
+ * that share the same UTC second.
26
+ */
27
+ collision: number;
28
+ }
29
+ /**
30
+ * Result of a {@link saveVersion} call.
31
+ */
32
+ interface SaveVersionResult {
33
+ /** True when a new snapshot file was actually written. */
34
+ saved: boolean;
35
+ /** The newly stamped version (only when `saved` is true). */
36
+ version: Version | null;
37
+ /**
38
+ * Why the save behaved the way it did:
39
+ * - `'saved'` — a new snapshot was written.
40
+ * - `'unchanged'` — current content matches the latest snapshot byte-for-byte.
41
+ * - `'no-document'` — the container has no primary markdown document.
42
+ * - `'empty'` — the resolved content was empty.
43
+ */
44
+ reason: 'saved' | 'unchanged' | 'no-document' | 'empty';
45
+ }
46
+ /**
47
+ * Options for {@link saveVersion}.
48
+ */
49
+ interface SaveVersionOptions {
50
+ /** Override the document content; otherwise the container's primary doc is read. */
51
+ content?: string;
52
+ /** Override the timestamp; defaults to `new Date()`. Useful for tests. */
53
+ now?: Date;
54
+ /** Skip the diff-vs-latest check and force a write. */
55
+ force?: boolean;
56
+ /** Override the document basename used to build the version filename. */
57
+ basename?: string;
58
+ }
59
+ /**
60
+ * Pruning policy passed to {@link pruneVersions}.
61
+ */
62
+ type PrunePolicy = {
63
+ type: 'keep-last-n';
64
+ n: number;
65
+ } | {
66
+ type: 'older-than';
67
+ date: Date;
68
+ } | {
69
+ type: 'predicate';
70
+ keep: (v: Version, all: Version[]) => boolean;
71
+ };
72
+ /**
73
+ * Options for {@link revertToVersion}.
74
+ */
75
+ interface RevertOptions {
76
+ /**
77
+ * Whether to snapshot the current document content before replacing it.
78
+ * Defaults to `true` so a revert is always recoverable.
79
+ */
80
+ snapshotCurrent?: boolean;
81
+ }
82
+ /**
83
+ * Options for {@link coalesceVersions}.
84
+ */
85
+ interface CoalesceOptions {
86
+ /**
87
+ * Two adjacent snapshots whose timestamps are within `windowMs` collapse
88
+ * to the newer one. Defaults to 60_000 (one minute).
89
+ */
90
+ windowMs?: number;
91
+ }
92
+
93
+ export type { CoalesceOptions as C, PrunePolicy as P, RevertOptions as R, SaveVersionOptions as S, Version as V, SaveVersionResult as a };
@@ -0,0 +1,128 @@
1
+ import { C as CoalesceOptions, V as Version, P as PrunePolicy, R as RevertOptions, S as SaveVersionOptions, a as SaveVersionResult } from '../types-D98li1gV.js';
2
+ import { C as ContentContainer } from '../ContentContainer-DNx460y8.js';
3
+
4
+ /**
5
+ * Pure-ish version operations against a {@link ContentContainer}.
6
+ *
7
+ * These functions are the canonical implementation. {@link DocumentVersionManager}
8
+ * is a thin wrapper that captures a container reference for ergonomics.
9
+ */
10
+
11
+ /**
12
+ * List all snapshots in the container, newest-first.
13
+ *
14
+ * @param basename Optional filter: when set, only versions whose basename
15
+ * matches are returned.
16
+ */
17
+ declare function listVersions(container: ContentContainer, basename?: string): Promise<Version[]>;
18
+ /**
19
+ * Read the markdown content of a snapshot. Returns null if the snapshot
20
+ * doesn't exist.
21
+ */
22
+ declare function readVersion(container: ContentContainer, version: Version | string): Promise<string | null>;
23
+ /**
24
+ * Save a new snapshot of the document if its content differs from the
25
+ * latest existing snapshot.
26
+ */
27
+ declare function saveVersion(container: ContentContainer, options?: SaveVersionOptions): Promise<SaveVersionResult>;
28
+ /**
29
+ * Revert the document to a prior snapshot. By default, the *current*
30
+ * document is snapshotted first so the revert is itself recoverable.
31
+ */
32
+ declare function revertToVersion(container: ContentContainer, version: Version | string, options?: RevertOptions): Promise<{
33
+ reverted: boolean;
34
+ snapshotted: Version | null;
35
+ }>;
36
+ /**
37
+ * Delete snapshots that don't satisfy the policy. Returns the deleted
38
+ * versions in their original (newest-first) order.
39
+ */
40
+ declare function pruneVersions(container: ContentContainer, policy: PrunePolicy, basename?: string): Promise<Version[]>;
41
+ /**
42
+ * Collapse adjacent snapshots that occurred close together — keeping the
43
+ * newer one — to keep history readable across rapid edits.
44
+ */
45
+ declare function coalesceVersions(container: ContentContainer, options?: CoalesceOptions, basename?: string): Promise<Version[]>;
46
+
47
+ /**
48
+ * Convenience wrapper around the version operations that captures a
49
+ * {@link ContentContainer} reference and an optional basename override.
50
+ *
51
+ * Hosts that prefer a stable handle (e.g. to pass into a UI component)
52
+ * use this; everything it does is also reachable as a free function.
53
+ */
54
+
55
+ interface DocumentVersionManagerOptions {
56
+ /**
57
+ * Override the document basename used in version filenames. Defaults to
58
+ * the basename of `container.getDocumentPath()` resolved at call time.
59
+ */
60
+ basename?: string;
61
+ }
62
+ declare class DocumentVersionManager {
63
+ private readonly container;
64
+ private readonly basename;
65
+ constructor(container: ContentContainer, options?: DocumentVersionManagerOptions);
66
+ saveVersion(options?: SaveVersionOptions): Promise<SaveVersionResult>;
67
+ listVersions(): Promise<Version[]>;
68
+ readVersion(version: Version | string): Promise<string | null>;
69
+ revertToVersion(version: Version | string, options?: RevertOptions): Promise<{
70
+ reverted: boolean;
71
+ snapshotted: Version | null;
72
+ }>;
73
+ pruneVersions(policy: PrunePolicy): Promise<Version[]>;
74
+ coalesceVersions(options?: CoalesceOptions): Promise<Version[]>;
75
+ }
76
+
77
+ /**
78
+ * Sortable, human-readable timestamps for version filenames.
79
+ *
80
+ * Format: ISO 8601 basic, UTC, second precision, `Z` suffix —
81
+ * e.g. `20260430T152030Z`. Lexicographic order matches chronological order,
82
+ * so `listFiles` returns versions in time order without parsing.
83
+ */
84
+ /**
85
+ * Format a Date as a sortable, filename-safe UTC timestamp string.
86
+ */
87
+ declare function formatVersionTimestamp(date: Date): string;
88
+ /**
89
+ * Parse a version timestamp string back to a Date. Returns null if the input
90
+ * doesn't match the expected format.
91
+ */
92
+ declare function parseVersionTimestamp(stamp: string): Date | null;
93
+ /**
94
+ * The pattern a valid version timestamp matches. Exported so other modules
95
+ * can validate filenames without re-deriving the regex.
96
+ */
97
+ declare const VERSION_TIMESTAMP_PATTERN: RegExp;
98
+
99
+ /**
100
+ * Path conventions for version snapshots.
101
+ *
102
+ * Snapshots live at `<VERSIONS_PREFIX><basename>.<timestamp>[<-suffix>].md`.
103
+ * The optional numeric suffix (`-2`, `-3`, ...) is appended only when two
104
+ * snapshots collide on the same UTC second.
105
+ */
106
+ /** Subfolder (inside the ContentContainer) that holds version snapshots. */
107
+ declare const VERSIONS_PREFIX = ".versions/";
108
+ /**
109
+ * Strip the directory and extension from a document path to produce the
110
+ * basename used in version filenames. `subdir/index.md` -> `index`.
111
+ */
112
+ declare function getDocBasename(documentPath: string): string;
113
+ /**
114
+ * Build a version snapshot path. Optionally append a collision suffix
115
+ * (e.g. `2`, `3`) when two saves land on the same UTC second.
116
+ */
117
+ declare function buildVersionPath(basename: string, date: Date, collision?: number): string;
118
+ /**
119
+ * Parse a version snapshot path. Returns null if it doesn't match the
120
+ * convention (so unrelated files stored under `.versions/` are ignored).
121
+ */
122
+ declare function parseVersionPath(path: string): {
123
+ basename: string;
124
+ timestamp: Date;
125
+ collision: number;
126
+ } | null;
127
+
128
+ export { CoalesceOptions, DocumentVersionManager, type DocumentVersionManagerOptions, PrunePolicy, RevertOptions, SaveVersionOptions, SaveVersionResult, VERSIONS_PREFIX, VERSION_TIMESTAMP_PATTERN, Version, buildVersionPath, coalesceVersions, formatVersionTimestamp, getDocBasename, listVersions, parseVersionPath, parseVersionTimestamp, pruneVersions, readVersion, revertToVersion, saveVersion };
@@ -0,0 +1,35 @@
1
+ import {
2
+ DocumentVersionManager,
3
+ VERSIONS_PREFIX,
4
+ buildVersionPath,
5
+ coalesceVersions,
6
+ getDocBasename,
7
+ listVersions,
8
+ parseVersionPath,
9
+ pruneVersions,
10
+ readVersion,
11
+ revertToVersion,
12
+ saveVersion
13
+ } from "../chunk-VLJJHDAC.js";
14
+ import {
15
+ VERSION_TIMESTAMP_PATTERN,
16
+ formatVersionTimestamp,
17
+ parseVersionTimestamp
18
+ } from "../chunk-JELIRVDP.js";
19
+ export {
20
+ DocumentVersionManager,
21
+ VERSIONS_PREFIX,
22
+ VERSION_TIMESTAMP_PATTERN,
23
+ buildVersionPath,
24
+ coalesceVersions,
25
+ formatVersionTimestamp,
26
+ getDocBasename,
27
+ listVersions,
28
+ parseVersionPath,
29
+ parseVersionTimestamp,
30
+ pruneVersions,
31
+ readVersion,
32
+ revertToVersion,
33
+ saveVersion
34
+ };
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "Headless utilities for doc/block rendering, spatial math, Markdown, and storage",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",
@@ -85,13 +85,40 @@
85
85
  "types": "./dist/transform/index.d.ts",
86
86
  "import": "./dist/transform/index.js",
87
87
  "default": "./dist/transform/index.js"
88
+ },
89
+ "./versions": {
90
+ "types": "./dist/versions/index.d.ts",
91
+ "import": "./dist/versions/index.js",
92
+ "default": "./dist/versions/index.js"
93
+ },
94
+ "./jsonForm": {
95
+ "types": "./dist/jsonForm/index.d.ts",
96
+ "import": "./dist/jsonForm/index.js",
97
+ "default": "./dist/jsonForm/index.js"
98
+ },
99
+ "./imageEdit": {
100
+ "types": "./dist/imageEdit/index.d.ts",
101
+ "import": "./dist/imageEdit/index.js",
102
+ "default": "./dist/imageEdit/index.js"
103
+ },
104
+ "./icons": {
105
+ "types": "./dist/icons/index.d.ts",
106
+ "import": "./dist/icons/index.js",
107
+ "default": "./dist/icons/index.js"
108
+ },
109
+ "./recommend": {
110
+ "types": "./dist/recommend/index.d.ts",
111
+ "import": "./dist/recommend/index.js",
112
+ "default": "./dist/recommend/index.js"
88
113
  }
89
114
  },
90
115
  "scripts": {
91
116
  "build": "tsup",
117
+ "dev": "concurrently -n js,dts -c blue,gray -r \"tsup --watch --no-dts --no-clean\" \"tsup --watch --dts-only --no-clean\"",
92
118
  "typecheck": "tsc --noEmit"
93
119
  },
94
120
  "dependencies": {
121
+ "genson-js": "0.0.8",
95
122
  "hast-util-from-html": "2.0.3",
96
123
  "localforage": "1.10.0",
97
124
  "ngeohash": "0.6.3",
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ isHex,
4
+ oklchLighten,
5
+ oklchDarken,
6
+ oklchSetChroma,
7
+ contrastRatio,
8
+ pickContrastingText,
9
+ deriveScale,
10
+ relativeLuminance,
11
+ } from '../schemas/colorUtils.js';
12
+
13
+ describe('isHex', () => {
14
+ it('accepts #rgb and #rrggbb', () => {
15
+ expect(isHex('#fff')).toBe(true);
16
+ expect(isHex('#123abc')).toBe(true);
17
+ expect(isHex('#FF0080')).toBe(true);
18
+ });
19
+ it('rejects malformed strings', () => {
20
+ expect(isHex('fff')).toBe(false);
21
+ expect(isHex('#1234')).toBe(false);
22
+ expect(isHex('#xyz')).toBe(false);
23
+ expect(isHex('rgb(0,0,0)')).toBe(false);
24
+ });
25
+ });
26
+
27
+ describe('oklchLighten / oklchDarken', () => {
28
+ it('lighten produces a lighter color (higher luminance)', () => {
29
+ const dark = '#101010';
30
+ const lighter = oklchLighten(dark, 0.2);
31
+ expect(relativeLuminance(lighter)).toBeGreaterThan(relativeLuminance(dark));
32
+ });
33
+
34
+ it('darken produces a darker color (lower luminance)', () => {
35
+ const light = '#e0e0e0';
36
+ const darker = oklchDarken(light, 0.2);
37
+ expect(relativeLuminance(darker)).toBeLessThan(relativeLuminance(light));
38
+ });
39
+
40
+ it('round-trips approximately stable for moderate adjustments', () => {
41
+ const seed = '#3182ce';
42
+ const round = oklchDarken(oklchLighten(seed, 0.1), 0.1);
43
+ // sRGB gamut clamping prevents perfect round-trip; expect within a small epsilon.
44
+ expect(round).toMatch(/^#[0-9a-f]{6}$/);
45
+ const lumDiff = Math.abs(relativeLuminance(seed) - relativeLuminance(round));
46
+ expect(lumDiff).toBeLessThan(0.05);
47
+ });
48
+
49
+ it('returns a hex string', () => {
50
+ expect(oklchLighten('#3182ce', 0.1)).toMatch(/^#[0-9a-f]{6}$/);
51
+ expect(oklchDarken('#3182ce', 0.1)).toMatch(/^#[0-9a-f]{6}$/);
52
+ });
53
+
54
+ it('falls back to input on parse failure', () => {
55
+ expect(oklchLighten('not-a-color', 0.1)).toBe('not-a-color');
56
+ });
57
+ });
58
+
59
+ describe('oklchSetChroma', () => {
60
+ it('reducing chroma toward 0 desaturates a color', () => {
61
+ const vivid = '#ff3366';
62
+ const muted = oklchSetChroma(vivid, 0.1);
63
+ // Muted version's R/G/B channels should be much closer to each other than vivid.
64
+ const parse = (h: string) => [
65
+ parseInt(h.slice(1, 3), 16),
66
+ parseInt(h.slice(3, 5), 16),
67
+ parseInt(h.slice(5, 7), 16),
68
+ ];
69
+ const [vr, vg, vb] = parse(vivid);
70
+ const [mr, mg, mb] = parse(muted);
71
+ const vSpread = Math.max(vr, vg, vb) - Math.min(vr, vg, vb);
72
+ const mSpread = Math.max(mr, mg, mb) - Math.min(mr, mg, mb);
73
+ expect(mSpread).toBeLessThan(vSpread);
74
+ });
75
+ });
76
+
77
+ describe('contrastRatio', () => {
78
+ it('white-on-black is the maximum (≈21)', () => {
79
+ expect(contrastRatio('#ffffff', '#000000')).toBeCloseTo(21, 0);
80
+ });
81
+ it('same-color is 1', () => {
82
+ expect(contrastRatio('#aabbcc', '#aabbcc')).toBeCloseTo(1, 5);
83
+ });
84
+ it('is symmetric', () => {
85
+ expect(contrastRatio('#222', '#ddd')).toBeCloseTo(contrastRatio('#ddd', '#222'), 5);
86
+ });
87
+ });
88
+
89
+ describe('pickContrastingText', () => {
90
+ it('returns dark text for light backgrounds', () => {
91
+ expect(pickContrastingText('#ffffff')).toBe('#1a202c');
92
+ expect(pickContrastingText('#f7fafc')).toBe('#1a202c');
93
+ });
94
+ it('returns light text for dark backgrounds', () => {
95
+ expect(pickContrastingText('#000000')).toBe('#f7fafc');
96
+ expect(pickContrastingText('#1a202c')).toBe('#f7fafc');
97
+ });
98
+ it('respects custom light/dark options', () => {
99
+ expect(pickContrastingText('#000000', '#fefefe', '#020202')).toBe('#fefefe');
100
+ });
101
+ });
102
+
103
+ describe('deriveScale', () => {
104
+ it('produces 5 stops with base in the middle', () => {
105
+ const scale = deriveScale('#3182ce', 0.15);
106
+ expect(scale.base).toBe('#3182ce');
107
+ expect(relativeLuminance(scale.lighter2)).toBeGreaterThan(relativeLuminance(scale.lighter1));
108
+ expect(relativeLuminance(scale.lighter1)).toBeGreaterThan(relativeLuminance(scale.base));
109
+ expect(relativeLuminance(scale.base)).toBeGreaterThan(relativeLuminance(scale.darker1));
110
+ expect(relativeLuminance(scale.darker1)).toBeGreaterThan(relativeLuminance(scale.darker2));
111
+ });
112
+ });
@@ -11,7 +11,7 @@ import type { Block, Layer, TextLayer, ShapeLayer } from '../schemas/Doc.js';
11
11
 
12
12
  function makeTemplateBlock(overrides: Partial<TemplateBlock> = {}): TemplateBlock {
13
13
  return {
14
- template: 'titleBlock',
14
+ template: 'title',
15
15
  id: 'test-title-1',
16
16
  duration: 5,
17
17
  audioSegment: 0,
@@ -43,7 +43,7 @@ const defaultContext: RenderContext = {
43
43
 
44
44
  describe('getLayers', () => {
45
45
  it('generates layers for a known template block', () => {
46
- const block = makeTemplateBlock({ template: 'titleBlock', title: 'Test Title' });
46
+ const block = makeTemplateBlock({ template: 'title', title: 'Test Title' });
47
47
  const layers = getLayers(block, defaultContext);
48
48
 
49
49
  expect(Array.isArray(layers)).toBe(true);
@@ -83,6 +83,31 @@ describe('getLayers', () => {
83
83
  expect(layers).toEqual(existingLayers);
84
84
  });
85
85
 
86
+ it('resolves legacy template aliases through TEMPLATE_ALIASES', () => {
87
+ // Regression: `getLayers` previously did `block.template in templateRegistry`
88
+ // without alias resolution, so docs authored with the legacy long ids
89
+ // (`titleBlock`, `quoteBlock`, `mapBlock`, `listBlock`) rendered as
90
+ // empty SVG cards in the linear/document view — `hasTemplate()` accepts
91
+ // the alias, so `isAnnotatedBlock` returns true and the card wrapper
92
+ // renders, but the registry lookup below would miss the alias and the
93
+ // layer array came back empty.
94
+ const aliasedToCanonical: Array<[string, string]> = [
95
+ ['titleBlock', 'title'],
96
+ ['quoteBlock', 'quote'],
97
+ ['listBlock', 'list'],
98
+ ];
99
+ for (const [alias] of aliasedToCanonical) {
100
+ const block = makeTemplateBlock({
101
+ template: alias as TemplateBlock['template'],
102
+ title: 'Aliased',
103
+ items: ['a', 'b', 'c'],
104
+ quote: 'q',
105
+ } as Partial<TemplateBlock>);
106
+ const layers = getLayers(block, defaultContext);
107
+ expect(layers.length).toBeGreaterThan(0);
108
+ }
109
+ });
110
+
86
111
  it('returns empty array for unknown template', () => {
87
112
  const block = {
88
113
  template: 'totally_nonexistent',
@@ -103,7 +128,7 @@ describe('getLayers', () => {
103
128
  });
104
129
 
105
130
  it('uses default context values when context is omitted', () => {
106
- const block = makeTemplateBlock({ template: 'titleBlock', title: 'Defaults' });
131
+ const block = makeTemplateBlock({ template: 'title', title: 'Defaults' });
107
132
  const layers = getLayers(block);
108
133
 
109
134
  expect(Array.isArray(layers)).toBe(true);
@@ -147,7 +172,7 @@ describe('getLayers', () => {
147
172
  };
148
173
 
149
174
  it('injects persistent bottom and top layers around block layers', () => {
150
- const block = makeTemplateBlock({ template: 'titleBlock', title: 'With Persistent' });
175
+ const block = makeTemplateBlock({ template: 'title', title: 'With Persistent' });
151
176
  const layers = getLayers(block, { ...defaultContext, persistentLayers: persistentConfig });
152
177
 
153
178
  // First layer should be the bottom persistent layer
@@ -160,7 +185,7 @@ describe('getLayers', () => {
160
185
 
161
186
  it('respects useBottomLayer: false opt-out', () => {
162
187
  const block = makeTemplateBlock({
163
- template: 'titleBlock',
188
+ template: 'title',
164
189
  title: 'No Bottom',
165
190
  useBottomLayer: false,
166
191
  });
@@ -174,7 +199,7 @@ describe('getLayers', () => {
174
199
 
175
200
  it('respects useTopLayer: false opt-out', () => {
176
201
  const block = makeTemplateBlock({
177
- template: 'titleBlock',
202
+ template: 'title',
178
203
  title: 'No Top',
179
204
  useTopLayer: false,
180
205
  });
@@ -187,7 +212,7 @@ describe('getLayers', () => {
187
212
  });
188
213
 
189
214
  it('skips injection when no persistent layers are configured', () => {
190
- const block = makeTemplateBlock({ template: 'titleBlock', title: 'No Persistent' });
215
+ const block = makeTemplateBlock({ template: 'title', title: 'No Persistent' });
191
216
  const withoutPersistent = getLayers(block, defaultContext);
192
217
  const withEmptyPersistent = getLayers(block, {
193
218
  ...defaultContext,