@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
package/src/GitService.ts CHANGED
@@ -3,17 +3,13 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import * as NodeCommandExecutor from "@effect/platform-node/NodeCommandExecutor"
7
- import * as NodeContext from "@effect/platform-node/NodeContext"
8
- import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem"
9
- import * as NodePath from "@effect/platform-node/NodePath"
10
- import * as CommandExecutor from "@effect/platform/CommandExecutor"
11
- import type * as PlatformError from "@effect/platform/Error"
12
- import * as FileSystem from "@effect/platform/FileSystem"
13
- import * as Path from "@effect/platform/Path"
14
6
  import * as Context from "effect/Context"
15
7
  import * as Effect from "effect/Effect"
8
+ import * as FileSystem from "effect/FileSystem"
16
9
  import * as Layer from "effect/Layer"
10
+ import * as Path from "effect/Path"
11
+ import type * as PlatformError from "effect/PlatformError"
12
+ import { ChildProcessSpawner } from "effect/unstable/process"
17
13
  import {
18
14
  GitError,
19
15
  GitMergeConflictError,
@@ -249,10 +245,10 @@ export interface GitServiceShape {
249
245
  *
250
246
  * @category Service
251
247
  */
252
- export class GitService extends Context.Tag("@knpkv/confluence-to-markdown/GitService")<
248
+ export class GitService extends Context.Service<
253
249
  GitService,
254
250
  GitServiceShape
255
- >() {}
251
+ >()("@knpkv/confluence-to-markdown/GitService") {}
256
252
 
257
253
  /**
258
254
  * Map PlatformError to GitError.
@@ -260,13 +256,15 @@ export class GitService extends Context.Tag("@knpkv/confluence-to-markdown/GitSe
260
256
  const mapFsError = (error: PlatformError.PlatformError): GitError =>
261
257
  new GitError({ command: "filesystem", message: error.message })
262
258
 
263
- // Dependencies layer for git operations (CommandExecutor + FileSystem + Path + NodeContext)
264
- // NodeCommandExecutor requires FileSystem, so use provideMerge to satisfy its dependencies
265
- const GitDepsLive = NodeCommandExecutor.layer.pipe(
266
- Layer.provideMerge(NodeFileSystem.layer),
267
- Layer.provideMerge(NodePath.layer),
268
- Layer.provideMerge(NodeContext.layer)
269
- )
259
+ const existsOrFalse = (
260
+ effect: Effect.Effect<boolean, PlatformError.PlatformError>
261
+ ): Effect.Effect<boolean> =>
262
+ effect.pipe(
263
+ Effect.catchIf(
264
+ (error): error is PlatformError.PlatformError => error._tag === "PlatformError",
265
+ () => Effect.succeed(false)
266
+ )
267
+ )
270
268
 
271
269
  /**
272
270
  * Copy a single file, creating parent directories as needed.
@@ -279,7 +277,7 @@ const copyFileFn = (
279
277
  ): Effect.Effect<void, GitError> =>
280
278
  Effect.gen(function*() {
281
279
  const destDir = pathService.dirname(dest)
282
- yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.catchAll(() => Effect.void))
280
+ yield* fs.makeDirectory(destDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
283
281
  yield* fs.copyFile(source, dest).pipe(Effect.mapError(mapFsError))
284
282
  })
285
283
 
@@ -293,7 +291,7 @@ const copyDirectoryFn = (
293
291
  dest: string
294
292
  ): Effect.Effect<void, GitError> =>
295
293
  Effect.gen(function*() {
296
- yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.catchAll(() => Effect.void))
294
+ yield* fs.makeDirectory(dest, { recursive: true }).pipe(Effect.mapError(mapFsError))
297
295
 
298
296
  const entries = yield* fs.readDirectory(source).pipe(Effect.mapError(mapFsError))
299
297
 
@@ -321,7 +319,7 @@ const copyMarkdownFilesFn = (
321
319
  dest: string
322
320
  ): Effect.Effect<void, GitError> =>
323
321
  Effect.gen(function*() {
324
- const exists = yield* fs.exists(source).pipe(Effect.catchAll(() => Effect.succeed(false)))
322
+ const exists = yield* existsOrFalse(fs.exists(source))
325
323
  if (!exists) {
326
324
  return
327
325
  }
@@ -349,7 +347,7 @@ const copyMarkdownFilesFn = (
349
347
 
350
348
  // Get paths helper - takes pathService as param
351
349
  const getPaths = (pathService: Path.Path) => {
352
- const cwd = process.cwd()
350
+ const cwd = pathService.resolve(".")
353
351
  const confluenceDir = pathService.join(cwd, ".confluence")
354
352
  const gitDir = pathService.join(confluenceDir, ".git")
355
353
  return { cwd, confluenceDir, gitDir, pathService }
@@ -358,7 +356,7 @@ const getPaths = (pathService: Path.Path) => {
358
356
  // Ensure initialized helper - takes fs and gitDir
359
357
  const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
360
358
  Effect.gen(function*() {
361
- const initialized = yield* fs.exists(gitDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
359
+ const initialized = yield* existsOrFalse(fs.exists(gitDir))
362
360
  if (!initialized) {
363
361
  return yield* Effect.fail(new GitNotInitializedError())
364
362
  }
@@ -368,17 +366,18 @@ const ensureInitializedFn = (fs: FileSystem.FileSystem, gitDir: string) =>
368
366
  const make = Effect.gen(function*() {
369
367
  const fs = yield* FileSystem.FileSystem
370
368
  const pathService = yield* Path.Path
371
- const commandExecutor = yield* CommandExecutor.CommandExecutor
369
+ const childProcessSpawner = yield* ChildProcessSpawner.ChildProcessSpawner
372
370
  const paths = getPaths(pathService)
373
371
  const { confluenceDir, cwd, gitDir } = paths
374
372
 
375
373
  // Create context with captured services for providing to returned Effects
376
- const depsContext: Context.Context<FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor> = Context
377
- .empty().pipe(
378
- Context.add(FileSystem.FileSystem, fs),
379
- Context.add(Path.Path, pathService),
380
- Context.add(CommandExecutor.CommandExecutor, commandExecutor)
381
- )
374
+ const depsContext: Context.Context<FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner> =
375
+ Context
376
+ .empty().pipe(
377
+ Context.add(FileSystem.FileSystem, fs),
378
+ Context.add(Path.Path, pathService),
379
+ Context.add(ChildProcessSpawner.ChildProcessSpawner, childProcessSpawner)
380
+ )
382
381
 
383
382
  // Helper to provide deps to an effect - uses any for R since we know depsContext covers all needs
384
383
  const provideDeps = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E> =>
@@ -396,11 +395,7 @@ const make = Effect.gen(function*() {
396
395
  )
397
396
  )
398
397
 
399
- const isInitialized = () =>
400
- Effect.succeed(fs).pipe(
401
- Effect.flatMap((f) => f.exists(gitDir)),
402
- Effect.catchAll(() => Effect.succeed(false))
403
- )
398
+ const isInitialized = () => existsOrFalse(fs.exists(gitDir))
404
399
 
405
400
  const init = () =>
406
401
  provideDeps(
@@ -410,12 +405,12 @@ const make = Effect.gen(function*() {
410
405
  Effect.catchTag("GitError", () => Effect.fail(new GitNotInstalledError({ message: "Git not found" })))
411
406
  )
412
407
 
413
- const exists = yield* fs.exists(confluenceDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
408
+ const exists = yield* existsOrFalse(fs.exists(confluenceDir))
414
409
  if (!exists) {
415
410
  yield* fs.makeDirectory(confluenceDir, { recursive: true }).pipe(Effect.mapError(mapFsError))
416
411
  }
417
412
 
418
- const gitExists = yield* fs.exists(gitDir).pipe(Effect.catchAll(() => Effect.succeed(false)))
413
+ const gitExists = yield* existsOrFalse(fs.exists(gitDir))
419
414
  if (!gitExists) {
420
415
  yield* runGit(["init"], confluenceDir)
421
416
  // Configure local git user for commits (needed in CI environments)
@@ -583,7 +578,7 @@ const make = Effect.gen(function*() {
583
578
  const sourcePath = pathService.join(absoluteDocsPath, pattern)
584
579
  const destPath = pathService.join(confluenceDir, pattern)
585
580
 
586
- const exists = yield* fs.exists(sourcePath).pipe(Effect.catchAll(() => Effect.succeed(false)))
581
+ const exists = yield* existsOrFalse(fs.exists(sourcePath))
587
582
  if (exists) {
588
583
  const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
589
584
  if (stat.type === "Directory") {
@@ -614,7 +609,7 @@ const make = Effect.gen(function*() {
614
609
  const sourcePath = pathService.join(confluenceDir, pattern)
615
610
  const destPath = pathService.join(absoluteDocsPath, pattern)
616
611
 
617
- const exists = yield* fs.exists(sourcePath).pipe(Effect.catchAll(() => Effect.succeed(false)))
612
+ const exists = yield* existsOrFalse(fs.exists(sourcePath))
618
613
  if (exists) {
619
614
  const stat = yield* fs.stat(sourcePath).pipe(Effect.mapError(mapFsError))
620
615
  if (stat.type === "Directory") {
@@ -842,18 +837,13 @@ const make = Effect.gen(function*() {
842
837
  })
843
838
  })
844
839
 
845
- // Layer with deps - requires FileSystem, Path, CommandExecutor
846
- const layerWithDeps: Layer.Layer<
847
- GitService,
848
- never,
849
- FileSystem.FileSystem | Path.Path | CommandExecutor.CommandExecutor
850
- > = Layer.effect(GitService, make)
851
-
852
840
  /**
853
- * Create GitService layer with all platform dependencies.
841
+ * Create GitService layer.
854
842
  *
855
843
  * @category Layers
856
844
  */
857
- export const layer = layerWithDeps.pipe(
858
- Layer.provide(GitDepsLive)
859
- )
845
+ export const layer: Layer.Layer<
846
+ GitService,
847
+ never,
848
+ FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner
849
+ > = Layer.effect(GitService, make)
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import * as FileSystem from "@effect/platform/FileSystem"
7
- import * as Path from "@effect/platform/Path"
8
6
  import * as Context from "effect/Context"
9
7
  import * as Effect from "effect/Effect"
8
+ import * as FileSystem from "effect/FileSystem"
10
9
  import * as Layer from "effect/Layer"
10
+ import * as Path from "effect/Path"
11
11
  import type { ContentHash } from "./Brand.js"
12
12
  import type { FrontMatterError } from "./ConfluenceError.js"
13
13
  import { FileSystemError } from "./ConfluenceError.js"
@@ -59,9 +59,7 @@ export interface PageTreeNode {
59
59
  *
60
60
  * @category FileSystem
61
61
  */
62
- export class LocalFileSystem extends Context.Tag(
63
- "@knpkv/confluence-to-markdown/LocalFileSystem"
64
- )<
62
+ export class LocalFileSystem extends Context.Service<
65
63
  LocalFileSystem,
66
64
  {
67
65
  /**
@@ -135,7 +133,7 @@ export class LocalFileSystem extends Context.Tag(
135
133
  content: string
136
134
  ) => Effect.Effect<void, FileSystemError>
137
135
  }
138
- >() {}
136
+ >()("@knpkv/confluence-to-markdown/LocalFileSystem") {}
139
137
 
140
138
  /**
141
139
  * Layer that provides LocalFileSystem.
@@ -180,7 +178,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
180
178
  Effect.gen(function*() {
181
179
  const dir = pathService.dirname(filePath)
182
180
  yield* fs.makeDirectory(dir, { recursive: true }).pipe(
183
- Effect.catchAll(() => Effect.void)
181
+ Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
184
182
  )
185
183
 
186
184
  const serialized = serializeMarkdown(frontMatter, content)
@@ -257,7 +255,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
257
255
  Effect.gen(function*() {
258
256
  const dir = pathService.dirname(filePath)
259
257
  yield* fs.makeDirectory(dir, { recursive: true }).pipe(
260
- Effect.catchAll(() => Effect.void)
258
+ Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
261
259
  )
262
260
 
263
261
  // Atomic write: write to temp file, then rename
@@ -289,7 +287,7 @@ export const layer: Layer.Layer<LocalFileSystem, never, FileSystem.FileSystem |
289
287
  Effect.gen(function*() {
290
288
  const dir = pathService.dirname(filePath)
291
289
  yield* fs.makeDirectory(dir, { recursive: true }).pipe(
292
- Effect.catchAll(() => Effect.void)
290
+ Effect.mapError((cause) => new FileSystemError({ operation: "mkdir", path: dir, cause }))
293
291
  )
294
292
 
295
293
  const serialized = serializeNewPageMarkdown(frontMatter, content)
@@ -1,26 +1,30 @@
1
1
  /**
2
- * HTML to Markdown conversion service using AST-based approach.
2
+ * ADF Markdown conversion facade.
3
+ *
4
+ * Push (markdown → ADF) routes through the official `@atlaskit` markdown
5
+ * + JSON transformers and is strictly validated by `AdfSchemaValidator` —
6
+ * we author that side, so schema failures are bugs. Pull (ADF → markdown)
7
+ * routes through the in-package `AdfWalker`; incoming validation is advisory
8
+ * (logged, not thrown) because Confluence Cloud routinely emits documents the
9
+ * canonical schema lags behind.
3
10
  *
4
11
  * @module
5
12
  */
13
+ import type { DocNode } from "@atlaskit/adf-schema"
6
14
  import * as Context from "effect/Context"
7
15
  import * as Effect from "effect/Effect"
8
16
  import * as Layer from "effect/Layer"
9
17
  import * as Schema from "effect/Schema"
10
- import type { Document } from "./ast/Document.js"
18
+ import { revertPlaceholders } from "./AdfPlaceholders.js"
19
+ import { AdfSchemaValidator } from "./AdfSchemaValidator.js"
20
+ import { walk, type WalkerWarning } from "./AdfWalker.js"
21
+ import { AtlaskitTransformers } from "./AtlaskitTransformers.js"
22
+ import type { AdfSchemaError, AtlaskitTransformersError } from "./ConfluenceError.js"
11
23
  import { ConversionError } from "./ConfluenceError.js"
12
- import { parseConfluenceHtml } from "./parsers/ConfluenceParser.js"
13
- import { parseMarkdown } from "./parsers/MarkdownParser.js"
14
- import { ParseError, type SerializeError } from "./SchemaConverterError.js"
15
- import { ConfluenceToMarkdown, DocumentFromHast, DocumentFromMdast } from "./schemas/ConversionSchema.js"
16
- import { HastFromHtml } from "./schemas/hast/index.js"
17
- import { MdastFromMarkdown } from "./schemas/mdast/index.js"
18
- import { PreprocessedHtmlFromConfluence } from "./schemas/preprocessing/index.js"
19
- import { serializeToConfluence } from "./serializers/ConfluenceSerializer.js"
20
- import { type SerializeOptions, serializeToMarkdown } from "./serializers/MarkdownSerializer.js"
21
24
 
22
25
  /**
23
- * Markdown conversion service for HTML <-> GFM conversion.
26
+ * Markdown conversion service. Public surface is two delegating methods —
27
+ * `adfToMarkdown` (pull) and `markdownToAdf` (push).
24
28
  *
25
29
  * @example
26
30
  * ```typescript
@@ -29,163 +33,124 @@ import { type SerializeOptions, serializeToMarkdown } from "./serializers/Markdo
29
33
  *
30
34
  * const program = Effect.gen(function* () {
31
35
  * const converter = yield* MarkdownConverter
32
- * const md = yield* converter.htmlToMarkdown("<h1>Hello</h1><p>World</p>")
33
- * console.log(md) // # Hello\n\nWorld
36
+ * const md = yield* converter.adfToMarkdown(adfJson)
34
37
  * })
35
- *
36
- * Effect.runPromise(
37
- * program.pipe(Effect.provide(MarkdownConverter.layer))
38
- * )
39
38
  * ```
40
39
  *
41
40
  * @category Conversion
42
41
  */
43
- export class MarkdownConverter extends Context.Tag(
44
- "@knpkv/confluence-to-markdown/MarkdownConverter"
45
- )<
42
+ export class MarkdownConverter extends Context.Service<
46
43
  MarkdownConverter,
47
44
  {
48
45
  /**
49
- * Convert Confluence storage format (HTML) to GitHub Flavored Markdown.
50
- */
51
- readonly htmlToMarkdown: (
52
- html: string,
53
- options?: SerializeOptions
54
- ) => Effect.Effect<string, ConversionError>
55
-
56
- /**
57
- * Convert GitHub Flavored Markdown to HTML (Confluence storage format).
58
- */
59
- readonly markdownToHtml: (markdown: string) => Effect.Effect<string, ConversionError>
60
-
61
- /**
62
- * Parse Confluence HTML to Document AST.
63
- */
64
- readonly htmlToAst: (html: string) => Effect.Effect<Document, ParseError>
65
-
66
- /**
67
- * Parse Markdown to Document AST.
68
- */
69
- readonly markdownToAst: (markdown: string) => Effect.Effect<Document, ParseError>
70
-
71
- /**
72
- * Serialize Document AST to Confluence HTML.
46
+ * Convert an ADF JSON document (as wire-format string) to GitHub Flavored
47
+ * Markdown. Checks against the canonical @atlaskit/adf-schema before
48
+ * walking; violations are logged as warnings (remote drift), and only a
49
+ * document too malformed to walk at all fails with ConversionError.
73
50
  */
74
- readonly astToHtml: (doc: Document) => Effect.Effect<string, SerializeError>
51
+ readonly adfToMarkdown: (adfJson: string) => Effect.Effect<string, ConversionError>
75
52
 
76
53
  /**
77
- * Serialize Document AST to Markdown.
54
+ * Convert GitHub Flavored Markdown to a JSON-stringified ADF document.
55
+ * Routes through the official @atlaskit transformers; validates the
56
+ * produced ADF against the canonical schema before stringification.
78
57
  */
79
- readonly astToMarkdown: (doc: Document) => Effect.Effect<string, SerializeError>
58
+ readonly markdownToAdf: (markdown: string) => Effect.Effect<string, ConversionError>
59
+ }
60
+ >()("@knpkv/confluence-to-markdown/MarkdownConverter") {}
61
+
62
+ const warningSummary = (w: WalkerWarning): string => {
63
+ switch (w._tag) {
64
+ case "UnsupportedNode":
65
+ return `${w._tag} ${w.nodeType}`
66
+ case "LossyMark":
67
+ return `${w._tag} ${w.mark}`
68
+ case "MediaWithoutUrl":
69
+ return `${w._tag} ${w.mediaId}`
70
+ case "UnsupportedExtension":
71
+ return `${w._tag} ${w.nodeType} ${w.extensionKey || "?"}`
80
72
  }
81
- >() {}
73
+ }
74
+
75
+ const toConversionError = (
76
+ direction: "adfToMarkdown" | "markdownToAdf"
77
+ ) =>
78
+ (cause: AdfSchemaError | AtlaskitTransformersError | { readonly cause: unknown }): ConversionError =>
79
+ new ConversionError({ direction, cause })
80
+
81
+ // The least structure the walker needs: a doc node with a content array.
82
+ // Anything failing this isn't "schema drift", it's not an ADF document —
83
+ // advisory validation must not let it through (walking `null` is a defect;
84
+ // walking `{}` silently produces an empty page).
85
+ const isWalkableDoc = Schema.is(Schema.Struct({
86
+ type: Schema.Literal("doc"),
87
+ content: Schema.Array(Schema.Unknown)
88
+ }))
82
89
 
83
90
  /**
84
91
  * Layer that provides the MarkdownConverter service.
85
92
  *
86
93
  * @category Layers
87
94
  */
88
- export const layer: Layer.Layer<MarkdownConverter> = Layer.succeed(
95
+ export const layer: Layer.Layer<
89
96
  MarkdownConverter,
90
- MarkdownConverter.of({
91
- htmlToMarkdown: (html, options) =>
92
- Effect.gen(function*() {
93
- // Use AST-based approach to preserve colors, underlines, etc.
94
- const doc = yield* parseConfluenceHtml(html).pipe(
95
- Effect.mapError((e) => new ConversionError({ direction: "htmlToMarkdown", cause: e.message }))
96
- )
97
- return yield* serializeToMarkdown(doc, options).pipe(
98
- Effect.mapError((e) => new ConversionError({ direction: "htmlToMarkdown", cause: e.message }))
99
- )
100
- }),
97
+ never,
98
+ AtlaskitTransformers | AdfSchemaValidator
99
+ > = Layer.effect(
100
+ MarkdownConverter,
101
+ Effect.gen(function*() {
102
+ const transformers = yield* AtlaskitTransformers
103
+ const validator = yield* AdfSchemaValidator
101
104
 
102
- markdownToHtml: (markdown) =>
105
+ const adfToMarkdown = (adfJson: string): Effect.Effect<string, ConversionError> =>
103
106
  Effect.gen(function*() {
104
- // Use AST-based approach for consistency
105
- const doc = yield* parseMarkdown(markdown).pipe(
106
- Effect.mapError((e) => new ConversionError({ direction: "markdownToHtml", cause: e.message }))
107
- )
108
- return yield* serializeToConfluence(doc).pipe(
109
- Effect.mapError((e) => new ConversionError({ direction: "markdownToHtml", cause: e.message }))
107
+ const raw = yield* Effect.try({
108
+ try: () => JSON.parse(adfJson),
109
+ catch: (cause) => new ConversionError({ direction: "adfToMarkdown", cause })
110
+ })
111
+ // Incoming validation is advisory: the canonical @atlaskit schema is
112
+ // routinely stricter than what Confluence Cloud actually emits (old
113
+ // revisions, experimental nodes), so a failure here usually means
114
+ // "schema drift", not "broken document". Log + continue. Outgoing
115
+ // validation stays strict because we control that side.
116
+ const doc = yield* validator.check(raw, "incoming").pipe(
117
+ Effect.catchTag("AdfSchemaError", (err) =>
118
+ isWalkableDoc(raw)
119
+ ? Effect.gen(function*() {
120
+ yield* Effect.logWarning(
121
+ `adf schema (incoming): ${err.issues.length} issue(s); first: ${
122
+ err.issues.slice(0, 3).map((i) =>
123
+ `${i.instancePath ?? "?"} ${i.keyword ?? "?"} ${i.message ?? ""}`.trim()
124
+ ).join(" | ")
125
+ }`
126
+ )
127
+ return raw as DocNode
128
+ })
129
+ : Effect.fail(toConversionError("adfToMarkdown")(err)))
110
130
  )
111
- }),
112
-
113
- htmlToAst: (html) => parseConfluenceHtml(html),
114
-
115
- markdownToAst: (markdown) => parseMarkdown(markdown),
116
-
117
- astToHtml: (doc) => serializeToConfluence(doc),
118
-
119
- astToMarkdown: (doc) => serializeToMarkdown(doc)
120
- })
121
- )
122
-
123
- /**
124
- * Schema-based layer for MarkdownConverter using Effect Schema transforms.
125
- *
126
- * This is an alternative implementation that uses the new Schema-based
127
- * conversion pipeline. It provides the same API as the default layer.
128
- *
129
- * Note: For full fidelity, continue to use the default layer. This schema-based
130
- * layer is useful for simpler use cases or when you want to leverage Schema
131
- * composition.
132
- *
133
- * @example
134
- * ```typescript
135
- * import { MarkdownConverter, schemaBasedLayer } from "@knpkv/confluence-to-markdown/MarkdownConverter"
136
- * import { Effect } from "effect"
137
- *
138
- * const program = Effect.gen(function* () {
139
- * const converter = yield* MarkdownConverter
140
- * const md = yield* converter.htmlToMarkdown("<h1>Hello</h1>")
141
- * })
142
- *
143
- * Effect.runPromise(
144
- * program.pipe(Effect.provide(schemaBasedLayer))
145
- * )
146
- * ```
147
- *
148
- * @category Layers
149
- */
150
- export const schemaBasedLayer: Layer.Layer<MarkdownConverter> = Layer.succeed(
151
- MarkdownConverter,
152
- MarkdownConverter.of({
153
- // Note: Schema-based layer doesn't support includeRawSource option yet
154
- htmlToMarkdown: (html, options) =>
155
- Effect.gen(function*() {
156
- if (options?.includeRawSource !== undefined) {
157
- yield* Effect.logWarning("schemaBasedLayer: includeRawSource option is not supported, use default layer")
131
+ const { markdown, warnings } = walk(doc)
132
+ for (const w of warnings) {
133
+ yield* Effect.logWarning(`adf walker: ${warningSummary(w)}`, w)
158
134
  }
159
- return yield* Schema.decode(ConfluenceToMarkdown)(html)
160
- }).pipe(
161
- Effect.mapError((e) => new ConversionError({ direction: "htmlToMarkdown", cause: e.message }))
162
- ),
135
+ return markdown
136
+ })
163
137
 
164
- markdownToHtml: (markdown) =>
165
- Schema.encode(ConfluenceToMarkdown)(markdown).pipe(
166
- Effect.mapError((e) => new ConversionError({ direction: "markdownToHtml", cause: e.message }))
167
- ),
168
-
169
- htmlToAst: (html) =>
170
- Effect.gen(function*() {
171
- const preprocessed = yield* Schema.decode(PreprocessedHtmlFromConfluence)(html)
172
- const hast = yield* Schema.decode(HastFromHtml)(preprocessed)
173
- return yield* Schema.decode(DocumentFromHast)(hast)
174
- }).pipe(
175
- Effect.mapError((e) => new ParseError({ source: "confluence", message: e.message }))
176
- ),
177
-
178
- markdownToAst: (markdown) =>
138
+ const markdownToAdf = (markdown: string): Effect.Effect<string, ConversionError> =>
179
139
  Effect.gen(function*() {
180
- const mdast = yield* Schema.decode(MdastFromMarkdown)(markdown)
181
- return yield* Schema.decode(DocumentFromMdast)(mdast)
182
- }).pipe(
183
- Effect.mapError((e) => new ParseError({ source: "markdown", message: e.message }))
184
- ),
185
-
186
- // For serialization, continue using the existing serializers for full fidelity
187
- astToHtml: (doc) => serializeToConfluence(doc),
140
+ const adf = yield* transformers.use(({ json, md }) => json.encode(md.parse(markdown))).pipe(
141
+ Effect.mapError(toConversionError("markdownToAdf"))
142
+ )
143
+ // The walker emits HTML/comment placeholders for Confluence-only nodes
144
+ // (status, extension). @atlaskit's markdown transformer doesn't know
145
+ // these, so they come through as plain text. Rewrite them back into
146
+ // the structured nodes Confluence expects before validation.
147
+ const reverted = revertPlaceholders(adf)
148
+ const validated = yield* validator.check(reverted, "outgoing").pipe(
149
+ Effect.mapError(toConversionError("markdownToAdf"))
150
+ )
151
+ return JSON.stringify(validated)
152
+ })
188
153
 
189
- astToMarkdown: (doc) => serializeToMarkdown(doc)
154
+ return MarkdownConverter.of({ adfToMarkdown, markdownToAdf })
190
155
  })
191
156
  )
package/src/Schemas.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * @module
5
5
  */
6
+ import * as Effect from "effect/Effect"
6
7
  import * as Schema from "effect/Schema"
7
8
  import { ContentHashSchema, PageIdSchema, SpaceKeySchema } from "./Brand.js"
8
9
 
@@ -27,18 +28,18 @@ export const ConfluenceConfigFileSchema = Schema.Struct({
27
28
  rootPageId: PageIdSchema,
28
29
  /** Confluence Cloud base URL */
29
30
  baseUrl: Schema.String.pipe(
30
- Schema.pattern(/^https:\/\/[a-z0-9-]+\.atlassian\.net$/)
31
+ Schema.check(Schema.isPattern(/^https:\/\/[a-z0-9-]+\.atlassian\.net$/))
31
32
  ),
32
33
  /** Optional space key */
33
34
  spaceKey: Schema.optional(SpaceKeySchema),
34
35
  /** Local docs path (default: .confluence/docs) */
35
- docsPath: Schema.optionalWith(Schema.String, { default: () => ".confluence/docs" }),
36
+ docsPath: Schema.String.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(".confluence/docs"))),
36
37
  /** Glob patterns to exclude from sync */
37
- excludePatterns: Schema.optionalWith(Schema.Array(Schema.String), { default: () => [] }),
38
+ excludePatterns: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed([]))),
38
39
  /** Save original Confluence HTML alongside markdown (default: false) */
39
- saveSource: Schema.optionalWith(Schema.Boolean, { default: () => false }),
40
+ saveSource: Schema.Boolean.pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(false))),
40
41
  /** Glob patterns for files to track in git */
41
- trackedPaths: Schema.optionalWith(Schema.Array(Schema.String), { default: () => ["**/*.md"] })
42
+ trackedPaths: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultTypeKey(Effect.succeed(["**/*.md"])))
42
43
  })
43
44
 
44
45
  /**
@@ -71,9 +72,9 @@ export const PageFrontMatterSchema = Schema.Struct({
71
72
  /** Confluence page ID */
72
73
  pageId: PageIdSchema,
73
74
  /** Page version number */
74
- version: Schema.Number.pipe(Schema.int(), Schema.positive()),
75
+ version: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
75
76
  /** Page title */
76
- title: Schema.String.pipe(Schema.nonEmptyString()),
77
+ title: Schema.NonEmptyString,
77
78
  /** Last updated timestamp (ISO8601) */
78
79
  updated: Schema.DateFromString,
79
80
  /** Parent page ID (optional) */
@@ -104,7 +105,7 @@ export type PageFrontMatter = Schema.Schema.Type<typeof PageFrontMatterSchema>
104
105
  */
105
106
  export const NewPageFrontMatterSchema = Schema.Struct({
106
107
  /** Page title */
107
- title: Schema.String.pipe(Schema.nonEmptyString()),
108
+ title: Schema.NonEmptyString,
108
109
  /** Parent page ID (optional, determined by directory structure) */
109
110
  parentId: Schema.optional(PageIdSchema)
110
111
  })
@@ -125,9 +126,9 @@ export const SyncStateSchema = Schema.Struct({
125
126
  /** Last sync timestamp */
126
127
  lastSync: Schema.DateFromString,
127
128
  /** Map of page ID to sync info */
128
- pages: Schema.Record({
129
- key: Schema.String,
130
- value: Schema.Struct({
129
+ pages: Schema.Record(
130
+ Schema.String,
131
+ Schema.Struct({
131
132
  /** Local file path */
132
133
  localPath: Schema.String,
133
134
  /** Last synced version */
@@ -135,7 +136,7 @@ export const SyncStateSchema = Schema.Struct({
135
136
  /** Content hash at last sync */
136
137
  contentHash: ContentHashSchema
137
138
  })
138
- })
139
+ )
139
140
  })
140
141
 
141
142
  /**
@@ -163,7 +164,7 @@ export const PageResponseSchema = Schema.Struct({
163
164
  }),
164
165
  body: Schema.optional(
165
166
  Schema.Struct({
166
- storage: Schema.optional(
167
+ atlas_doc_format: Schema.optional(
167
168
  Schema.Struct({
168
169
  value: Schema.String,
169
170
  representation: Schema.optional(Schema.String)
@@ -204,7 +205,7 @@ export const PageListItemSchema = Schema.Struct({
204
205
  })),
205
206
  body: Schema.optional(
206
207
  Schema.Struct({
207
- storage: Schema.optional(
208
+ atlas_doc_format: Schema.optional(
208
209
  Schema.Struct({
209
210
  value: Schema.String,
210
211
  representation: Schema.optional(Schema.String)
@@ -377,7 +378,7 @@ export const PageVersionSchema = Schema.Struct({
377
378
  title: Schema.optional(Schema.String),
378
379
  body: Schema.optional(
379
380
  Schema.Struct({
380
- storage: Schema.optional(
381
+ atlas_doc_format: Schema.optional(
381
382
  Schema.Struct({
382
383
  value: Schema.String,
383
384
  representation: Schema.optional(Schema.String)
@@ -413,7 +414,7 @@ export const PageVersionContentSchema = Schema.Struct({
413
414
  /** Page content */
414
415
  body: Schema.optional(
415
416
  Schema.Struct({
416
- storage: Schema.optional(
417
+ atlas_doc_format: Schema.optional(
417
418
  Schema.Struct({
418
419
  value: Schema.String,
419
420
  representation: Schema.optional(Schema.String)