@knpkv/confluence-to-markdown 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +58 -14
  3. package/dist/AdfPlaceholders.d.ts +42 -0
  4. package/dist/AdfPlaceholders.d.ts.map +1 -0
  5. package/dist/AdfPlaceholders.js +547 -0
  6. package/dist/AdfPlaceholders.js.map +1 -0
  7. package/dist/AdfSchemaValidator.d.ts +37 -0
  8. package/dist/AdfSchemaValidator.d.ts.map +1 -0
  9. package/dist/AdfSchemaValidator.js +37 -0
  10. package/dist/AdfSchemaValidator.js.map +1 -0
  11. package/dist/AdfWalker.d.ts +39 -0
  12. package/dist/AdfWalker.d.ts.map +1 -0
  13. package/dist/AdfWalker.js +527 -0
  14. package/dist/AdfWalker.js.map +1 -0
  15. package/dist/AtlaskitTransformers.d.ts +35 -0
  16. package/dist/AtlaskitTransformers.d.ts.map +1 -0
  17. package/dist/AtlaskitTransformers.js +48 -0
  18. package/dist/AtlaskitTransformers.js.map +1 -0
  19. package/dist/Brand.d.ts +6 -6
  20. package/dist/Brand.d.ts.map +1 -1
  21. package/dist/Brand.js +8 -6
  22. package/dist/Brand.js.map +1 -1
  23. package/dist/ConfluenceAuth.d.ts +4 -4
  24. package/dist/ConfluenceAuth.d.ts.map +1 -1
  25. package/dist/ConfluenceAuth.js +15 -27
  26. package/dist/ConfluenceAuth.js.map +1 -1
  27. package/dist/ConfluenceClient.d.ts +4 -4
  28. package/dist/ConfluenceClient.d.ts.map +1 -1
  29. package/dist/ConfluenceClient.js +21 -14
  30. package/dist/ConfluenceClient.js.map +1 -1
  31. package/dist/ConfluenceConfig.d.ts +3 -3
  32. package/dist/ConfluenceConfig.d.ts.map +1 -1
  33. package/dist/ConfluenceConfig.js +13 -11
  34. package/dist/ConfluenceConfig.js.map +1 -1
  35. package/dist/ConfluenceError.d.ts +56 -4
  36. package/dist/ConfluenceError.d.ts.map +1 -1
  37. package/dist/ConfluenceError.js +30 -1
  38. package/dist/ConfluenceError.js.map +1 -1
  39. package/dist/GitService.d.ts +11 -3
  40. package/dist/GitService.d.ts.map +1 -1
  41. package/dist/GitService.js +19 -27
  42. package/dist/GitService.js.map +1 -1
  43. package/dist/LocalFileSystem.d.ts +3 -3
  44. package/dist/LocalFileSystem.d.ts.map +1 -1
  45. package/dist/LocalFileSystem.js +6 -6
  46. package/dist/LocalFileSystem.js.map +1 -1
  47. package/dist/MarkdownConverter.d.ts +16 -65
  48. package/dist/MarkdownConverter.d.ts.map +1 -1
  49. package/dist/MarkdownConverter.js +64 -85
  50. package/dist/MarkdownConverter.js.map +1 -1
  51. package/dist/Schemas.d.ts +128 -141
  52. package/dist/Schemas.d.ts.map +1 -1
  53. package/dist/Schemas.js +21 -23
  54. package/dist/Schemas.js.map +1 -1
  55. package/dist/SyncEngine.d.ts +8 -5
  56. package/dist/SyncEngine.d.ts.map +1 -1
  57. package/dist/SyncEngine.js +189 -113
  58. package/dist/SyncEngine.js.map +1 -1
  59. package/dist/bin.js +23 -35
  60. package/dist/bin.js.map +1 -1
  61. package/dist/commands/auth.d.ts +2 -14
  62. package/dist/commands/auth.d.ts.map +1 -1
  63. package/dist/commands/auth.js +11 -16
  64. package/dist/commands/auth.js.map +1 -1
  65. package/dist/commands/clone.d.ts +4 -6
  66. package/dist/commands/clone.d.ts.map +1 -1
  67. package/dist/commands/clone.js +34 -32
  68. package/dist/commands/clone.js.map +1 -1
  69. package/dist/commands/delete.d.ts +2 -10
  70. package/dist/commands/delete.d.ts.map +1 -1
  71. package/dist/commands/delete.js +5 -4
  72. package/dist/commands/delete.js.map +1 -1
  73. package/dist/commands/errorHandler.d.ts +2 -1
  74. package/dist/commands/errorHandler.d.ts.map +1 -1
  75. package/dist/commands/errorHandler.js +22 -15
  76. package/dist/commands/errorHandler.js.map +1 -1
  77. package/dist/commands/fetch.d.ts +27 -0
  78. package/dist/commands/fetch.d.ts.map +1 -0
  79. package/dist/commands/fetch.js +48 -0
  80. package/dist/commands/fetch.js.map +1 -0
  81. package/dist/commands/git.d.ts +7 -10
  82. package/dist/commands/git.d.ts.map +1 -1
  83. package/dist/commands/git.js +6 -6
  84. package/dist/commands/git.js.map +1 -1
  85. package/dist/commands/index.d.ts +1 -0
  86. package/dist/commands/index.d.ts.map +1 -1
  87. package/dist/commands/index.js +1 -0
  88. package/dist/commands/index.js.map +1 -1
  89. package/dist/commands/layers.d.ts +10 -9
  90. package/dist/commands/layers.d.ts.map +1 -1
  91. package/dist/commands/layers.js +41 -30
  92. package/dist/commands/layers.js.map +1 -1
  93. package/dist/commands/new.d.ts +2 -6
  94. package/dist/commands/new.d.ts.map +1 -1
  95. package/dist/commands/new.js +5 -4
  96. package/dist/commands/new.js.map +1 -1
  97. package/dist/commands/pageInput.d.ts +19 -0
  98. package/dist/commands/pageInput.d.ts.map +1 -0
  99. package/dist/commands/pageInput.js +68 -0
  100. package/dist/commands/pageInput.js.map +1 -0
  101. package/dist/commands/root.d.ts +8 -0
  102. package/dist/commands/root.d.ts.map +1 -0
  103. package/dist/commands/root.js +29 -0
  104. package/dist/commands/root.js.map +1 -0
  105. package/dist/commands/sync.d.ts +6 -9
  106. package/dist/commands/sync.d.ts.map +1 -1
  107. package/dist/commands/sync.js +5 -6
  108. package/dist/commands/sync.js.map +1 -1
  109. package/dist/index.d.ts +3 -8
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +2 -13
  112. package/dist/index.js.map +1 -1
  113. package/dist/internal/NodeLayers.d.ts.map +1 -1
  114. package/dist/internal/NodeLayers.js +1 -2
  115. package/dist/internal/NodeLayers.js.map +1 -1
  116. package/dist/internal/adfMetadata.d.ts +30 -0
  117. package/dist/internal/adfMetadata.d.ts.map +1 -0
  118. package/dist/internal/adfMetadata.js +126 -0
  119. package/dist/internal/adfMetadata.js.map +1 -0
  120. package/dist/internal/cleanMarkdown.d.ts +5 -0
  121. package/dist/internal/cleanMarkdown.d.ts.map +1 -0
  122. package/dist/internal/cleanMarkdown.js +13 -0
  123. package/dist/internal/cleanMarkdown.js.map +1 -0
  124. package/dist/internal/frontmatter.d.ts.map +1 -1
  125. package/dist/internal/frontmatter.js +41 -8
  126. package/dist/internal/frontmatter.js.map +1 -1
  127. package/dist/internal/gitCommands.d.ts +9 -3
  128. package/dist/internal/gitCommands.d.ts.map +1 -1
  129. package/dist/internal/gitCommands.js +18 -9
  130. package/dist/internal/gitCommands.js.map +1 -1
  131. package/dist/internal/hashUtils.d.ts +1 -1
  132. package/dist/internal/hashUtils.d.ts.map +1 -1
  133. package/dist/internal/hashUtils.js +1 -1
  134. package/dist/internal/hashUtils.js.map +1 -1
  135. package/dist/internal/oauthServer.d.ts +10 -5
  136. package/dist/internal/oauthServer.d.ts.map +1 -1
  137. package/dist/internal/oauthServer.js +19 -40
  138. package/dist/internal/oauthServer.js.map +1 -1
  139. package/dist/internal/pathUtils.d.ts +1 -1
  140. package/dist/internal/pathUtils.d.ts.map +1 -1
  141. package/dist/internal/pathUtils.js +1 -1
  142. package/dist/internal/pathUtils.js.map +1 -1
  143. package/dist/internal/process.d.ts +15 -0
  144. package/dist/internal/process.d.ts.map +1 -0
  145. package/dist/internal/process.js +10 -0
  146. package/dist/internal/process.js.map +1 -0
  147. package/dist/internal/stdio.d.ts +6 -0
  148. package/dist/internal/stdio.d.ts.map +1 -0
  149. package/dist/internal/stdio.js +15 -0
  150. package/dist/internal/stdio.js.map +1 -0
  151. package/dist/internal/tokenStorage.d.ts +3 -13
  152. package/dist/internal/tokenStorage.d.ts.map +1 -1
  153. package/dist/internal/tokenStorage.js +26 -24
  154. package/dist/internal/tokenStorage.js.map +1 -1
  155. package/dist/internal/userCache.d.ts +1 -1
  156. package/dist/internal/userCache.d.ts.map +1 -1
  157. package/dist/internal/userCache.js +1 -1
  158. package/dist/internal/userCache.js.map +1 -1
  159. package/package.json +29 -20
  160. package/skills/confluence/SKILL.md +143 -0
  161. package/skills/confluence/agents/openai.yaml +4 -0
  162. package/src/AdfPlaceholders.ts +563 -0
  163. package/src/AdfSchemaValidator.ts +65 -0
  164. package/src/AdfWalker.ts +591 -0
  165. package/src/AtlaskitTransformers.ts +70 -0
  166. package/src/Brand.ts +11 -16
  167. package/src/ConfluenceAuth.ts +22 -30
  168. package/src/ConfluenceClient.ts +28 -24
  169. package/src/ConfluenceConfig.ts +14 -14
  170. package/src/ConfluenceError.ts +65 -3
  171. package/src/GitService.ts +39 -49
  172. package/src/LocalFileSystem.ts +7 -9
  173. package/src/MarkdownConverter.ts +108 -143
  174. package/src/Schemas.ts +17 -16
  175. package/src/SyncEngine.ts +272 -127
  176. package/src/atlaskit-adf-schema.d.ts +3 -0
  177. package/src/bin.ts +30 -56
  178. package/src/commands/auth.ts +21 -18
  179. package/src/commands/clone.ts +46 -38
  180. package/src/commands/delete.ts +5 -4
  181. package/src/commands/errorHandler.ts +25 -18
  182. package/src/commands/fetch.ts +90 -0
  183. package/src/commands/git.ts +6 -6
  184. package/src/commands/index.ts +1 -0
  185. package/src/commands/layers.ts +64 -37
  186. package/src/commands/new.ts +5 -4
  187. package/src/commands/pageInput.ts +103 -0
  188. package/src/commands/root.ts +59 -0
  189. package/src/commands/sync.ts +7 -6
  190. package/src/index.ts +3 -18
  191. package/src/internal/NodeLayers.ts +1 -2
  192. package/src/internal/adfMetadata.ts +145 -0
  193. package/src/internal/cleanMarkdown.ts +15 -0
  194. package/src/internal/frontmatter.ts +45 -8
  195. package/src/internal/gitCommands.ts +23 -17
  196. package/src/internal/hashUtils.ts +2 -2
  197. package/src/internal/oauthServer.ts +84 -105
  198. package/src/internal/pathUtils.ts +1 -1
  199. package/src/internal/process.ts +15 -0
  200. package/src/internal/stdio.ts +22 -0
  201. package/src/internal/tokenStorage.ts +39 -29
  202. package/src/internal/userCache.ts +2 -2
  203. package/test/AdfPlaceholders.test.ts +508 -0
  204. package/test/AdfSchemaValidator.test.ts +34 -0
  205. package/test/AdfWalker.test.ts +676 -0
  206. package/test/AtlaskitTransformers.test.ts +25 -0
  207. package/test/Brand.test.ts +11 -11
  208. package/test/GitService.test.ts +6 -2
  209. package/test/MarkdownConverter.test.ts +121 -105
  210. package/test/RoundTrip.test.ts +521 -0
  211. package/test/Schemas.test.ts +40 -40
  212. package/test/adfMetadata.test.ts +110 -0
  213. package/test/cleanMarkdown.test.ts +36 -0
  214. package/test/commandHarness.test.ts +79 -0
  215. package/test/commandHarness.ts +147 -0
  216. package/test/fetch.test.ts +61 -0
  217. package/test/frontmatter.test.ts +41 -0
  218. package/test/integration.test.ts +569 -156
  219. package/test/layers.test.ts +12 -0
  220. package/test/oauthServer.test.ts +4 -5
  221. package/test/pageInput.test.ts +83 -0
  222. package/test/tokenStorage.test.ts +17 -17
  223. package/dist/SchemaConverterError.d.ts +0 -108
  224. package/dist/SchemaConverterError.d.ts.map +0 -1
  225. package/dist/SchemaConverterError.js +0 -84
  226. package/dist/SchemaConverterError.js.map +0 -1
  227. package/dist/ast/BlockNode.d.ts +0 -453
  228. package/dist/ast/BlockNode.d.ts.map +0 -1
  229. package/dist/ast/BlockNode.js +0 -310
  230. package/dist/ast/BlockNode.js.map +0 -1
  231. package/dist/ast/Document.d.ts +0 -216
  232. package/dist/ast/Document.d.ts.map +0 -1
  233. package/dist/ast/Document.js +0 -69
  234. package/dist/ast/Document.js.map +0 -1
  235. package/dist/ast/InlineNode.d.ts +0 -477
  236. package/dist/ast/InlineNode.d.ts.map +0 -1
  237. package/dist/ast/InlineNode.js +0 -263
  238. package/dist/ast/InlineNode.js.map +0 -1
  239. package/dist/ast/MacroNode.d.ts +0 -267
  240. package/dist/ast/MacroNode.d.ts.map +0 -1
  241. package/dist/ast/MacroNode.js +0 -164
  242. package/dist/ast/MacroNode.js.map +0 -1
  243. package/dist/ast/index.d.ts +0 -10
  244. package/dist/ast/index.d.ts.map +0 -1
  245. package/dist/ast/index.js +0 -14
  246. package/dist/ast/index.js.map +0 -1
  247. package/dist/parsers/ConfluenceParser.d.ts +0 -26
  248. package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
  249. package/dist/parsers/ConfluenceParser.js +0 -797
  250. package/dist/parsers/ConfluenceParser.js.map +0 -1
  251. package/dist/parsers/MarkdownParser.d.ts +0 -26
  252. package/dist/parsers/MarkdownParser.d.ts.map +0 -1
  253. package/dist/parsers/MarkdownParser.js +0 -982
  254. package/dist/parsers/MarkdownParser.js.map +0 -1
  255. package/dist/parsers/index.d.ts +0 -8
  256. package/dist/parsers/index.d.ts.map +0 -1
  257. package/dist/parsers/index.js +0 -8
  258. package/dist/parsers/index.js.map +0 -1
  259. package/dist/schemas/ConfluenceSchema.d.ts +0 -21
  260. package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
  261. package/dist/schemas/ConfluenceSchema.js +0 -38
  262. package/dist/schemas/ConfluenceSchema.js.map +0 -1
  263. package/dist/schemas/ConversionSchema.d.ts +0 -35
  264. package/dist/schemas/ConversionSchema.d.ts.map +0 -1
  265. package/dist/schemas/ConversionSchema.js +0 -208
  266. package/dist/schemas/ConversionSchema.js.map +0 -1
  267. package/dist/schemas/MarkdownSchema.d.ts +0 -21
  268. package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
  269. package/dist/schemas/MarkdownSchema.js +0 -38
  270. package/dist/schemas/MarkdownSchema.js.map +0 -1
  271. package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
  272. package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
  273. package/dist/schemas/hast/HastFromHtml.js +0 -107
  274. package/dist/schemas/hast/HastFromHtml.js.map +0 -1
  275. package/dist/schemas/hast/HastSchema.d.ts +0 -195
  276. package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
  277. package/dist/schemas/hast/HastSchema.js +0 -183
  278. package/dist/schemas/hast/HastSchema.js.map +0 -1
  279. package/dist/schemas/hast/index.d.ts +0 -9
  280. package/dist/schemas/hast/index.d.ts.map +0 -1
  281. package/dist/schemas/hast/index.js +0 -3
  282. package/dist/schemas/hast/index.js.map +0 -1
  283. package/dist/schemas/index.d.ts +0 -14
  284. package/dist/schemas/index.d.ts.map +0 -1
  285. package/dist/schemas/index.js +0 -16
  286. package/dist/schemas/index.js.map +0 -1
  287. package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
  288. package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
  289. package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
  290. package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
  291. package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
  292. package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
  293. package/dist/schemas/mdast/MdastSchema.js +0 -266
  294. package/dist/schemas/mdast/MdastSchema.js.map +0 -1
  295. package/dist/schemas/mdast/index.d.ts +0 -10
  296. package/dist/schemas/mdast/index.d.ts.map +0 -1
  297. package/dist/schemas/mdast/index.js +0 -4
  298. package/dist/schemas/mdast/index.js.map +0 -1
  299. package/dist/schemas/mdast/mdastToString.d.ts +0 -13
  300. package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
  301. package/dist/schemas/mdast/mdastToString.js +0 -85
  302. package/dist/schemas/mdast/mdastToString.js.map +0 -1
  303. package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
  304. package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
  305. package/dist/schemas/nodes/block/BlockSchema.js +0 -634
  306. package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
  307. package/dist/schemas/nodes/block/index.d.ts +0 -7
  308. package/dist/schemas/nodes/block/index.d.ts.map +0 -1
  309. package/dist/schemas/nodes/block/index.js +0 -7
  310. package/dist/schemas/nodes/block/index.js.map +0 -1
  311. package/dist/schemas/nodes/index.d.ts +0 -9
  312. package/dist/schemas/nodes/index.d.ts.map +0 -1
  313. package/dist/schemas/nodes/index.js +0 -12
  314. package/dist/schemas/nodes/index.js.map +0 -1
  315. package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
  316. package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
  317. package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
  318. package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
  319. package/dist/schemas/nodes/inline/index.d.ts +0 -7
  320. package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
  321. package/dist/schemas/nodes/inline/index.js +0 -7
  322. package/dist/schemas/nodes/inline/index.js.map +0 -1
  323. package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
  324. package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
  325. package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
  326. package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
  327. package/dist/schemas/nodes/macro/index.d.ts +0 -7
  328. package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
  329. package/dist/schemas/nodes/macro/index.js +0 -7
  330. package/dist/schemas/nodes/macro/index.js.map +0 -1
  331. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -24
  332. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
  333. package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -359
  334. package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
  335. package/dist/schemas/preprocessing/index.d.ts +0 -8
  336. package/dist/schemas/preprocessing/index.d.ts.map +0 -1
  337. package/dist/schemas/preprocessing/index.js +0 -2
  338. package/dist/schemas/preprocessing/index.js.map +0 -1
  339. package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
  340. package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
  341. package/dist/serializers/ConfluenceSerializer.js +0 -560
  342. package/dist/serializers/ConfluenceSerializer.js.map +0 -1
  343. package/dist/serializers/MarkdownSerializer.d.ts +0 -34
  344. package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
  345. package/dist/serializers/MarkdownSerializer.js +0 -395
  346. package/dist/serializers/MarkdownSerializer.js.map +0 -1
  347. package/dist/serializers/index.d.ts +0 -8
  348. package/dist/serializers/index.d.ts.map +0 -1
  349. package/dist/serializers/index.js +0 -8
  350. package/dist/serializers/index.js.map +0 -1
  351. package/src/SchemaConverterError.ts +0 -108
  352. package/src/ast/BlockNode.ts +0 -469
  353. package/src/ast/Document.ts +0 -90
  354. package/src/ast/InlineNode.ts +0 -323
  355. package/src/ast/MacroNode.ts +0 -245
  356. package/src/ast/index.ts +0 -83
  357. package/src/parsers/ConfluenceParser.ts +0 -956
  358. package/src/parsers/MarkdownParser.ts +0 -1338
  359. package/src/parsers/index.ts +0 -8
  360. package/src/schemas/ConfluenceSchema.ts +0 -56
  361. package/src/schemas/ConversionSchema.ts +0 -318
  362. package/src/schemas/MarkdownSchema.ts +0 -56
  363. package/src/schemas/hast/HastFromHtml.ts +0 -153
  364. package/src/schemas/hast/HastSchema.ts +0 -274
  365. package/src/schemas/hast/index.ts +0 -35
  366. package/src/schemas/index.ts +0 -20
  367. package/src/schemas/mdast/MdastFromMarkdown.ts +0 -118
  368. package/src/schemas/mdast/MdastSchema.ts +0 -566
  369. package/src/schemas/mdast/index.ts +0 -59
  370. package/src/schemas/mdast/mdastToString.ts +0 -102
  371. package/src/schemas/nodes/block/BlockSchema.ts +0 -773
  372. package/src/schemas/nodes/block/index.ts +0 -13
  373. package/src/schemas/nodes/index.ts +0 -20
  374. package/src/schemas/nodes/inline/InlineSchema.ts +0 -523
  375. package/src/schemas/nodes/inline/index.ts +0 -14
  376. package/src/schemas/nodes/macro/MacroSchema.ts +0 -226
  377. package/src/schemas/nodes/macro/index.ts +0 -6
  378. package/src/schemas/preprocessing/ConfluencePreprocessor.ts +0 -455
  379. package/src/schemas/preprocessing/index.ts +0 -8
  380. package/src/serializers/ConfluenceSerializer.ts +0 -737
  381. package/src/serializers/MarkdownSerializer.ts +0 -543
  382. package/src/serializers/index.ts +0 -8
  383. package/test/ast/BlockNode.test.ts +0 -265
  384. package/test/ast/Document.test.ts +0 -126
  385. package/test/ast/InlineNode.test.ts +0 -161
  386. package/test/fixtures/integration-test.html.fixture +0 -103
  387. package/test/fixtures/integration-test.md.expected +0 -257
  388. package/test/parsers/ConfluenceParser.test.ts +0 -452
  389. package/test/schemas/ConfluencePreprocessor.test.ts +0 -180
  390. package/test/schemas/ConversionSchema.test.ts +0 -159
  391. package/test/schemas/HastSchema.test.ts +0 -138
  392. package/test/schemas/MdastSchema.test.ts +0 -145
  393. package/test/schemas/nodes/block/BlockSchema.test.ts +0 -173
  394. package/test/schemas/nodes/inline/InlineSchema.test.ts +0 -198
  395. package/test/schemas/nodes/macro/MacroSchema.test.ts +0 -142
@@ -0,0 +1,521 @@
1
+ /**
2
+ * Markdown → ADF → Markdown round-trip fidelity tests for the new pipeline.
3
+ *
4
+ * Replaces the structural fidelity coverage previously held by the deleted
5
+ * `ConfluenceParser`/`MarkdownParser`/`ConversionSchema`/fixture tests. We
6
+ * pin the *substantive* output of the round-trip (heading structure, list
7
+ * markers, code-block fences, table layout, link/title fidelity) rather than
8
+ * exact whitespace, since the @atlaskit transformer normalizes whitespace
9
+ * and we don't want to over-couple to its emission.
10
+ */
11
+ import { describe, expect, it } from "@effect/vitest"
12
+ import * as Effect from "effect/Effect"
13
+ import * as Layer from "effect/Layer"
14
+ import { layer as AdfSchemaValidatorLayer } from "../src/AdfSchemaValidator.js"
15
+ import { layer as AtlaskitTransformersLayer } from "../src/AtlaskitTransformers.js"
16
+ import { layer as MarkdownConverterLayer, MarkdownConverter } from "../src/MarkdownConverter.js"
17
+
18
+ const TestLayer = MarkdownConverterLayer.pipe(
19
+ Layer.provide(AtlaskitTransformersLayer),
20
+ Layer.provide(AdfSchemaValidatorLayer)
21
+ )
22
+
23
+ const roundTrip = (source: string) =>
24
+ Effect.gen(function*() {
25
+ const converter = yield* MarkdownConverter
26
+ const adf = yield* converter.markdownToAdf(source)
27
+ return yield* converter.adfToMarkdown(adf)
28
+ })
29
+
30
+ describe("MarkdownConverter round-trip", () => {
31
+ it.effect("preserves nested headings", () =>
32
+ Effect.gen(function*() {
33
+ const md = yield* roundTrip("# H1\n\n## H2\n\n### H3\n")
34
+ expect(md).toContain("# H1")
35
+ expect(md).toContain("## H2")
36
+ expect(md).toContain("### H3")
37
+ }).pipe(Effect.provide(TestLayer)))
38
+
39
+ it.effect("preserves a fenced code block with language", () =>
40
+ Effect.gen(function*() {
41
+ const md = yield* roundTrip("```ts\nconst x: number = 1\n```\n")
42
+ expect(md).toContain("```ts")
43
+ expect(md).toContain("const x: number = 1")
44
+ }).pipe(Effect.provide(TestLayer)))
45
+
46
+ it.effect("preserves a blockquote", () =>
47
+ Effect.gen(function*() {
48
+ const md = yield* roundTrip("> a quote\n")
49
+ expect(md).toMatch(/^> a quote/m)
50
+ }).pipe(Effect.provide(TestLayer)))
51
+
52
+ it.effect("preserves a bullet list", () =>
53
+ Effect.gen(function*() {
54
+ const md = yield* roundTrip("- one\n- two\n- three\n")
55
+ expect(md).toContain("- one")
56
+ expect(md).toContain("- two")
57
+ expect(md).toContain("- three")
58
+ }).pipe(Effect.provide(TestLayer)))
59
+
60
+ it.effect("preserves an ordered list", () =>
61
+ Effect.gen(function*() {
62
+ const md = yield* roundTrip("1. one\n2. two\n3. three\n")
63
+ expect(md).toMatch(/1\. one/)
64
+ expect(md).toMatch(/2\. two/)
65
+ expect(md).toMatch(/3\. three/)
66
+ }).pipe(Effect.provide(TestLayer)))
67
+
68
+ it.effect("preserves a GFM table with header", () =>
69
+ Effect.gen(function*() {
70
+ const md = yield* roundTrip("| A | B |\n| --- | --- |\n| 1 | 2 |\n")
71
+ expect(md).toContain("| A | B |")
72
+ expect(md).toContain("| --- | --- |")
73
+ expect(md).toContain("| 1 | 2 |")
74
+ }).pipe(Effect.provide(TestLayer)))
75
+
76
+ // The @atlaskit markdown transformer drops link titles when parsing
77
+ // markdown (its ProseMirror schema for `link` does not capture `title`).
78
+ // So we only assert that text + href survive the round-trip; the title
79
+ // attribute is documented as round-trip-lossy via this test's name.
80
+ it.effect("preserves link text and href (title is lossy via @atlaskit)", () =>
81
+ Effect.gen(function*() {
82
+ const md = yield* roundTrip(`[home](https://example.com "Home")\n`)
83
+ expect(md).toContain("[home]")
84
+ expect(md).toContain("https://example.com")
85
+ }).pipe(Effect.provide(TestLayer)))
86
+
87
+ it.effect("preserves bold, italic, and inline code combinations", () =>
88
+ Effect.gen(function*() {
89
+ const md = yield* roundTrip("a **b** _c_ `d` text\n")
90
+ expect(md).toContain("**b**")
91
+ expect(md).toContain("_c_")
92
+ expect(md).toContain("`d`")
93
+ }).pipe(Effect.provide(TestLayer)))
94
+
95
+ it.effect("does not over-escape ordinary version strings", () =>
96
+ Effect.gen(function*() {
97
+ const md = yield* roundTrip("Released v1.0.0 on 2026-05-03\n")
98
+ expect(md).toContain("v1.0.0")
99
+ expect(md).toContain("2026-05-03")
100
+ expect(md).not.toContain("v1\\.0\\.0")
101
+ expect(md).not.toContain("2026\\-05\\-03")
102
+ }).pipe(Effect.provide(TestLayer)))
103
+
104
+ it.effect("does not escape parentheses or other line-start-only characters", () =>
105
+ Effect.gen(function*() {
106
+ const md = yield* roundTrip("a (b) c+ d!\n")
107
+ expect(md).toContain("a (b) c+ d!")
108
+ expect(md).not.toContain("\\(")
109
+ expect(md).not.toContain("\\+")
110
+ }).pipe(Effect.provide(TestLayer)))
111
+
112
+ // Regression: escaping inside code spans put literal backslashes into the
113
+ // ADF text, which the next pull re-escaped — doubling them on every
114
+ // round-trip (`a_b` → `a\_b` → `a\\\_b` → …).
115
+ it.effect("code spans with markdown-special characters are a round-trip fixed point", () =>
116
+ Effect.gen(function*() {
117
+ const source = "x `a_b` y `c()` (z)\n"
118
+ const once = yield* roundTrip(source)
119
+ const twice = yield* roundTrip(once)
120
+ expect(once).toContain("`a_b`")
121
+ expect(once).toContain("`c()`")
122
+ expect(once).not.toContain("\\")
123
+ expect(twice).toBe(once)
124
+ }).pipe(Effect.provide(TestLayer)))
125
+
126
+ it.effect("preserves an inline status placeholder through round-trip", () =>
127
+ Effect.gen(function*() {
128
+ const md = yield* roundTrip(
129
+ `Status: <span class="adf-status" data-color="blue">TESTING</span>\n`
130
+ )
131
+ expect(md).toContain(`<span class="adf-status" data-color="blue">TESTING</span>`)
132
+ }).pipe(Effect.provide(TestLayer)))
133
+
134
+ it.effect("upgrades a legacy generic block extension placeholder to the attrs form, then stays fixed", () =>
135
+ Effect.gen(function*() {
136
+ const md = yield* roundTrip(
137
+ `<!-- adf:extension key=anchor type=com.atlassian.confluence.macro.core -->\n`
138
+ )
139
+ expect(md).toContain("<!-- adf:extension key=anchor type=com.atlassian.confluence.macro.core attrs=")
140
+ const again = yield* roundTrip(md)
141
+ expect(again).toBe(md)
142
+ }).pipe(Effect.provide(TestLayer)))
143
+
144
+ it.effect("round-trips native TOC syntax as a fixed point", () =>
145
+ Effect.gen(function*() {
146
+ const md = yield* roundTrip("[[toc:min=2,max=4]]\n")
147
+ expect(md).toContain("[[toc:min=2,max=4]]")
148
+ const again = yield* roundTrip(md)
149
+ expect(again).toBe(md)
150
+ }).pipe(Effect.provide(TestLayer)))
151
+
152
+ it.effect("round-trips macro parameters through the placeholder attrs blob", () =>
153
+ Effect.gen(function*() {
154
+ const converter = yield* MarkdownConverter
155
+ const attrs = {
156
+ extensionKey: "toc",
157
+ extensionType: "com.atlassian.confluence.macro.core",
158
+ layout: "default",
159
+ localId: "abc-123",
160
+ parameters: { macroParams: { maxLevel: { value: "3" } } }
161
+ }
162
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
163
+ version: 1,
164
+ type: "doc",
165
+ content: [{ type: "extension", attrs }]
166
+ }))
167
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
168
+ content: Array<{ type: string; attrs: Record<string, unknown> }>
169
+ }
170
+ expect(adfOut.content[0]).toEqual({ type: "extension", attrs })
171
+ }).pipe(Effect.provide(TestLayer)))
172
+
173
+ it.effect("round-trips Confluence TOC macroMetadata through the placeholder attrs blob", () =>
174
+ Effect.gen(function*() {
175
+ const converter = yield* MarkdownConverter
176
+ const attrs = {
177
+ extensionKey: "toc",
178
+ extensionType: "com.atlassian.confluence.macro.core",
179
+ layout: "default",
180
+ parameters: {
181
+ macroMetadata: {
182
+ schemaVersion: { value: "1" },
183
+ title: "Table of Contents"
184
+ },
185
+ macroParams: {}
186
+ }
187
+ }
188
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
189
+ version: 1,
190
+ type: "doc",
191
+ content: [{ type: "extension", attrs }]
192
+ }))
193
+ expect(md).toContain("<!-- adf:extension key=toc type=com.atlassian.confluence.macro.core attrs=")
194
+ expect(md).not.toContain("[[toc")
195
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
196
+ content: Array<{ type: string; attrs: Record<string, unknown> }>
197
+ }
198
+ expect(adfOut.content[0]).toEqual({ type: "extension", attrs })
199
+ }).pipe(Effect.provide(TestLayer)))
200
+
201
+ it.effect("round-trips a bodiedExtension with its body re-attached", () =>
202
+ Effect.gen(function*() {
203
+ const converter = yield* MarkdownConverter
204
+ const attrs = { extensionKey: "details", extensionType: "com.atlassian.confluence.macro.core" }
205
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
206
+ version: 1,
207
+ type: "doc",
208
+ content: [{
209
+ type: "bodiedExtension",
210
+ attrs,
211
+ content: [
212
+ { type: "paragraph", content: [{ type: "text", text: "first body paragraph" }] },
213
+ { type: "paragraph", content: [{ type: "text", text: "second body paragraph" }] }
214
+ ]
215
+ }]
216
+ }))
217
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
218
+ content: Array<{ type: string; attrs: Record<string, unknown>; content: Array<unknown> }>
219
+ }
220
+ expect(adfOut.content).toHaveLength(1)
221
+ expect(adfOut.content[0]).toMatchObject({ type: "bodiedExtension", attrs })
222
+ expect(adfOut.content[0]!.content).toEqual([
223
+ { type: "paragraph", content: [{ type: "text", text: "first body paragraph" }] },
224
+ { type: "paragraph", content: [{ type: "text", text: "second body paragraph" }] }
225
+ ])
226
+ }).pipe(Effect.provide(TestLayer)))
227
+
228
+ it.effect("round-trips a Confluence panel as a panel node", () =>
229
+ Effect.gen(function*() {
230
+ const converter = yield* MarkdownConverter
231
+ const attrs = { panelType: "warning" }
232
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
233
+ version: 1,
234
+ type: "doc",
235
+ content: [{
236
+ type: "panel",
237
+ attrs,
238
+ content: [{ type: "paragraph", content: [{ type: "text", text: "watch this" }] }]
239
+ }]
240
+ }))
241
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
242
+ content: Array<{ type: string; attrs: Record<string, unknown>; content: Array<unknown> }>
243
+ }
244
+ expect(adfOut.content[0]).toEqual({
245
+ type: "panel",
246
+ attrs,
247
+ content: [{ type: "paragraph", content: [{ type: "text", text: "watch this" }] }]
248
+ })
249
+ }).pipe(Effect.provide(TestLayer)))
250
+
251
+ it.effect("round-trips Confluence-only inline marks as native marks", () =>
252
+ Effect.gen(function*() {
253
+ const converter = yield* MarkdownConverter
254
+ const source = {
255
+ version: 1,
256
+ type: "doc",
257
+ content: [{
258
+ type: "paragraph",
259
+ content: [
260
+ { type: "text", text: "underline", marks: [{ type: "underline" }] },
261
+ { type: "text", text: "2", marks: [{ type: "subsup", attrs: { type: "sub" } }] },
262
+ { type: "text", text: "2", marks: [{ type: "subsup", attrs: { type: "sup" } }] },
263
+ { type: "text", text: "Colored", marks: [{ type: "textColor", attrs: { color: "#ff5630" } }] },
264
+ { type: "text", text: "highlighted", marks: [{ type: "backgroundColor", attrs: { color: "#f8e6a0" } }] }
265
+ ]
266
+ }]
267
+ }
268
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
269
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
270
+ expect(adfOut.content[0]).toEqual(source.content[0])
271
+ }).pipe(Effect.provide(TestLayer)))
272
+
273
+ it.effect("round-trips paragraph alignment and indentation marks", () =>
274
+ Effect.gen(function*() {
275
+ const converter = yield* MarkdownConverter
276
+ const source = {
277
+ version: 1,
278
+ type: "doc",
279
+ content: [
280
+ {
281
+ type: "paragraph",
282
+ marks: [{ type: "alignment", attrs: { align: "center" } }],
283
+ content: [{ type: "text", text: "centered" }]
284
+ },
285
+ {
286
+ type: "paragraph",
287
+ marks: [{ type: "alignment", attrs: { align: "end" } }],
288
+ content: [{ type: "text", text: "right" }]
289
+ },
290
+ {
291
+ type: "paragraph",
292
+ marks: [{ type: "indentation", attrs: { level: 2 } }],
293
+ content: [{ type: "text", text: "indented" }]
294
+ }
295
+ ]
296
+ }
297
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
298
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
299
+ expect(adfOut.content).toEqual(source.content)
300
+ }).pipe(Effect.provide(TestLayer)))
301
+
302
+ it.effect("round-trips inline smart links as native inlineCard nodes", () =>
303
+ Effect.gen(function*() {
304
+ const converter = yield* MarkdownConverter
305
+ const source = {
306
+ version: 1,
307
+ type: "doc",
308
+ content: [{
309
+ type: "paragraph",
310
+ content: [
311
+ { type: "text", text: "Inline smart link: " },
312
+ { type: "inlineCard", attrs: { url: "https://www.atlassian.com" } },
313
+ { type: "text", text: "." }
314
+ ]
315
+ }]
316
+ }
317
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
318
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
319
+ expect(adfOut.content[0]).toEqual(source.content[0])
320
+ }).pipe(Effect.provide(TestLayer)))
321
+
322
+ it.effect("round-trips task lists as native task nodes", () =>
323
+ Effect.gen(function*() {
324
+ const converter = yield* MarkdownConverter
325
+ const source = {
326
+ version: 1,
327
+ type: "doc",
328
+ content: [{
329
+ type: "taskList",
330
+ attrs: { localId: "tasks-1" },
331
+ content: [
332
+ {
333
+ type: "taskItem",
334
+ attrs: { localId: "task-1", state: "DONE" },
335
+ content: [{ type: "text", text: "Existing primitive coverage reviewed" }]
336
+ },
337
+ {
338
+ type: "taskItem",
339
+ attrs: { localId: "task-2", state: "TODO" },
340
+ content: [{ type: "text", text: "Insert real @mention in editor" }]
341
+ }
342
+ ]
343
+ }]
344
+ }
345
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
346
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
347
+ expect(adfOut.content[0]).toEqual(source.content[0])
348
+ }).pipe(Effect.provide(TestLayer)))
349
+
350
+ it.effect("round-trips decision lists as native decision nodes", () =>
351
+ Effect.gen(function*() {
352
+ const converter = yield* MarkdownConverter
353
+ const source = {
354
+ version: 1,
355
+ type: "doc",
356
+ content: [{
357
+ type: "decisionList",
358
+ attrs: { localId: "decisions-1" },
359
+ content: [{
360
+ type: "decisionItem",
361
+ attrs: { localId: "decision-1", state: "DECIDED" },
362
+ content: [{ type: "text", text: "Decide whether to maintain a separate asset for advanced macros." }]
363
+ }]
364
+ }]
365
+ }
366
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
367
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
368
+ expect(adfOut.content[0]).toEqual(source.content[0])
369
+ }).pipe(Effect.provide(TestLayer)))
370
+
371
+ it.effect("round-trips expand, table, layout, cards, date, and emoji as native nodes", () =>
372
+ Effect.gen(function*() {
373
+ const converter = yield* MarkdownConverter
374
+ const source = {
375
+ version: 1,
376
+ type: "doc",
377
+ content: [
378
+ {
379
+ type: "expand",
380
+ attrs: { title: "Expandable supplementary content" },
381
+ content: [{ type: "paragraph", content: [{ type: "text", text: "This section can be expanded." }] }]
382
+ },
383
+ {
384
+ type: "table",
385
+ content: [{
386
+ type: "tableRow",
387
+ content: [
388
+ {
389
+ type: "tableHeader",
390
+ content: [{ type: "paragraph", content: [{ type: "text", text: "Primitive" }] }]
391
+ },
392
+ {
393
+ type: "tableHeader",
394
+ content: [{ type: "paragraph", content: [{ type: "text", text: "Example" }] }]
395
+ }
396
+ ]
397
+ }, {
398
+ type: "tableRow",
399
+ content: [
400
+ { type: "tableCell", content: [{ type: "paragraph", content: [{ type: "text", text: "Date" }] }] },
401
+ {
402
+ type: "tableCell",
403
+ content: [{
404
+ type: "paragraph",
405
+ content: [{ type: "date", attrs: { timestamp: "1782259200000" } }]
406
+ }]
407
+ }
408
+ ]
409
+ }, {
410
+ type: "tableRow",
411
+ content: [
412
+ { type: "tableCell", content: [{ type: "paragraph", content: [{ type: "text", text: "Emoji" }] }] },
413
+ {
414
+ type: "tableCell",
415
+ content: [{
416
+ type: "paragraph",
417
+ content: [{ type: "emoji", attrs: { shortName: ":white_check_mark:", text: "✅" } }]
418
+ }]
419
+ }
420
+ ]
421
+ }]
422
+ },
423
+ {
424
+ type: "layoutSection",
425
+ content: [
426
+ {
427
+ type: "layoutColumn",
428
+ attrs: { width: 50 },
429
+ content: [{ type: "paragraph", content: [{ type: "text", text: "Left column" }] }]
430
+ },
431
+ {
432
+ type: "layoutColumn",
433
+ attrs: { width: 50 },
434
+ content: [{ type: "paragraph", content: [{ type: "text", text: "Right column" }] }]
435
+ }
436
+ ]
437
+ },
438
+ { type: "blockCard", attrs: { url: "https://www.atlassian.com/software/confluence" } },
439
+ { type: "embedCard", attrs: { url: "https://www.atlassian.com/software/confluence", layout: "center" } }
440
+ ]
441
+ }
442
+ const md = yield* converter.adfToMarkdown(JSON.stringify(source))
443
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as typeof source
444
+ expect(adfOut.content).toEqual(source.content)
445
+ }).pipe(Effect.provide(TestLayer)))
446
+
447
+ // Regression: `|` in a cell was escaped twice (escapeText + the table-cell
448
+ // pass), emitting `\\|` — GFM reads that as literal backslash + bare pipe,
449
+ // which opens a phantom column and breaks the row.
450
+ it.effect("escapes a pipe inside a table cell exactly once", () =>
451
+ Effect.gen(function*() {
452
+ const md = yield* roundTrip("| A |\n| --- |\n| a\\|b |\n")
453
+ expect(md).toContain("a\\|b")
454
+ expect(md).not.toContain("a\\\\|b")
455
+ }).pipe(Effect.provide(TestLayer)))
456
+
457
+ // Regression: a code fence *quoting* the placeholder syntax got structured
458
+ // nodes injected into the codeBlock, failing outgoing schema validation.
459
+ it.effect("does not expand placeholder-looking text inside a code fence", () =>
460
+ Effect.gen(function*() {
461
+ const fence = "```html\n" +
462
+ `<span class="adf-status" data-color="blue">X</span>\n` +
463
+ `<!-- adf:inlineExtension key=k type=t -->\n` +
464
+ "```\n"
465
+ const md = yield* roundTrip(fence)
466
+ expect(md).toContain(`<span class="adf-status" data-color="blue">X</span>`)
467
+ expect(md).toContain(`<!-- adf:inlineExtension key=k type=t -->`)
468
+ expect(md).toContain("```html")
469
+ }).pipe(Effect.provide(TestLayer)))
470
+
471
+ // Regression: the inline twin of the fence case — a code *span* quoting a
472
+ // placeholder was replaced by a real status node, silently dropping the
473
+ // quoted sample.
474
+ it.effect("does not expand placeholder-looking text inside a code span", () =>
475
+ Effect.gen(function*() {
476
+ const converter = yield* MarkdownConverter
477
+ const source = `Use \`<span class="adf-status" data-color="green">DONE</span>\` in docs\n`
478
+ const adf = JSON.parse(yield* converter.markdownToAdf(source)) as {
479
+ content: Array<{ content: Array<{ type: string }> }>
480
+ }
481
+ expect(adf.content[0]!.content.some((n) => n.type === "status")).toBe(false)
482
+ }).pipe(Effect.provide(TestLayer)))
483
+
484
+ // Regression: '# x' / '> x' / '+ x' paragraph text became real headings,
485
+ // quotes, and lists after the ESCAPE_RE narrowing dropped those characters.
486
+ it.effect("keeps line-start block markers in paragraph text as text", () =>
487
+ Effect.gen(function*() {
488
+ const converter = yield* MarkdownConverter
489
+ const paragraph = (text: string) => ({ type: "paragraph", content: [{ type: "text", text }] })
490
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
491
+ version: 1,
492
+ type: "doc",
493
+ content: [paragraph("# not a heading"), paragraph("> not a quote"), paragraph("+ not a list")]
494
+ }))
495
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
496
+ content: Array<{ type: string }>
497
+ }
498
+ expect(adfOut.content.map((n) => n.type)).toEqual(["paragraph", "paragraph", "paragraph"])
499
+ }).pipe(Effect.provide(TestLayer)))
500
+
501
+ it.effect("keeps the bodied kind for an empty-body bodied extension", () =>
502
+ Effect.gen(function*() {
503
+ const converter = yield* MarkdownConverter
504
+ const attrs = { extensionKey: "excerpt", extensionType: "com.atlassian.confluence.macro.core" }
505
+ const md = yield* converter.adfToMarkdown(JSON.stringify({
506
+ version: 1,
507
+ type: "doc",
508
+ content: [{ type: "bodiedExtension", attrs, content: [{ type: "paragraph", content: [] }] }]
509
+ }))
510
+ const adfOut = JSON.parse(yield* converter.markdownToAdf(md)) as {
511
+ content: Array<{ type: string }>
512
+ }
513
+ expect(adfOut.content[0]!.type).toBe("bodiedExtension")
514
+ }).pipe(Effect.provide(TestLayer)))
515
+
516
+ it.effect("preserves a mention's accountId through round-trip", () =>
517
+ Effect.gen(function*() {
518
+ const md = yield* roundTrip(`[@Andrey Konopkov](confluence-mention://557057%3Aabc-123)\n`)
519
+ expect(md).toContain("[@Andrey Konopkov](confluence-mention://557057%3Aabc-123)")
520
+ }).pipe(Effect.provide(TestLayer)))
521
+ })