@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
@@ -0,0 +1,122 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ resolveIcon,
4
+ canonicalIconToken,
5
+ looksLikeIconToken,
6
+ suggestIcons,
7
+ } from '../icons/resolve';
8
+
9
+ describe('resolveIcon — bare tokens', () => {
10
+ it('resolves a name that is unique across families', () => {
11
+ // `github` only exists in fa-brands.
12
+ const icon = resolveIcon('github');
13
+ expect(icon).not.toBeNull();
14
+ expect(icon!.family).toBe('brands');
15
+ expect(icon!.name).toBe('github');
16
+ });
17
+
18
+ it('returns null for a name that collides across families', () => {
19
+ // `user` ships in both solid and regular — bare form is ambiguous.
20
+ const icon = resolveIcon('user');
21
+ expect(icon).toBeNull();
22
+ });
23
+
24
+ it('returns null for unknown names', () => {
25
+ expect(resolveIcon('totallyMadeUp_____Name')).toBeNull();
26
+ });
27
+ });
28
+
29
+ describe('resolveIcon — qualified tokens', () => {
30
+ it('resolves an ambiguous name with the fa-solid: prefix', () => {
31
+ const icon = resolveIcon('fa-solid:user');
32
+ expect(icon).not.toBeNull();
33
+ expect(icon!.family).toBe('solid');
34
+ expect(icon!.name).toBe('user');
35
+ });
36
+
37
+ it('resolves the same name in the other family', () => {
38
+ const icon = resolveIcon('fa-regular:user');
39
+ expect(icon).not.toBeNull();
40
+ expect(icon!.family).toBe('regular');
41
+ });
42
+
43
+ it('accepts short family prefixes too', () => {
44
+ const icon = resolveIcon('brands:github');
45
+ expect(icon).not.toBeNull();
46
+ expect(icon!.family).toBe('brands');
47
+ });
48
+
49
+ it('returns null for an unknown family prefix', () => {
50
+ expect(resolveIcon('fa-foo:github')).toBeNull();
51
+ });
52
+
53
+ it('returns null for a qualified token whose name does not exist in that family', () => {
54
+ expect(resolveIcon('fa-brands:user')).toBeNull();
55
+ });
56
+ });
57
+
58
+ describe('canonicalIconToken', () => {
59
+ it('emits the bare form for unique names', () => {
60
+ const icon = resolveIcon('github')!;
61
+ expect(canonicalIconToken(icon)).toBe('github');
62
+ });
63
+
64
+ it('emits the qualified form for ambiguous names', () => {
65
+ const icon = resolveIcon('fa-solid:user')!;
66
+ expect(canonicalIconToken(icon)).toBe('fa-solid:user');
67
+ });
68
+ });
69
+
70
+ describe('suggestIcons', () => {
71
+ it('ranks "starts with" matches above "contains" matches', () => {
72
+ const results = suggestIcons('git');
73
+ // `github` (brands) starts with "git" → score 0; `digital-tachograph`
74
+ // contains "git" → score 1. The first must outrank the latter.
75
+ const githubIdx = results.findIndex((r) => r.entry.name === 'github');
76
+ const containsIdx = results.findIndex(
77
+ (r) => r.entry.name.includes('git') && !r.entry.name.startsWith('git'),
78
+ );
79
+ expect(githubIdx).toBeGreaterThanOrEqual(0);
80
+ if (containsIdx >= 0) {
81
+ expect(githubIdx).toBeLessThan(containsIdx);
82
+ }
83
+ });
84
+
85
+ it('returns canonical tokens (bare when unique, qualified otherwise)', () => {
86
+ const results = suggestIcons('user');
87
+ const userTokens = results.filter((r) => r.entry.name === 'user').map((r) => r.token);
88
+ // `user` is ambiguous — each match must be qualified.
89
+ expect(userTokens.every((t) => t.startsWith('fa-'))).toBe(true);
90
+ });
91
+
92
+ it('matches by keyword too', () => {
93
+ const results = suggestIcons('octocat'); // a github keyword
94
+ expect(results.some((r) => r.entry.name === 'github')).toBe(true);
95
+ });
96
+
97
+ it('honors the limit parameter', () => {
98
+ expect(suggestIcons('e', 5)).toHaveLength(5);
99
+ });
100
+
101
+ it('returns nothing useful for whitespace-only queries', () => {
102
+ // Empty / whitespace queries return the first N icons (score 3
103
+ // bucket) — useful as a "browse the catalog" affordance in pickers.
104
+ const results = suggestIcons(' ', 10);
105
+ expect(results).toHaveLength(10);
106
+ expect(results.every((r) => r.score === 3)).toBe(true);
107
+ });
108
+ });
109
+
110
+ describe('looksLikeIconToken', () => {
111
+ it('accepts alphanumeric tokens with hyphens, underscores, and one colon', () => {
112
+ expect(looksLikeIconToken('github')).toBe(true);
113
+ expect(looksLikeIconToken('fa-solid:user')).toBe(true);
114
+ expect(looksLikeIconToken('face-smile_wink')).toBe(true);
115
+ });
116
+
117
+ it('rejects whitespace and special characters', () => {
118
+ expect(looksLikeIconToken('hello world')).toBe(false);
119
+ expect(looksLikeIconToken('with/slash')).toBe(false);
120
+ expect(looksLikeIconToken('with$dollar')).toBe(false);
121
+ });
122
+ });
@@ -0,0 +1,74 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ createEmptyImageEditDoc,
4
+ addLayer,
5
+ removeLayer,
6
+ reorderLayer,
7
+ updateLayer,
8
+ setCanvas,
9
+ } from '../imageEdit/state';
10
+ import type { ImageEditLayer } from '../schemas/ImageEditDoc';
11
+
12
+ function textLayer(id: string, text = 'hi'): ImageEditLayer {
13
+ return {
14
+ id,
15
+ type: 'text',
16
+ position: { x: 0, y: 0, width: 100, height: 30 },
17
+ content: { text, style: { fontSize: 16, color: '#000' } },
18
+ };
19
+ }
20
+
21
+ describe('imageEdit/state helpers', () => {
22
+ it('createEmptyImageEditDoc seeds canvas + meta', () => {
23
+ const doc = createEmptyImageEditDoc(800, 600, { sourcePath: 'src.png' });
24
+ expect(doc.version).toBe(1);
25
+ expect(doc.canvas).toEqual({ width: 800, height: 600, background: 'transparent' });
26
+ expect(doc.layers).toEqual([]);
27
+ expect(doc.meta?.sourcePath).toBe('src.png');
28
+ expect(doc.meta?.createdAt).toBeDefined();
29
+ expect(doc.meta?.updatedAt).toBeDefined();
30
+ });
31
+
32
+ it('addLayer appends and assigns id when missing', () => {
33
+ let doc = createEmptyImageEditDoc(100, 100);
34
+ doc = addLayer(doc, textLayer('a'));
35
+ doc = addLayer(doc, { ...textLayer(''), id: '' });
36
+ expect(doc.layers).toHaveLength(2);
37
+ expect(doc.layers[0]!.id).toBe('a');
38
+ expect(doc.layers[1]!.id).toMatch(/^layer-/);
39
+ });
40
+
41
+ it('removeLayer drops by id, no-op when missing', () => {
42
+ let doc = addLayer(createEmptyImageEditDoc(100, 100), textLayer('a'));
43
+ doc = addLayer(doc, textLayer('b'));
44
+ const after = removeLayer(doc, 'a');
45
+ expect(after.layers.map((l) => l.id)).toEqual(['b']);
46
+ const noop = removeLayer(after, 'missing');
47
+ expect(noop).toBe(after);
48
+ });
49
+
50
+ it('reorderLayer moves and clamps index', () => {
51
+ let doc = createEmptyImageEditDoc(100, 100);
52
+ for (const id of ['a', 'b', 'c']) doc = addLayer(doc, textLayer(id));
53
+ const moved = reorderLayer(doc, 'a', 99);
54
+ expect(moved.layers.map((l) => l.id)).toEqual(['b', 'c', 'a']);
55
+ const moved2 = reorderLayer(moved, 'a', -10);
56
+ expect(moved2.layers.map((l) => l.id)).toEqual(['a', 'b', 'c']);
57
+ });
58
+
59
+ it('updateLayer shallow-merges by id', () => {
60
+ let doc = addLayer(createEmptyImageEditDoc(100, 100), textLayer('a'));
61
+ doc = updateLayer(doc, 'a', { name: 'Title', opacity: 0.5 });
62
+ expect(doc.layers[0]!.name).toBe('Title');
63
+ expect(doc.layers[0]!.opacity).toBe(0.5);
64
+ });
65
+
66
+ it('setCanvas replaces canvas', () => {
67
+ const doc = setCanvas(createEmptyImageEditDoc(100, 100), {
68
+ width: 200,
69
+ height: 300,
70
+ background: '#fff',
71
+ });
72
+ expect(doc.canvas).toEqual({ width: 200, height: 300, background: '#fff' });
73
+ });
74
+ });
@@ -0,0 +1,169 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { MemoryContentContainer } from '../storage/ContentContainer';
3
+ import { scopeContainer } from '../storage/ScopedContentContainer';
4
+ import { createEmptyImageEditDoc, addLayer } from '../imageEdit/state';
5
+ import { writeImageEditDoc, readImageEditDoc } from '../imageEdit/persistence';
6
+ import {
7
+ saveImageEditVersion,
8
+ listImageEditVersions,
9
+ readImageEditVersion,
10
+ revertToImageEditVersion,
11
+ pruneImageEditVersions,
12
+ } from '../imageEdit/versions';
13
+ import { ImageEditVersionManager } from '../imageEdit/ImageEditVersionManager';
14
+ import type { ImageEditLayer } from '../schemas/ImageEditDoc';
15
+
16
+ const text = (id: string): ImageEditLayer => ({
17
+ id,
18
+ type: 'text',
19
+ position: { x: 0, y: 0 },
20
+ content: { text: id, style: { fontSize: 16, color: '#000' } },
21
+ });
22
+
23
+ describe('imageEdit/persistence', () => {
24
+ it('round-trips state.json', async () => {
25
+ const sidecar = scopeContainer(new MemoryContentContainer(), 'image_files');
26
+ const doc = addLayer(createEmptyImageEditDoc(640, 480), text('a'));
27
+ await writeImageEditDoc(sidecar, doc);
28
+ const read = await readImageEditDoc(sidecar);
29
+ expect(read?.canvas.width).toBe(640);
30
+ expect(read?.layers).toHaveLength(1);
31
+ expect(read?.layers[0]!.id).toBe('a');
32
+ });
33
+
34
+ it('returns null when state.json is missing', async () => {
35
+ const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
36
+ expect(await readImageEditDoc(sidecar)).toBeNull();
37
+ });
38
+
39
+ it('rejects unsupported schema version', async () => {
40
+ const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
41
+ await sidecar.writeFile(
42
+ 'state.json',
43
+ new TextEncoder().encode(
44
+ JSON.stringify({ version: 2, canvas: { width: 1, height: 1 }, layers: [] }),
45
+ ),
46
+ );
47
+ await expect(readImageEditDoc(sidecar)).rejects.toThrow(/unsupported schema version/);
48
+ });
49
+ });
50
+
51
+ describe('imageEdit/versions', () => {
52
+ let parent: MemoryContentContainer;
53
+ let sidecar: ReturnType<typeof scopeContainer>;
54
+
55
+ beforeEach(() => {
56
+ parent = new MemoryContentContainer();
57
+ sidecar = scopeContainer(parent, 'image_files');
58
+ });
59
+
60
+ it('saves a snapshot when state.json exists', async () => {
61
+ const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
62
+ await writeImageEditDoc(sidecar, doc);
63
+ const result = await saveImageEditVersion(sidecar, { now: new Date('2026-04-01T10:00:00Z') });
64
+ expect(result.saved).toBe(true);
65
+ expect(result.version?.path).toMatch(/^\.versions\/state\.\d{8}T\d{6}Z\.json$/);
66
+ // snapshot is inside the sidecar, visible to the parent under the prefix
67
+ expect(await parent.exists(`image_files/${result.version!.path}`)).toBe(true);
68
+ });
69
+
70
+ it('returns no-state when sidecar is empty', async () => {
71
+ const result = await saveImageEditVersion(sidecar);
72
+ expect(result).toEqual({ saved: false, version: null, reason: 'no-state' });
73
+ });
74
+
75
+ it('skips saving when content is unchanged', async () => {
76
+ const doc = createEmptyImageEditDoc(100, 100, { now: new Date('2026-01-01') });
77
+ await writeImageEditDoc(sidecar, doc);
78
+ const first = await saveImageEditVersion(sidecar, {
79
+ doc,
80
+ now: new Date('2026-04-01T10:00:00Z'),
81
+ });
82
+ expect(first.saved).toBe(true);
83
+ const second = await saveImageEditVersion(sidecar, {
84
+ doc,
85
+ now: new Date('2026-04-01T10:01:00Z'),
86
+ });
87
+ expect(second).toEqual({ saved: false, version: null, reason: 'unchanged' });
88
+ });
89
+
90
+ it('appends a collision suffix when saves land in the same second', async () => {
91
+ const same = new Date('2026-04-01T10:00:00Z');
92
+ const docA = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
93
+ const docB = addLayer(createEmptyImageEditDoc(100, 100), text('b'));
94
+ const r1 = await saveImageEditVersion(sidecar, { doc: docA, now: same });
95
+ const r2 = await saveImageEditVersion(sidecar, { doc: docB, now: same });
96
+ expect(r1.saved).toBe(true);
97
+ expect(r2.saved).toBe(true);
98
+ expect(r1.version!.path).not.toBe(r2.version!.path);
99
+ expect(r2.version!.path).toMatch(/-2\.json$/);
100
+ });
101
+
102
+ it('lists versions newest-first', async () => {
103
+ await saveImageEditVersion(sidecar, {
104
+ doc: addLayer(createEmptyImageEditDoc(100, 100), text('a')),
105
+ now: new Date('2026-01-01T00:00:00Z'),
106
+ });
107
+ await saveImageEditVersion(sidecar, {
108
+ doc: addLayer(createEmptyImageEditDoc(100, 100), text('b')),
109
+ now: new Date('2026-02-01T00:00:00Z'),
110
+ });
111
+ const versions = await listImageEditVersions(sidecar);
112
+ expect(versions).toHaveLength(2);
113
+ expect(versions[0]!.timestamp.getUTCFullYear()).toBe(2026);
114
+ expect(versions[0]!.timestamp.getUTCMonth()).toBe(1); // Feb
115
+ });
116
+
117
+ it('readImageEditVersion returns the parsed snapshot', async () => {
118
+ const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
119
+ const result = await saveImageEditVersion(sidecar, {
120
+ doc,
121
+ now: new Date('2026-03-01T00:00:00Z'),
122
+ });
123
+ const read = await readImageEditVersion(sidecar, result.version!);
124
+ expect(read?.layers[0]!.id).toBe('a');
125
+ });
126
+
127
+ it('revertToImageEditVersion restores state.json and snapshots current first', async () => {
128
+ const docA = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
129
+ await writeImageEditDoc(sidecar, docA);
130
+ const v1 = await saveImageEditVersion(sidecar, {
131
+ doc: docA,
132
+ now: new Date('2026-01-01T00:00:00Z'),
133
+ });
134
+
135
+ const docB = addLayer(createEmptyImageEditDoc(100, 100), text('b'));
136
+ await writeImageEditDoc(sidecar, docB);
137
+ const result = await revertToImageEditVersion(sidecar, v1.version!);
138
+
139
+ expect(result.reverted).toBe(true);
140
+ expect(result.snapshotted).not.toBeNull();
141
+ const current = await readImageEditDoc(sidecar);
142
+ expect(current?.layers[0]!.id).toBe('a');
143
+ });
144
+
145
+ it('pruneImageEditVersions keep-last-n drops older snapshots', async () => {
146
+ for (let i = 0; i < 5; i++) {
147
+ await saveImageEditVersion(sidecar, {
148
+ doc: addLayer(createEmptyImageEditDoc(100, 100), text(`v${i}`)),
149
+ now: new Date(`2026-01-0${i + 1}T00:00:00Z`),
150
+ });
151
+ }
152
+ const deleted = await pruneImageEditVersions(sidecar, { type: 'keep-last-n', n: 2 });
153
+ expect(deleted).toHaveLength(3);
154
+ const remaining = await listImageEditVersions(sidecar);
155
+ expect(remaining).toHaveLength(2);
156
+ });
157
+ });
158
+
159
+ describe('ImageEditVersionManager', () => {
160
+ it('mirrors operations against the captured container', async () => {
161
+ const sidecar = scopeContainer(new MemoryContentContainer(), 'image_files');
162
+ const mgr = new ImageEditVersionManager(sidecar);
163
+ const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
164
+ await writeImageEditDoc(sidecar, doc);
165
+ const r = await mgr.saveVersion({ now: new Date('2026-04-01T00:00:00Z') });
166
+ expect(r.saved).toBe(true);
167
+ expect((await mgr.listVersions())[0]!.path).toBe(r.version!.path);
168
+ });
169
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseMarkdown } from '../markdown/parse.js';
3
+ import { inferDocumentTitle } from '../markdown/utils.js';
4
+
5
+ describe('inferDocumentTitle', () => {
6
+ it('returns the frontmatter title when set', () => {
7
+ const doc = parseMarkdown('---\ntitle: My Doc\n---\n\n# Heading\n');
8
+ expect(inferDocumentTitle(doc)).toBe('My Doc');
9
+ });
10
+
11
+ it('trims surrounding whitespace from frontmatter title', () => {
12
+ const doc = parseMarkdown('---\ntitle: " Spaced "\n---\n\n# Heading\n');
13
+ expect(inferDocumentTitle(doc)).toBe('Spaced');
14
+ });
15
+
16
+ it('falls back to the first H1 when frontmatter title is absent', () => {
17
+ const doc = parseMarkdown('# Welcome\n\n## Details');
18
+ expect(inferDocumentTitle(doc)).toBe('Welcome');
19
+ });
20
+
21
+ it('falls back to the first H2 when no H1 is present', () => {
22
+ const doc = parseMarkdown('## Section\n\n### Detail');
23
+ expect(inferDocumentTitle(doc)).toBe('Section');
24
+ });
25
+
26
+ it('prefers the shallowest heading regardless of source order', () => {
27
+ const doc = parseMarkdown('## Earlier H2\n\n# Real Title\n\n### Nested');
28
+ expect(inferDocumentTitle(doc)).toBe('Real Title');
29
+ });
30
+
31
+ it('skips empty frontmatter title and falls back to headings', () => {
32
+ const doc = parseMarkdown('---\ntitle: ""\n---\n\n# Real\n');
33
+ expect(inferDocumentTitle(doc)).toBe('Real');
34
+ });
35
+
36
+ it('returns undefined when there is no frontmatter and no heading', () => {
37
+ const doc = parseMarkdown('Just a paragraph.\n\nAnother one.');
38
+ expect(inferDocumentTitle(doc)).toBeUndefined();
39
+ });
40
+
41
+ it('strips inline formatting from heading text', () => {
42
+ const doc = parseMarkdown('# **Bold** and *italic*');
43
+ expect(inferDocumentTitle(doc)).toBe('Bold and italic');
44
+ });
45
+
46
+ it('skips headings that contain only whitespace', () => {
47
+ const doc = parseMarkdown('# \n\n## Real Heading');
48
+ expect(inferDocumentTitle(doc)).toBe('Real Heading');
49
+ });
50
+ });
@@ -0,0 +1,86 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { chooseControl, primaryType, arrayItemKind } from '../jsonForm/index.js';
3
+
4
+ describe('chooseControl', () => {
5
+ it('honors explicit squisq.control', () => {
6
+ expect(chooseControl({ type: 'string', squisq: { control: 'radio' } })).toBe('radio');
7
+ });
8
+
9
+ it('maps format=color', () => {
10
+ expect(chooseControl({ type: 'string', format: 'color' })).toBe('color');
11
+ });
12
+ it('maps format=date / time / date-time / markdown / textarea', () => {
13
+ expect(chooseControl({ type: 'string', format: 'date' })).toBe('date');
14
+ expect(chooseControl({ type: 'string', format: 'time' })).toBe('time');
15
+ expect(chooseControl({ type: 'string', format: 'date-time' })).toBe('datetime');
16
+ expect(chooseControl({ type: 'string', format: 'markdown' })).toBe('richtext');
17
+ expect(chooseControl({ type: 'string', format: 'textarea' })).toBe('multiline');
18
+ });
19
+
20
+ it('uses segmented for short enums (≤4)', () => {
21
+ expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c'] })).toBe('segmented');
22
+ expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c', 'd'] })).toBe('segmented');
23
+ });
24
+ it('uses combobox for long enums (>4)', () => {
25
+ expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c', 'd', 'e'] })).toBe('combobox');
26
+ });
27
+
28
+ it('arrays of objects → card-stack', () => {
29
+ expect(chooseControl({ type: 'array', items: { type: 'object', properties: {} } })).toBe(
30
+ 'card-stack',
31
+ );
32
+ });
33
+ it('arrays of primitives → chip-bin', () => {
34
+ expect(chooseControl({ type: 'array', items: { type: 'string' } })).toBe('chip-bin');
35
+ });
36
+
37
+ it('booleans → toggle', () => {
38
+ expect(chooseControl({ type: 'boolean' })).toBe('toggle');
39
+ });
40
+
41
+ it('numbers with both min and max → slider', () => {
42
+ expect(chooseControl({ type: 'number', minimum: 0, maximum: 100 })).toBe('slider');
43
+ });
44
+ it('numbers without bounded range → stepper', () => {
45
+ expect(chooseControl({ type: 'number' })).toBe('stepper');
46
+ expect(chooseControl({ type: 'integer', minimum: 0 })).toBe('stepper');
47
+ });
48
+
49
+ it('strings with maxLength > 200 → multiline', () => {
50
+ expect(chooseControl({ type: 'string', maxLength: 500 })).toBe('multiline');
51
+ });
52
+ it('plain strings → text', () => {
53
+ expect(chooseControl({ type: 'string' })).toBe('text');
54
+ });
55
+
56
+ it('objects → group', () => {
57
+ expect(chooseControl({ type: 'object', properties: {} })).toBe('group');
58
+ });
59
+
60
+ it('oneOf / anyOf → tabs', () => {
61
+ expect(chooseControl({ oneOf: [{ type: 'string' }, { type: 'number' }] })).toBe('tabs');
62
+ expect(chooseControl({ anyOf: [{ type: 'string' }, { type: 'number' }] })).toBe('tabs');
63
+ });
64
+ });
65
+
66
+ describe('primaryType', () => {
67
+ it('returns the lone type', () => {
68
+ expect(primaryType({ type: 'string' })).toBe('string');
69
+ });
70
+ it('skips null in nullable shorthand', () => {
71
+ expect(primaryType({ type: ['string', 'null'] })).toBe('string');
72
+ expect(primaryType({ type: ['null', 'integer'] })).toBe('integer');
73
+ });
74
+ });
75
+
76
+ describe('arrayItemKind', () => {
77
+ it('detects object items', () => {
78
+ expect(arrayItemKind({ type: 'array', items: { type: 'object' } })).toBe('object');
79
+ });
80
+ it('detects primitive items', () => {
81
+ expect(arrayItemKind({ type: 'array', items: { type: 'string' } })).toBe('primitive');
82
+ });
83
+ it('treats missing items as primitive', () => {
84
+ expect(arrayItemKind({ type: 'array' })).toBe('primitive');
85
+ });
86
+ });
@@ -0,0 +1,59 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { evaluateWhen, resolveFlag } from '../jsonForm/index.js';
3
+
4
+ const data = {
5
+ user: { role: 'admin', name: 'Alex' },
6
+ count: 3,
7
+ active: true,
8
+ tags: ['a', 'b'],
9
+ };
10
+
11
+ describe('evaluateWhen', () => {
12
+ it('equals — primitives', () => {
13
+ expect(evaluateWhen({ field: 'user.role', equals: 'admin' }, data)).toBe(true);
14
+ expect(evaluateWhen({ field: 'user.role', equals: 'guest' }, data)).toBe(false);
15
+ });
16
+
17
+ it('equals — arrays via deep equality', () => {
18
+ expect(evaluateWhen({ field: 'tags', equals: ['a', 'b'] }, data)).toBe(true);
19
+ expect(evaluateWhen({ field: 'tags', equals: ['a'] }, data)).toBe(false);
20
+ });
21
+
22
+ it('oneOf', () => {
23
+ expect(evaluateWhen({ field: 'count', oneOf: [1, 2, 3] }, data)).toBe(true);
24
+ expect(evaluateWhen({ field: 'count', oneOf: [10, 20] }, data)).toBe(false);
25
+ });
26
+
27
+ it('matches regex', () => {
28
+ expect(evaluateWhen({ field: 'user.name', matches: '^Al' }, data)).toBe(true);
29
+ expect(evaluateWhen({ field: 'user.name', matches: '^Bo' }, data)).toBe(false);
30
+ });
31
+
32
+ it('matches: returns false for non-string targets', () => {
33
+ expect(evaluateWhen({ field: 'count', matches: '\\d' }, data)).toBe(false);
34
+ });
35
+
36
+ it('truthy', () => {
37
+ expect(evaluateWhen({ field: 'active', truthy: true }, data)).toBe(true);
38
+ expect(evaluateWhen({ field: 'active', truthy: false }, data)).toBe(false);
39
+ expect(evaluateWhen({ field: 'missing', truthy: false }, data)).toBe(true);
40
+ });
41
+
42
+ it('default behavior with no operator: field is defined', () => {
43
+ expect(evaluateWhen({ field: 'count' }, data)).toBe(true);
44
+ expect(evaluateWhen({ field: 'missing' }, data)).toBe(false);
45
+ });
46
+ });
47
+
48
+ describe('resolveFlag', () => {
49
+ it('passes through literal booleans', () => {
50
+ expect(resolveFlag(true, data)).toBe(true);
51
+ expect(resolveFlag(false, data)).toBe(false);
52
+ });
53
+ it('returns false for undefined', () => {
54
+ expect(resolveFlag(undefined, data)).toBe(false);
55
+ });
56
+ it('evaluates SquisqWhen', () => {
57
+ expect(resolveFlag({ field: 'user.role', equals: 'admin' }, data)).toBe(true);
58
+ });
59
+ });
@@ -0,0 +1,25 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { inferSchema } from '../jsonForm/index.js';
3
+
4
+ describe('inferSchema', () => {
5
+ it('infers an object schema from a sample', () => {
6
+ const schema = inferSchema({ name: 'Alex', age: 30, active: true });
7
+ expect(schema.type).toBe('object');
8
+ expect(schema.properties?.name?.type).toBe('string');
9
+ expect(schema.properties?.age?.type).toBe('integer');
10
+ expect(schema.properties?.active?.type).toBe('boolean');
11
+ });
12
+
13
+ it('infers array item types', () => {
14
+ const schema = inferSchema({ tags: ['a', 'b', 'c'] });
15
+ const items = schema.properties?.tags?.items;
16
+ const first = Array.isArray(items) ? items[0] : items;
17
+ expect(first?.type).toBe('string');
18
+ });
19
+
20
+ it('merges multiple samples', () => {
21
+ const schema = inferSchema({ name: 'Alex' }, { additionalSamples: [{ name: 'Bo', age: 5 }] });
22
+ expect(schema.properties?.name?.type).toBe('string');
23
+ expect(schema.properties?.age?.type).toBe('integer');
24
+ });
25
+ });