@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
@@ -1,797 +0,0 @@
1
- /**
2
- * Parser for Confluence storage format (HTML) to AST.
3
- *
4
- * @module
5
- */
6
- import * as Effect from "effect/Effect";
7
- import * as Schema from "effect/Schema";
8
- import rehypeParse from "rehype-parse";
9
- import { unified } from "unified";
10
- import { CodeBlock, Heading, Image, Paragraph, Table, TableCell, TableRow, ThematicBreak, UnsupportedBlock } from "../ast/BlockNode.js";
11
- import { makeDocument } from "../ast/Document.js";
12
- import { ColoredText, DateTime, Emoticon, Emphasis, Highlight, InlineCode, LineBreak, Link, Strikethrough, Strong, Subscript, Superscript, Text, Underline, UnsupportedInline, UserMention } from "../ast/InlineNode.js";
13
- import { PanelTypes } from "../ast/MacroNode.js";
14
- import { ParseError } from "../SchemaConverterError.js";
15
- import { PreprocessedHtmlFromConfluence } from "../schemas/preprocessing/index.js";
16
- /**
17
- * Parse Confluence storage format HTML to Document AST.
18
- *
19
- * @example
20
- * ```typescript
21
- * import { parseConfluenceHtml } from "@knpkv/confluence-to-markdown/parsers/ConfluenceParser"
22
- * import { Effect } from "effect"
23
- *
24
- * Effect.gen(function* () {
25
- * const doc = yield* parseConfluenceHtml("<h1>Title</h1><p>Content</p>")
26
- * console.log(doc.children.length) // 2
27
- * })
28
- * ```
29
- *
30
- * @category Parsers
31
- */
32
- export const parseConfluenceHtml = (html) => Effect.gen(function* () {
33
- // Pre-process Confluence macros (includes size validation)
34
- const preprocessed = yield* Schema.decode(PreprocessedHtmlFromConfluence)(html).pipe(Effect.mapError((error) => new ParseError({
35
- source: "confluence",
36
- message: `Preprocessing error: ${error.message}`,
37
- rawContent: html.slice(0, 200)
38
- })));
39
- // Parse HTML to hast
40
- const hast = yield* Effect.try({
41
- try: () => unified().use(rehypeParse, { fragment: true }).parse(preprocessed),
42
- catch: (error) => new ParseError({
43
- source: "confluence",
44
- message: `HTML parse error: ${error instanceof Error ? error.message : String(error)}`,
45
- rawContent: html.slice(0, 200)
46
- })
47
- });
48
- // Convert hast to AST
49
- const children = yield* hastToDocumentNodes(hast);
50
- // Store original HTML for 1-to-1 roundtrip
51
- return makeDocument(children, html);
52
- });
53
- /**
54
- * Convert hast Root to document nodes.
55
- */
56
- const hastToDocumentNodes = (root) => Effect.gen(function* () {
57
- const nodes = [];
58
- for (const child of root.children) {
59
- if (child.type === "element") {
60
- const el = child;
61
- // Check for marker div containing a cf: comment
62
- if (el.tagName === "div" && el.properties?.["dataCfMarker"] !== undefined) {
63
- const commentChild = el.children.find((c) => c.type === "comment");
64
- if (commentChild) {
65
- const comment = commentChild.value;
66
- const node = yield* parseCommentNode(comment);
67
- if (node !== null)
68
- nodes.push(node);
69
- }
70
- }
71
- else {
72
- const node = yield* hastElementToNode(el);
73
- if (node !== null)
74
- nodes.push(node);
75
- }
76
- }
77
- else if (child.type === "comment") {
78
- // Handle cf: comment-encoded elements at root level
79
- const comment = child.value;
80
- const node = yield* parseCommentNode(comment);
81
- if (node !== null)
82
- nodes.push(node);
83
- }
84
- }
85
- return nodes;
86
- });
87
- /**
88
- * Parse comment-encoded elements (decision lists, layout markers, etc).
89
- */
90
- const parseCommentNode = (comment) => Effect.gen(function* () {
91
- // Decision list: cf:decision:localId;state;content|localId;state;content
92
- const decisionMatch = comment.match(/^cf:decision:(.*)$/);
93
- if (decisionMatch) {
94
- const itemsStr = decisionMatch[1] ?? "";
95
- // Return as UnsupportedBlock with the encoded comment for roundtrip
96
- return new UnsupportedBlock({
97
- rawHtml: `<!--cf:decision:${itemsStr}-->`,
98
- source: "confluence"
99
- });
100
- }
101
- // Layout markers - these are structural markers, preserve for roundtrip
102
- // cf:layout-start, cf:layout-end
103
- if (comment === "cf:layout-start" || comment === "cf:layout-end") {
104
- return new UnsupportedBlock({
105
- rawHtml: `<!--${comment}-->`,
106
- source: "confluence"
107
- });
108
- }
109
- // cf:section:index;type;breakoutMode;breakoutWidth;cellCount
110
- const sectionMatch = comment.match(/^cf:section:(\d+);([^;]*);([^;]*);([^;]*);(\d+)$/);
111
- if (sectionMatch) {
112
- return new UnsupportedBlock({
113
- rawHtml: `<!--${comment}-->`,
114
- source: "confluence"
115
- });
116
- }
117
- // cf:section-end:index
118
- if (comment.startsWith("cf:section-end:")) {
119
- return new UnsupportedBlock({
120
- rawHtml: `<!--${comment}-->`,
121
- source: "confluence"
122
- });
123
- }
124
- // cf:cell:sectionIndex;cellIndex
125
- const cellMatch = comment.match(/^cf:cell:(\d+);(\d+)$/);
126
- if (cellMatch) {
127
- return new UnsupportedBlock({
128
- rawHtml: `<!--${comment}-->`,
129
- source: "confluence"
130
- });
131
- }
132
- return null;
133
- });
134
- /**
135
- * Convert hast Element to BlockNode or MacroNode.
136
- */
137
- const hastElementToNode = (element) => Effect.gen(function* () {
138
- const tagName = element.tagName.toLowerCase();
139
- // Heading
140
- if (/^h[1-6]$/.test(tagName)) {
141
- const levelStr = tagName[1];
142
- if (!levelStr)
143
- return null;
144
- const level = parseInt(levelStr);
145
- const children = yield* hastChildrenToInline(element.children);
146
- return new Heading({ level, children });
147
- }
148
- // Paragraph (with optional alignment and indent)
149
- if (tagName === "p") {
150
- const children = yield* hastChildrenToInline(element.children);
151
- const style = element.properties?.style;
152
- let alignment;
153
- let indent;
154
- if (style) {
155
- const alignMatch = style.match(/text-align:\s*(left|center|right)/);
156
- if (alignMatch?.[1]) {
157
- alignment = alignMatch[1];
158
- }
159
- const marginMatch = style.match(/margin-left:\s*(\d+(?:\.\d+)?)\s*px/);
160
- if (marginMatch?.[1]) {
161
- indent = parseFloat(marginMatch[1]);
162
- }
163
- }
164
- if (alignment !== undefined || indent !== undefined) {
165
- return new Paragraph({
166
- children,
167
- ...(alignment !== undefined ? { alignment } : {}),
168
- ...(indent !== undefined ? { indent } : {})
169
- });
170
- }
171
- return new Paragraph({ children });
172
- }
173
- // Code block
174
- if (tagName === "pre") {
175
- const codeEl = element.children.find((c) => c.type === "element" && c.tagName === "code");
176
- const code = codeEl ? getTextContent(codeEl) : getTextContent(element);
177
- const language = element.properties?.["dataLanguage"] || undefined;
178
- return new CodeBlock({ code, language });
179
- }
180
- // Thematic break
181
- if (tagName === "hr") {
182
- return new ThematicBreak({});
183
- }
184
- // Image (supports both URL and Confluence attachments from preprocessed data)
185
- if (tagName === "img") {
186
- const src = element.properties?.src;
187
- const dataAttachment = element.properties?.["dataAttachment"];
188
- const dataAlign = element.properties?.["dataAlign"];
189
- const dataWidth = element.properties?.["dataWidth"];
190
- const alt = element.properties?.alt || undefined;
191
- // Confluence attachment (preprocessed)
192
- if (dataAttachment) {
193
- return new Image({
194
- attachment: { filename: dataAttachment },
195
- alt,
196
- ...(dataAlign ? { align: dataAlign } : {}),
197
- ...(dataWidth ? { width: parseInt(dataWidth) } : {})
198
- });
199
- }
200
- // URL-based image
201
- if (!src)
202
- return null;
203
- return new Image({
204
- src,
205
- alt,
206
- title: element.properties?.title || undefined
207
- });
208
- }
209
- // Table
210
- if (tagName === "table") {
211
- return yield* parseTable(element);
212
- }
213
- // Task list (from preprocessed data)
214
- if (tagName === "ul" && element.properties?.["dataMacro"] === "task-list") {
215
- return yield* parseTaskList(element);
216
- }
217
- // Lists
218
- if (tagName === "ul" || tagName === "ol") {
219
- return yield* parseList(element, tagName === "ol");
220
- }
221
- // Block quote
222
- if (tagName === "blockquote") {
223
- const children = yield* hastChildrenToSimpleBlocks(element.children);
224
- return { _tag: "BlockQuote", version: 1, children };
225
- }
226
- // Macro divs
227
- if (tagName === "div" && element.properties?.["dataMacro"]) {
228
- const macro = element.properties["dataMacro"];
229
- if (PanelTypes.includes(macro)) {
230
- const children = yield* hastChildrenToSimpleBlocks(element.children);
231
- return {
232
- _tag: "InfoPanel",
233
- version: 1,
234
- panelType: macro,
235
- title: element.properties["dataTitle"] || undefined,
236
- children
237
- };
238
- }
239
- }
240
- // Expand/details
241
- if (tagName === "details") {
242
- const summary = element.children.find((c) => c.type === "element" && c.tagName === "summary");
243
- const title = summary ? getTextContent(summary) : undefined;
244
- const contentChildren = element.children.filter((c) => !(c.type === "element" && c.tagName === "summary"));
245
- const children = yield* hastChildrenToSimpleBlocks(contentChildren);
246
- return {
247
- _tag: "ExpandMacro",
248
- version: 1,
249
- title,
250
- children
251
- };
252
- }
253
- // TOC
254
- if (tagName === "nav" && element.properties?.["dataMacro"] === "toc") {
255
- const minStr = element.properties["dataMin"];
256
- const maxStr = element.properties["dataMax"];
257
- return {
258
- _tag: "TocMacro",
259
- version: 1,
260
- minLevel: minStr ? parseInt(minStr) : undefined,
261
- maxLevel: maxStr ? parseInt(maxStr) : undefined
262
- };
263
- }
264
- // Unsupported macro
265
- if (element.properties?.["dataUnsupportedMacro"]) {
266
- return new UnsupportedBlock({
267
- rawHtml: hastToHtml(element),
268
- source: "confluence"
269
- });
270
- }
271
- // Generic div - recurse into children
272
- if (tagName === "div" || tagName === "section" || tagName === "article") {
273
- const children = [];
274
- for (const child of element.children) {
275
- if (child.type === "element") {
276
- const node = yield* hastElementToNode(child);
277
- if (node !== null)
278
- children.push(node);
279
- }
280
- }
281
- if (children.length >= 1) {
282
- const first = children[0];
283
- return first !== undefined ? first : null;
284
- }
285
- return null;
286
- }
287
- // Ignore common layout elements
288
- if (["br", "html", "head", "body"].includes(tagName)) {
289
- return null;
290
- }
291
- // Inline elements at block level - wrap in paragraph
292
- if (["a", "strong", "em", "b", "i", "u", "code", "del", "sub", "sup", "span"].includes(tagName)) {
293
- const inlineNode = yield* hastElementToInline(element);
294
- if (inlineNode) {
295
- return new Paragraph({ children: [inlineNode] });
296
- }
297
- return null;
298
- }
299
- // Unknown block element
300
- return new UnsupportedBlock({
301
- rawHtml: hastToHtml(element),
302
- source: "confluence"
303
- });
304
- });
305
- /**
306
- * Convert hast children to inline nodes.
307
- */
308
- const hastChildrenToInline = (children) => Effect.gen(function* () {
309
- const nodes = [];
310
- for (const child of children) {
311
- if (child.type === "text") {
312
- const textNode = child;
313
- if (textNode.value.trim() || nodes.length > 0) {
314
- nodes.push(new Text({ value: textNode.value }));
315
- }
316
- }
317
- else if (child.type === "element") {
318
- const node = yield* hastElementToInline(child);
319
- if (node !== null)
320
- nodes.push(node);
321
- }
322
- }
323
- return nodes;
324
- });
325
- /**
326
- * Convert hast Element to InlineNode.
327
- */
328
- const hastElementToInline = (element) => Effect.gen(function* () {
329
- const tagName = element.tagName.toLowerCase();
330
- // Strong/bold
331
- if (tagName === "strong" || tagName === "b") {
332
- const children = yield* hastChildrenToBaseInline(element.children);
333
- return new Strong({ children });
334
- }
335
- // Emphasis/italic
336
- if (tagName === "em" || tagName === "i") {
337
- const children = yield* hastChildrenToBaseInline(element.children);
338
- return new Emphasis({ children });
339
- }
340
- // Underline
341
- if (tagName === "u") {
342
- const children = yield* hastChildrenToBaseInline(element.children);
343
- return new Underline({ children });
344
- }
345
- // Strikethrough
346
- if (tagName === "del" || tagName === "s") {
347
- const children = yield* hastChildrenToBaseInline(element.children);
348
- return new Strikethrough({ children });
349
- }
350
- // Subscript
351
- if (tagName === "sub") {
352
- const children = yield* hastChildrenToBaseInline(element.children);
353
- return new Subscript({ children });
354
- }
355
- // Superscript
356
- if (tagName === "sup") {
357
- const children = yield* hastChildrenToBaseInline(element.children);
358
- return new Superscript({ children });
359
- }
360
- // Inline code
361
- if (tagName === "code") {
362
- return new InlineCode({ value: getTextContent(element) });
363
- }
364
- // Smart link (Jira, Confluence search, etc.) - preserve datasource for roundtrip
365
- if (tagName === "a" && element.properties?.["dataDatasource"]) {
366
- const href = element.properties?.href;
367
- const appearance = element.properties?.["dataCardAppearance"] || "inline";
368
- const datasource = element.properties["dataDatasource"];
369
- return new UnsupportedInline({
370
- raw: `<!--cf:smartlink:${encodeURIComponent(href ?? "")};${encodeURIComponent(appearance)};${encodeURIComponent(datasource)}-->`,
371
- source: "confluence"
372
- });
373
- }
374
- // Link
375
- if (tagName === "a") {
376
- const href = element.properties?.href;
377
- if (!href)
378
- return null;
379
- const children = yield* hastChildrenToBaseInline(element.children);
380
- return new Link({
381
- href,
382
- title: element.properties?.title || undefined,
383
- children
384
- });
385
- }
386
- // Line break
387
- if (tagName === "br") {
388
- return new LineBreak({});
389
- }
390
- // Date/time (rehype converts datetime attr to camelCase dateTime)
391
- if (tagName === "time") {
392
- const datetime = element.properties?.dateTime || "";
393
- return new DateTime({ datetime });
394
- }
395
- // Emoticon (preprocessed from ac:emoticon)
396
- if (tagName === "span" && element.properties?.["dataEmoji"]) {
397
- const shortname = element.properties["dataEmoji"] || "";
398
- const emojiId = element.properties["dataEmojiId"] || "";
399
- const fallback = getTextContent(element);
400
- return new Emoticon({ shortname, emojiId, fallback });
401
- }
402
- // User mention (preprocessed from ac:link > ri:user)
403
- if (tagName === "span" && element.properties?.["dataUserMention"]) {
404
- const accountId = element.properties["dataUserMention"] || "";
405
- return new UserMention({ accountId });
406
- }
407
- // Confluence link with link-body (preprocessed from ac:link > ac:link-body)
408
- if (tagName === "span" && element.properties?.["dataConfluenceLink"] !== undefined) {
409
- const linkText = getTextContent(element);
410
- return new UnsupportedInline({
411
- raw: `<!--cf:link:${encodeURIComponent(linkText)}-->`,
412
- source: "confluence"
413
- });
414
- }
415
- // Status macro (inline) - use comment encoding for roundtrip
416
- if (tagName === "span" && element.properties?.["dataMacro"] === "status") {
417
- const color = element.properties["dataColor"] || "";
418
- const title = getTextContent(element);
419
- return new UnsupportedInline({
420
- raw: `<!--cf:status:${encodeURIComponent(title)};${encodeURIComponent(color)}-->`,
421
- source: "confluence"
422
- });
423
- }
424
- // TOC macro in inline context (e.g., inside table cell) - use comment encoding
425
- // Use ; as separator (not | which breaks markdown tables)
426
- if (tagName === "nav" && element.properties?.["dataMacro"] === "toc") {
427
- const minStr = element.properties["dataMin"];
428
- const maxStr = element.properties["dataMax"];
429
- return new UnsupportedInline({
430
- raw: `<!--cf:toc:${minStr ?? ""};${maxStr ?? ""}-->`,
431
- source: "confluence"
432
- });
433
- }
434
- // Colored text (span with color style)
435
- if (tagName === "span") {
436
- const style = element.properties?.style;
437
- if (style) {
438
- const colorMatch = style.match(/(?:^|;)\s*color:\s*([^;]+)/);
439
- const bgMatch = style.match(/(?:^|;)\s*background-color:\s*([^;]+)/);
440
- if (colorMatch?.[1]) {
441
- const children = yield* hastChildrenToBaseInline(element.children);
442
- return new ColoredText({ color: colorMatch[1].trim(), children });
443
- }
444
- if (bgMatch?.[1]) {
445
- const children = yield* hastChildrenToBaseInline(element.children);
446
- return new Highlight({ backgroundColor: bgMatch[1].trim(), children });
447
- }
448
- }
449
- // Nested inline elements - extract content
450
- const children = yield* hastChildrenToInline(element.children);
451
- if (children.length === 1) {
452
- const first = children[0];
453
- return first !== undefined ? first : null;
454
- }
455
- return null;
456
- }
457
- // Images can be inline too
458
- if (tagName === "img") {
459
- return new UnsupportedInline({
460
- raw: hastToHtml(element),
461
- source: "confluence"
462
- });
463
- }
464
- // Unknown inline element
465
- return new UnsupportedInline({
466
- raw: hastToHtml(element),
467
- source: "confluence"
468
- });
469
- });
470
- /**
471
- * Convert hast children to base inline nodes (for Strong/Emphasis/Link children).
472
- */
473
- const hastChildrenToBaseInline = (children) => Effect.gen(function* () {
474
- const nodes = [];
475
- for (const child of children) {
476
- if (child.type === "text") {
477
- const textNode = child;
478
- nodes.push(new Text({ value: textNode.value }));
479
- }
480
- else if (child.type === "element") {
481
- const el = child;
482
- const tagName = el.tagName.toLowerCase();
483
- if (tagName === "code") {
484
- nodes.push(new InlineCode({ value: getTextContent(el) }));
485
- }
486
- else if (tagName === "br") {
487
- nodes.push(new LineBreak({}));
488
- }
489
- else {
490
- nodes.push(new UnsupportedInline({ raw: hastToHtml(el), source: "confluence" }));
491
- }
492
- }
493
- }
494
- return nodes;
495
- });
496
- /**
497
- * Convert hast children to simple block nodes (non-recursive).
498
- */
499
- const hastChildrenToSimpleBlocks = (children) => Effect.gen(function* () {
500
- const blocks = [];
501
- for (const child of children) {
502
- if (child.type === "element") {
503
- const el = child;
504
- const tagName = el.tagName.toLowerCase();
505
- if (/^h[1-6]$/.test(tagName)) {
506
- const levelStr = tagName[1];
507
- if (levelStr) {
508
- const level = parseInt(levelStr);
509
- const inlineChildren = yield* hastChildrenToInline(el.children);
510
- blocks.push(new Heading({ level, children: inlineChildren }));
511
- }
512
- }
513
- else if (tagName === "p") {
514
- const inlineChildren = yield* hastChildrenToInline(el.children);
515
- blocks.push(new Paragraph({ children: inlineChildren }));
516
- }
517
- else if (tagName === "pre") {
518
- const codeEl = el.children.find((c) => c.type === "element" && c.tagName === "code");
519
- const code = codeEl ? getTextContent(codeEl) : getTextContent(el);
520
- blocks.push(new CodeBlock({ code }));
521
- }
522
- else if (tagName === "hr") {
523
- blocks.push(new ThematicBreak({}));
524
- }
525
- else if (tagName === "img") {
526
- const src = el.properties?.src;
527
- if (src)
528
- blocks.push(new Image({ src }));
529
- }
530
- else if (tagName === "table") {
531
- blocks.push(yield* parseTable(el));
532
- }
533
- else {
534
- blocks.push(new UnsupportedBlock({ rawHtml: hastToHtml(el), source: "confluence" }));
535
- }
536
- }
537
- }
538
- return blocks;
539
- });
540
- /**
541
- * Parse table element.
542
- */
543
- const parseTable = (element) => Effect.gen(function* () {
544
- let header;
545
- const rows = [];
546
- for (const child of element.children) {
547
- if (child.type !== "element")
548
- continue;
549
- const el = child;
550
- if (el.tagName === "thead") {
551
- const tr = el.children.find((c) => c.type === "element" && c.tagName === "tr");
552
- if (tr) {
553
- header = yield* parseTableRow(tr, true);
554
- }
555
- }
556
- else if (el.tagName === "tbody") {
557
- for (const row of el.children) {
558
- if (row.type === "element" && row.tagName === "tr") {
559
- const tr = row;
560
- // Check if this row has all <th> cells - treat as header if no header yet
561
- const allTh = tr.children
562
- .filter((c) => c.type === "element")
563
- .every((c) => c.tagName === "th");
564
- if (allTh && !header && rows.length === 0) {
565
- header = yield* parseTableRow(tr, true);
566
- }
567
- else {
568
- rows.push(yield* parseTableRow(tr, false));
569
- }
570
- }
571
- }
572
- }
573
- else if (el.tagName === "tr") {
574
- rows.push(yield* parseTableRow(el, false));
575
- }
576
- }
577
- return new Table({ header, rows });
578
- });
579
- /**
580
- * Parse table row.
581
- */
582
- const parseTableRow = (element, isHeader) => Effect.gen(function* () {
583
- const cells = [];
584
- for (const child of element.children) {
585
- if (child.type === "element") {
586
- const el = child;
587
- if (el.tagName === "td" || el.tagName === "th") {
588
- const cellIsHeader = isHeader || el.tagName === "th";
589
- // Unwrap single <p> elements inside cells
590
- const children = yield* parseCellContent(el.children);
591
- cells.push(new TableCell({ isHeader: cellIsHeader, children }));
592
- }
593
- }
594
- }
595
- return new TableRow({ cells });
596
- });
597
- /**
598
- * Parse cell content, unwrapping single <p> elements.
599
- *
600
- * Confluence's editor frequently emits empty `<p>` placeholders alongside the
601
- * real content (e.g. `<p/><p>Must</p>` for a styled cell). Skip those so the
602
- * single-real-paragraph case still hits the unwrap path.
603
- */
604
- const parseCellContent = (children) => Effect.gen(function* () {
605
- const isEmptyParagraph = (el) => el.tagName.toLowerCase() === "p" &&
606
- el.children.every((c) => c.type === "text" && !c.value.trim());
607
- // Find actual element children (skip whitespace text and empty <p> placeholders)
608
- const elementChildren = children.filter((c) => {
609
- if (c.type === "element")
610
- return !isEmptyParagraph(c);
611
- if (c.type === "text" && c.value.trim())
612
- return true;
613
- return false;
614
- });
615
- // If single <p> element, unwrap it
616
- if (elementChildren.length === 1) {
617
- const first = elementChildren[0];
618
- if (first && first.type === "element" && first.tagName === "p") {
619
- return yield* hastChildrenToInline(first.children);
620
- }
621
- }
622
- // Otherwise parse normally
623
- return yield* hastChildrenToInline(children);
624
- });
625
- /**
626
- * Parse task list element (preprocessed from ac:task-list).
627
- */
628
- const parseTaskList = (element) => Effect.gen(function* () {
629
- const items = [];
630
- for (const child of element.children) {
631
- if (child.type === "element" && child.tagName === "li") {
632
- const li = child;
633
- const id = li.properties?.["dataTaskId"] || "";
634
- const uuid = li.properties?.["dataTaskUuid"] || "";
635
- const status = li.properties?.["dataTaskStatus"] === "complete"
636
- ? "complete"
637
- : "incomplete";
638
- const body = yield* hastChildrenToInline(li.children);
639
- items.push({
640
- _tag: "TaskItem",
641
- id,
642
- uuid,
643
- status,
644
- body
645
- });
646
- }
647
- }
648
- return {
649
- _tag: "TaskList",
650
- version: 1,
651
- children: items
652
- };
653
- });
654
- /**
655
- * Parse list element.
656
- */
657
- const parseList = (element, ordered) => Effect.gen(function* () {
658
- const items = [];
659
- const startProp = element.properties?.start;
660
- const start = ordered && startProp ? parseInt(String(startProp)) : undefined;
661
- for (const child of element.children) {
662
- if (child.type === "element" && child.tagName === "li") {
663
- const li = child;
664
- const children = yield* parseListItemContent(li.children);
665
- // Check for task list items
666
- const checkbox = li.children.find((c) => c.type === "element" &&
667
- c.tagName === "input" &&
668
- c.properties?.type === "checkbox");
669
- const checked = checkbox ? (checkbox.properties?.checked === true) : undefined;
670
- if (checked !== undefined) {
671
- items.push({ _tag: "ListItem", checked, children });
672
- }
673
- else {
674
- items.push({ _tag: "ListItem", children });
675
- }
676
- }
677
- }
678
- if (start !== undefined) {
679
- return { _tag: "List", version: 1, ordered, start, children: items };
680
- }
681
- return { _tag: "List", version: 1, ordered, children: items };
682
- });
683
- /**
684
- * Parse list item content, handling nested lists and unwrapping single <p>.
685
- * Also handles direct text/inline content without wrapper elements.
686
- */
687
- const parseListItemContent = (children) => Effect.gen(function* () {
688
- const blocks = [];
689
- // Check if there's any direct text/inline content (not wrapped in <p>)
690
- const hasDirectInlineContent = children.some((child) => {
691
- if (child.type === "text") {
692
- return child.value.trim() !== "";
693
- }
694
- if (child.type === "element") {
695
- const tagName = child.tagName.toLowerCase();
696
- // Inline elements that should be wrapped in a paragraph
697
- return ["a", "strong", "em", "b", "i", "u", "code", "span", "del", "sub", "sup"].includes(tagName);
698
- }
699
- return false;
700
- });
701
- // If there's direct inline content, wrap it all in a paragraph
702
- if (hasDirectInlineContent) {
703
- const inlineChildren = yield* hastChildrenToInline(children);
704
- if (inlineChildren.length > 0) {
705
- blocks.push(new Paragraph({ children: inlineChildren }));
706
- }
707
- // Also check for nested lists after the inline content
708
- for (const child of children) {
709
- if (child.type === "element") {
710
- const el = child;
711
- const tagName = el.tagName.toLowerCase();
712
- if (tagName === "ul" || tagName === "ol") {
713
- blocks.push(yield* parseList(el, tagName === "ol"));
714
- }
715
- }
716
- }
717
- return blocks;
718
- }
719
- for (const child of children) {
720
- if (child.type !== "element")
721
- continue;
722
- const el = child;
723
- const tagName = el.tagName.toLowerCase();
724
- // Single <p> inside list item - extract inline content as paragraph
725
- if (tagName === "p") {
726
- const inlineChildren = yield* hastChildrenToInline(el.children);
727
- blocks.push(new Paragraph({ children: inlineChildren }));
728
- }
729
- else if (tagName === "ul" || tagName === "ol") {
730
- blocks.push(yield* parseList(el, tagName === "ol"));
731
- }
732
- else if (tagName === "pre") {
733
- const codeEl = el.children.find((c) => c.type === "element" && c.tagName === "code");
734
- const code = codeEl ? getTextContent(codeEl) : getTextContent(el);
735
- blocks.push(new CodeBlock({ code }));
736
- }
737
- else if (tagName === "hr") {
738
- blocks.push(new ThematicBreak({}));
739
- }
740
- else if (tagName === "img") {
741
- const src = el.properties?.src;
742
- if (src)
743
- blocks.push(new Image({ src }));
744
- }
745
- else if (tagName === "table") {
746
- blocks.push(yield* parseTable(el));
747
- }
748
- else if (/^h[1-6]$/.test(tagName)) {
749
- const levelStr = tagName[1];
750
- if (levelStr) {
751
- const level = parseInt(levelStr);
752
- const inlineChildren = yield* hastChildrenToInline(el.children);
753
- blocks.push(new Heading({ level, children: inlineChildren }));
754
- }
755
- }
756
- }
757
- return blocks;
758
- });
759
- /**
760
- * Get text content from hast node.
761
- */
762
- const getTextContent = (element) => {
763
- let text = "";
764
- for (const child of element.children) {
765
- if (child.type === "text") {
766
- text += child.value;
767
- }
768
- else if (child.type === "element") {
769
- text += getTextContent(child);
770
- }
771
- }
772
- return text;
773
- };
774
- /**
775
- * Convert hast element back to HTML string (for unsupported elements).
776
- */
777
- const hastToHtml = (element) => {
778
- const props = Object.entries(element.properties || {})
779
- .map(([k, v]) => {
780
- const attrName = k.replace(/([A-Z])/g, "-$1").toLowerCase();
781
- return `${attrName}="${String(v)}"`;
782
- })
783
- .join(" ");
784
- const openTag = props ? `<${element.tagName} ${props}>` : `<${element.tagName}>`;
785
- const closeTag = `</${element.tagName}>`;
786
- const content = element.children
787
- .map((c) => {
788
- if (c.type === "text")
789
- return c.value;
790
- if (c.type === "element")
791
- return hastToHtml(c);
792
- return "";
793
- })
794
- .join("");
795
- return `${openTag}${content}${closeTag}`;
796
- };
797
- //# sourceMappingURL=ConfluenceParser.js.map