@knpkv/confluence-to-markdown 0.6.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 (357) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/LICENSE +21 -0
  3. package/README.md +22 -13
  4. package/dist/AdfPlaceholders.d.ts +42 -0
  5. package/dist/AdfPlaceholders.d.ts.map +1 -0
  6. package/dist/AdfPlaceholders.js +547 -0
  7. package/dist/AdfPlaceholders.js.map +1 -0
  8. package/dist/AdfSchemaValidator.d.ts +37 -0
  9. package/dist/AdfSchemaValidator.d.ts.map +1 -0
  10. package/dist/AdfSchemaValidator.js +37 -0
  11. package/dist/AdfSchemaValidator.js.map +1 -0
  12. package/dist/AdfWalker.d.ts +39 -0
  13. package/dist/AdfWalker.d.ts.map +1 -0
  14. package/dist/AdfWalker.js +527 -0
  15. package/dist/AdfWalker.js.map +1 -0
  16. package/dist/AtlaskitTransformers.d.ts +35 -0
  17. package/dist/AtlaskitTransformers.d.ts.map +1 -0
  18. package/dist/AtlaskitTransformers.js +48 -0
  19. package/dist/AtlaskitTransformers.js.map +1 -0
  20. package/dist/Brand.d.ts +6 -6
  21. package/dist/Brand.d.ts.map +1 -1
  22. package/dist/Brand.js +8 -6
  23. package/dist/Brand.js.map +1 -1
  24. package/dist/ConfluenceAuth.d.ts +4 -4
  25. package/dist/ConfluenceAuth.d.ts.map +1 -1
  26. package/dist/ConfluenceAuth.js +37 -39
  27. package/dist/ConfluenceAuth.js.map +1 -1
  28. package/dist/ConfluenceClient.d.ts +7 -17
  29. package/dist/ConfluenceClient.d.ts.map +1 -1
  30. package/dist/ConfluenceClient.js +81 -38
  31. package/dist/ConfluenceClient.js.map +1 -1
  32. package/dist/ConfluenceConfig.d.ts +3 -3
  33. package/dist/ConfluenceConfig.d.ts.map +1 -1
  34. package/dist/ConfluenceConfig.js +13 -11
  35. package/dist/ConfluenceConfig.js.map +1 -1
  36. package/dist/ConfluenceError.d.ts +68 -16
  37. package/dist/ConfluenceError.d.ts.map +1 -1
  38. package/dist/ConfluenceError.js +30 -1
  39. package/dist/ConfluenceError.js.map +1 -1
  40. package/dist/GitError.d.ts +5 -5
  41. package/dist/GitService.d.ts +11 -3
  42. package/dist/GitService.d.ts.map +1 -1
  43. package/dist/GitService.js +22 -27
  44. package/dist/GitService.js.map +1 -1
  45. package/dist/LocalFileSystem.d.ts +3 -3
  46. package/dist/LocalFileSystem.d.ts.map +1 -1
  47. package/dist/LocalFileSystem.js +6 -6
  48. package/dist/LocalFileSystem.js.map +1 -1
  49. package/dist/MarkdownConverter.d.ts +16 -65
  50. package/dist/MarkdownConverter.d.ts.map +1 -1
  51. package/dist/MarkdownConverter.js +64 -85
  52. package/dist/MarkdownConverter.js.map +1 -1
  53. package/dist/Schemas.d.ts +128 -141
  54. package/dist/Schemas.d.ts.map +1 -1
  55. package/dist/Schemas.js +21 -23
  56. package/dist/Schemas.js.map +1 -1
  57. package/dist/SyncEngine.d.ts +8 -5
  58. package/dist/SyncEngine.d.ts.map +1 -1
  59. package/dist/SyncEngine.js +189 -113
  60. package/dist/SyncEngine.js.map +1 -1
  61. package/dist/bin.js +23 -35
  62. package/dist/bin.js.map +1 -1
  63. package/dist/commands/auth.d.ts +2 -14
  64. package/dist/commands/auth.d.ts.map +1 -1
  65. package/dist/commands/auth.js +11 -16
  66. package/dist/commands/auth.js.map +1 -1
  67. package/dist/commands/clone.d.ts +4 -6
  68. package/dist/commands/clone.d.ts.map +1 -1
  69. package/dist/commands/clone.js +34 -32
  70. package/dist/commands/clone.js.map +1 -1
  71. package/dist/commands/delete.d.ts +2 -10
  72. package/dist/commands/delete.d.ts.map +1 -1
  73. package/dist/commands/delete.js +5 -4
  74. package/dist/commands/delete.js.map +1 -1
  75. package/dist/commands/errorHandler.d.ts +2 -1
  76. package/dist/commands/errorHandler.d.ts.map +1 -1
  77. package/dist/commands/errorHandler.js +22 -15
  78. package/dist/commands/errorHandler.js.map +1 -1
  79. package/dist/commands/fetch.d.ts +27 -0
  80. package/dist/commands/fetch.d.ts.map +1 -0
  81. package/dist/commands/fetch.js +48 -0
  82. package/dist/commands/fetch.js.map +1 -0
  83. package/dist/commands/git.d.ts +7 -10
  84. package/dist/commands/git.d.ts.map +1 -1
  85. package/dist/commands/git.js +6 -6
  86. package/dist/commands/git.js.map +1 -1
  87. package/dist/commands/index.d.ts +1 -0
  88. package/dist/commands/index.d.ts.map +1 -1
  89. package/dist/commands/index.js +1 -0
  90. package/dist/commands/index.js.map +1 -1
  91. package/dist/commands/layers.d.ts +10 -9
  92. package/dist/commands/layers.d.ts.map +1 -1
  93. package/dist/commands/layers.js +41 -30
  94. package/dist/commands/layers.js.map +1 -1
  95. package/dist/commands/new.d.ts +2 -6
  96. package/dist/commands/new.d.ts.map +1 -1
  97. package/dist/commands/new.js +5 -4
  98. package/dist/commands/new.js.map +1 -1
  99. package/dist/commands/pageInput.d.ts +19 -0
  100. package/dist/commands/pageInput.d.ts.map +1 -0
  101. package/dist/commands/pageInput.js +68 -0
  102. package/dist/commands/pageInput.js.map +1 -0
  103. package/dist/commands/root.d.ts +8 -0
  104. package/dist/commands/root.d.ts.map +1 -0
  105. package/dist/commands/root.js +29 -0
  106. package/dist/commands/root.js.map +1 -0
  107. package/dist/commands/sync.d.ts +6 -9
  108. package/dist/commands/sync.d.ts.map +1 -1
  109. package/dist/commands/sync.js +5 -6
  110. package/dist/commands/sync.js.map +1 -1
  111. package/dist/index.d.ts +3 -8
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +2 -13
  114. package/dist/index.js.map +1 -1
  115. package/dist/internal/NodeLayers.d.ts.map +1 -1
  116. package/dist/internal/NodeLayers.js +1 -2
  117. package/dist/internal/NodeLayers.js.map +1 -1
  118. package/dist/internal/adfMetadata.d.ts +30 -0
  119. package/dist/internal/adfMetadata.d.ts.map +1 -0
  120. package/dist/internal/adfMetadata.js +126 -0
  121. package/dist/internal/adfMetadata.js.map +1 -0
  122. package/dist/internal/cleanMarkdown.d.ts +5 -0
  123. package/dist/internal/cleanMarkdown.d.ts.map +1 -0
  124. package/dist/internal/cleanMarkdown.js +13 -0
  125. package/dist/internal/cleanMarkdown.js.map +1 -0
  126. package/dist/internal/frontmatter.d.ts.map +1 -1
  127. package/dist/internal/frontmatter.js +41 -8
  128. package/dist/internal/frontmatter.js.map +1 -1
  129. package/dist/internal/gitCommands.d.ts +9 -3
  130. package/dist/internal/gitCommands.d.ts.map +1 -1
  131. package/dist/internal/gitCommands.js +18 -9
  132. package/dist/internal/gitCommands.js.map +1 -1
  133. package/dist/internal/hashUtils.d.ts +1 -1
  134. package/dist/internal/hashUtils.d.ts.map +1 -1
  135. package/dist/internal/hashUtils.js +1 -1
  136. package/dist/internal/hashUtils.js.map +1 -1
  137. package/dist/internal/oauthServer.d.ts +10 -5
  138. package/dist/internal/oauthServer.d.ts.map +1 -1
  139. package/dist/internal/oauthServer.js +19 -40
  140. package/dist/internal/oauthServer.js.map +1 -1
  141. package/dist/internal/pathUtils.d.ts +1 -1
  142. package/dist/internal/pathUtils.d.ts.map +1 -1
  143. package/dist/internal/pathUtils.js +1 -1
  144. package/dist/internal/pathUtils.js.map +1 -1
  145. package/dist/internal/process.d.ts +15 -0
  146. package/dist/internal/process.d.ts.map +1 -0
  147. package/dist/internal/process.js +10 -0
  148. package/dist/internal/process.js.map +1 -0
  149. package/dist/internal/stdio.d.ts +6 -0
  150. package/dist/internal/stdio.d.ts.map +1 -0
  151. package/dist/internal/stdio.js +15 -0
  152. package/dist/internal/stdio.js.map +1 -0
  153. package/dist/internal/tokenStorage.d.ts +3 -13
  154. package/dist/internal/tokenStorage.d.ts.map +1 -1
  155. package/dist/internal/tokenStorage.js +26 -24
  156. package/dist/internal/tokenStorage.js.map +1 -1
  157. package/dist/internal/userCache.d.ts +1 -1
  158. package/dist/internal/userCache.d.ts.map +1 -1
  159. package/dist/internal/userCache.js +1 -1
  160. package/dist/internal/userCache.js.map +1 -1
  161. package/package.json +30 -30
  162. package/skills/confluence/SKILL.md +143 -0
  163. package/skills/confluence/agents/openai.yaml +4 -0
  164. package/src/AdfPlaceholders.ts +310 -13
  165. package/src/AdfSchemaValidator.ts +2 -4
  166. package/src/AdfWalker.ts +122 -42
  167. package/src/AtlaskitTransformers.ts +2 -4
  168. package/src/Brand.ts +11 -16
  169. package/src/ConfluenceAuth.ts +22 -30
  170. package/src/ConfluenceClient.ts +24 -20
  171. package/src/ConfluenceConfig.ts +14 -14
  172. package/src/GitService.ts +39 -49
  173. package/src/LocalFileSystem.ts +7 -9
  174. package/src/MarkdownConverter.ts +2 -4
  175. package/src/Schemas.ts +13 -12
  176. package/src/SyncEngine.ts +151 -53
  177. package/src/bin.ts +30 -56
  178. package/src/commands/auth.ts +21 -18
  179. package/src/commands/clone.ts +38 -37
  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 +53 -33
  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/internal/NodeLayers.ts +1 -2
  191. package/src/internal/adfMetadata.ts +145 -0
  192. package/src/internal/cleanMarkdown.ts +15 -0
  193. package/src/internal/frontmatter.ts +45 -8
  194. package/src/internal/gitCommands.ts +23 -17
  195. package/src/internal/hashUtils.ts +2 -2
  196. package/src/internal/oauthServer.ts +84 -105
  197. package/src/internal/pathUtils.ts +1 -1
  198. package/src/internal/process.ts +15 -0
  199. package/src/internal/stdio.ts +22 -0
  200. package/src/internal/tokenStorage.ts +39 -29
  201. package/src/internal/userCache.ts +2 -2
  202. package/test/AdfPlaceholders.test.ts +213 -0
  203. package/test/AdfSchemaValidator.test.ts +6 -6
  204. package/test/AdfWalker.test.ts +167 -21
  205. package/test/AtlaskitTransformers.test.ts +4 -4
  206. package/test/Brand.test.ts +11 -11
  207. package/test/GitService.test.ts +6 -2
  208. package/test/MarkdownConverter.test.ts +12 -11
  209. package/test/RoundTrip.test.ts +258 -3
  210. package/test/Schemas.test.ts +40 -40
  211. package/test/adfMetadata.test.ts +110 -0
  212. package/test/cleanMarkdown.test.ts +36 -0
  213. package/test/commandHarness.test.ts +79 -0
  214. package/test/commandHarness.ts +147 -0
  215. package/test/fetch.test.ts +61 -0
  216. package/test/frontmatter.test.ts +41 -0
  217. package/test/integration.test.ts +569 -156
  218. package/test/layers.test.ts +12 -0
  219. package/test/oauthServer.test.ts +4 -5
  220. package/test/pageInput.test.ts +83 -0
  221. package/test/tokenStorage.test.ts +17 -17
  222. package/dist/SchemaConverterError.d.ts +0 -108
  223. package/dist/SchemaConverterError.d.ts.map +0 -1
  224. package/dist/SchemaConverterError.js +0 -84
  225. package/dist/SchemaConverterError.js.map +0 -1
  226. package/dist/ast/BlockNode.d.ts +0 -468
  227. package/dist/ast/BlockNode.d.ts.map +0 -1
  228. package/dist/ast/BlockNode.js +0 -319
  229. package/dist/ast/BlockNode.js.map +0 -1
  230. package/dist/ast/Document.d.ts +0 -244
  231. package/dist/ast/Document.d.ts.map +0 -1
  232. package/dist/ast/Document.js +0 -69
  233. package/dist/ast/Document.js.map +0 -1
  234. package/dist/ast/InlineNode.d.ts +0 -477
  235. package/dist/ast/InlineNode.d.ts.map +0 -1
  236. package/dist/ast/InlineNode.js +0 -263
  237. package/dist/ast/InlineNode.js.map +0 -1
  238. package/dist/ast/MacroNode.d.ts +0 -267
  239. package/dist/ast/MacroNode.d.ts.map +0 -1
  240. package/dist/ast/MacroNode.js +0 -164
  241. package/dist/ast/MacroNode.js.map +0 -1
  242. package/dist/ast/index.d.ts +0 -10
  243. package/dist/ast/index.d.ts.map +0 -1
  244. package/dist/ast/index.js +0 -14
  245. package/dist/ast/index.js.map +0 -1
  246. package/dist/parsers/ConfluenceParser.d.ts +0 -26
  247. package/dist/parsers/ConfluenceParser.d.ts.map +0 -1
  248. package/dist/parsers/ConfluenceParser.js +0 -792
  249. package/dist/parsers/ConfluenceParser.js.map +0 -1
  250. package/dist/parsers/MarkdownParser.d.ts +0 -26
  251. package/dist/parsers/MarkdownParser.d.ts.map +0 -1
  252. package/dist/parsers/MarkdownParser.js +0 -873
  253. package/dist/parsers/MarkdownParser.js.map +0 -1
  254. package/dist/parsers/index.d.ts +0 -8
  255. package/dist/parsers/index.d.ts.map +0 -1
  256. package/dist/parsers/index.js +0 -8
  257. package/dist/parsers/index.js.map +0 -1
  258. package/dist/parsers/preprocessing/ConfluencePreprocessing.d.ts +0 -23
  259. package/dist/parsers/preprocessing/ConfluencePreprocessing.d.ts.map +0 -1
  260. package/dist/parsers/preprocessing/ConfluencePreprocessing.js +0 -323
  261. package/dist/parsers/preprocessing/ConfluencePreprocessing.js.map +0 -1
  262. package/dist/parsers/preprocessing/index.d.ts +0 -7
  263. package/dist/parsers/preprocessing/index.d.ts.map +0 -1
  264. package/dist/parsers/preprocessing/index.js +0 -7
  265. package/dist/parsers/preprocessing/index.js.map +0 -1
  266. package/dist/schemas/ConfluenceSchema.d.ts +0 -21
  267. package/dist/schemas/ConfluenceSchema.d.ts.map +0 -1
  268. package/dist/schemas/ConfluenceSchema.js +0 -38
  269. package/dist/schemas/ConfluenceSchema.js.map +0 -1
  270. package/dist/schemas/ConversionSchema.d.ts +0 -35
  271. package/dist/schemas/ConversionSchema.d.ts.map +0 -1
  272. package/dist/schemas/ConversionSchema.js +0 -208
  273. package/dist/schemas/ConversionSchema.js.map +0 -1
  274. package/dist/schemas/MarkdownSchema.d.ts +0 -21
  275. package/dist/schemas/MarkdownSchema.d.ts.map +0 -1
  276. package/dist/schemas/MarkdownSchema.js +0 -38
  277. package/dist/schemas/MarkdownSchema.js.map +0 -1
  278. package/dist/schemas/hast/HastFromHtml.d.ts +0 -27
  279. package/dist/schemas/hast/HastFromHtml.d.ts.map +0 -1
  280. package/dist/schemas/hast/HastFromHtml.js +0 -107
  281. package/dist/schemas/hast/HastFromHtml.js.map +0 -1
  282. package/dist/schemas/hast/HastSchema.d.ts +0 -195
  283. package/dist/schemas/hast/HastSchema.d.ts.map +0 -1
  284. package/dist/schemas/hast/HastSchema.js +0 -183
  285. package/dist/schemas/hast/HastSchema.js.map +0 -1
  286. package/dist/schemas/hast/index.d.ts +0 -9
  287. package/dist/schemas/hast/index.d.ts.map +0 -1
  288. package/dist/schemas/hast/index.js +0 -3
  289. package/dist/schemas/hast/index.js.map +0 -1
  290. package/dist/schemas/index.d.ts +0 -14
  291. package/dist/schemas/index.d.ts.map +0 -1
  292. package/dist/schemas/index.js +0 -16
  293. package/dist/schemas/index.js.map +0 -1
  294. package/dist/schemas/mdast/MdastFromMarkdown.d.ts +0 -30
  295. package/dist/schemas/mdast/MdastFromMarkdown.d.ts.map +0 -1
  296. package/dist/schemas/mdast/MdastFromMarkdown.js +0 -79
  297. package/dist/schemas/mdast/MdastFromMarkdown.js.map +0 -1
  298. package/dist/schemas/mdast/MdastSchema.d.ts +0 -385
  299. package/dist/schemas/mdast/MdastSchema.d.ts.map +0 -1
  300. package/dist/schemas/mdast/MdastSchema.js +0 -266
  301. package/dist/schemas/mdast/MdastSchema.js.map +0 -1
  302. package/dist/schemas/mdast/index.d.ts +0 -10
  303. package/dist/schemas/mdast/index.d.ts.map +0 -1
  304. package/dist/schemas/mdast/index.js +0 -4
  305. package/dist/schemas/mdast/index.js.map +0 -1
  306. package/dist/schemas/mdast/mdastToString.d.ts +0 -13
  307. package/dist/schemas/mdast/mdastToString.d.ts.map +0 -1
  308. package/dist/schemas/mdast/mdastToString.js +0 -85
  309. package/dist/schemas/mdast/mdastToString.js.map +0 -1
  310. package/dist/schemas/nodes/block/BlockSchema.d.ts +0 -43
  311. package/dist/schemas/nodes/block/BlockSchema.d.ts.map +0 -1
  312. package/dist/schemas/nodes/block/BlockSchema.js +0 -634
  313. package/dist/schemas/nodes/block/BlockSchema.js.map +0 -1
  314. package/dist/schemas/nodes/block/index.d.ts +0 -7
  315. package/dist/schemas/nodes/block/index.d.ts.map +0 -1
  316. package/dist/schemas/nodes/block/index.js +0 -7
  317. package/dist/schemas/nodes/block/index.js.map +0 -1
  318. package/dist/schemas/nodes/index.d.ts +0 -9
  319. package/dist/schemas/nodes/index.d.ts.map +0 -1
  320. package/dist/schemas/nodes/index.js +0 -12
  321. package/dist/schemas/nodes/index.js.map +0 -1
  322. package/dist/schemas/nodes/inline/InlineSchema.d.ts +0 -48
  323. package/dist/schemas/nodes/inline/InlineSchema.d.ts.map +0 -1
  324. package/dist/schemas/nodes/inline/InlineSchema.js +0 -436
  325. package/dist/schemas/nodes/inline/InlineSchema.js.map +0 -1
  326. package/dist/schemas/nodes/inline/index.d.ts +0 -7
  327. package/dist/schemas/nodes/inline/index.d.ts.map +0 -1
  328. package/dist/schemas/nodes/inline/index.js +0 -7
  329. package/dist/schemas/nodes/inline/index.js.map +0 -1
  330. package/dist/schemas/nodes/macro/MacroSchema.d.ts +0 -27
  331. package/dist/schemas/nodes/macro/MacroSchema.d.ts.map +0 -1
  332. package/dist/schemas/nodes/macro/MacroSchema.js +0 -162
  333. package/dist/schemas/nodes/macro/MacroSchema.js.map +0 -1
  334. package/dist/schemas/nodes/macro/index.d.ts +0 -7
  335. package/dist/schemas/nodes/macro/index.d.ts.map +0 -1
  336. package/dist/schemas/nodes/macro/index.js +0 -7
  337. package/dist/schemas/nodes/macro/index.js.map +0 -1
  338. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts +0 -53
  339. package/dist/schemas/preprocessing/ConfluencePreprocessor.d.ts.map +0 -1
  340. package/dist/schemas/preprocessing/ConfluencePreprocessor.js +0 -349
  341. package/dist/schemas/preprocessing/ConfluencePreprocessor.js.map +0 -1
  342. package/dist/schemas/preprocessing/index.d.ts +0 -8
  343. package/dist/schemas/preprocessing/index.d.ts.map +0 -1
  344. package/dist/schemas/preprocessing/index.js +0 -2
  345. package/dist/schemas/preprocessing/index.js.map +0 -1
  346. package/dist/serializers/ConfluenceSerializer.d.ts +0 -30
  347. package/dist/serializers/ConfluenceSerializer.d.ts.map +0 -1
  348. package/dist/serializers/ConfluenceSerializer.js +0 -551
  349. package/dist/serializers/ConfluenceSerializer.js.map +0 -1
  350. package/dist/serializers/MarkdownSerializer.d.ts +0 -34
  351. package/dist/serializers/MarkdownSerializer.d.ts.map +0 -1
  352. package/dist/serializers/MarkdownSerializer.js +0 -355
  353. package/dist/serializers/MarkdownSerializer.js.map +0 -1
  354. package/dist/serializers/index.d.ts +0 -8
  355. package/dist/serializers/index.d.ts.map +0 -1
  356. package/dist/serializers/index.js +0 -8
  357. package/dist/serializers/index.js.map +0 -1
@@ -3,6 +3,7 @@ import { revertPlaceholders } from "../src/AdfPlaceholders.js"
3
3
 
4
4
  const docOf = (content: ReadonlyArray<unknown>) => ({ version: 1, type: "doc", content })
5
5
  const para = (text: string) => ({ type: "paragraph", content: [{ type: "text", text }] })
6
+ const b64 = (value: unknown): string => Buffer.from(JSON.stringify(value)).toString("base64")
6
7
 
7
8
  describe("revertPlaceholders", () => {
8
9
  it("rewrites a status span placeholder into a status node", () => {
@@ -31,6 +32,53 @@ describe("revertPlaceholders", () => {
31
32
  })
32
33
  })
33
34
 
35
+ it("rewrites native TOC syntax into a Confluence core extension node", () => {
36
+ const out = revertPlaceholders(docOf([para("[[toc]]")])) as {
37
+ content: Array<{ type: string; attrs?: Record<string, unknown> }>
38
+ }
39
+
40
+ expect(out.content[0]).toEqual({
41
+ type: "extension",
42
+ attrs: {
43
+ extensionKey: "toc",
44
+ extensionType: "com.atlassian.confluence.macro.core"
45
+ }
46
+ })
47
+ })
48
+
49
+ it("rewrites native TOC syntax with levels into macro parameters", () => {
50
+ const out = revertPlaceholders(docOf([para("[[toc:min=2,max=4]]")])) as {
51
+ content: Array<{ type: string; attrs?: Record<string, unknown> }>
52
+ }
53
+
54
+ expect(out.content[0]).toEqual({
55
+ type: "extension",
56
+ attrs: {
57
+ extensionKey: "toc",
58
+ extensionType: "com.atlassian.confluence.macro.core",
59
+ parameters: {
60
+ macroParams: {
61
+ minLevel: { value: "2" },
62
+ maxLevel: { value: "4" }
63
+ }
64
+ }
65
+ }
66
+ })
67
+ })
68
+
69
+ it("leaves invalid or code-marked native TOC syntax as text", () => {
70
+ const invalid = revertPlaceholders(docOf([para("[[toc:min=0]]")])) as {
71
+ content: Array<{ type: string; content?: ReadonlyArray<unknown> }>
72
+ }
73
+ const quoted = revertPlaceholders(docOf([{
74
+ type: "paragraph",
75
+ content: [{ type: "text", text: "[[toc]]", marks: [{ type: "code" }] }]
76
+ }])) as { content: Array<{ type: string; content?: ReadonlyArray<unknown> }> }
77
+
78
+ expect(invalid.content[0]!.type).toBe("paragraph")
79
+ expect(quoted.content[0]!.type).toBe("paragraph")
80
+ })
81
+
34
82
  it("rewrites status and extension placeholders inside table cells", () => {
35
83
  const cell = (text: string) => ({
36
84
  type: "tableCell",
@@ -85,6 +133,67 @@ describe("revertPlaceholders", () => {
85
133
  })
86
134
  })
87
135
 
136
+ it("rewrites fallback inline formatting HTML into native marks", () => {
137
+ const out = revertPlaceholders(
138
+ docOf([para(
139
+ `Plain <u>underline</u>, H<sub>2</sub>O, x<sup>2</sup>, ` +
140
+ `<span style="color:#ff5630">Colored text</span>, ` +
141
+ `<span style="background-color:#f8e6a0">highlighted text</span>.`
142
+ )])
143
+ ) as {
144
+ content: Array<{
145
+ content: Array<{ type: string; text?: string; marks?: ReadonlyArray<{ type: string; attrs?: unknown }> }>
146
+ }>
147
+ }
148
+
149
+ const inlineContent = out.content[0]!.content
150
+ expect(inlineContent).toContainEqual({
151
+ type: "text",
152
+ text: "underline",
153
+ marks: [{ type: "underline" }]
154
+ })
155
+ expect(inlineContent).toContainEqual({
156
+ type: "text",
157
+ text: "2",
158
+ marks: [{ type: "subsup", attrs: { type: "sub" } }]
159
+ })
160
+ expect(inlineContent).toContainEqual({
161
+ type: "text",
162
+ text: "2",
163
+ marks: [{ type: "subsup", attrs: { type: "sup" } }]
164
+ })
165
+ expect(inlineContent).toContainEqual({
166
+ type: "text",
167
+ text: "Colored text",
168
+ marks: [{ type: "textColor", attrs: { color: "#ff5630" } }]
169
+ })
170
+ expect(inlineContent).toContainEqual({
171
+ type: "text",
172
+ text: "highlighted text",
173
+ marks: [{ type: "backgroundColor", attrs: { color: "#f8e6a0" } }]
174
+ })
175
+ })
176
+
177
+ it("rewrites inlineCard placeholders into native smart-link nodes", () => {
178
+ const attrs = { url: "https://www.atlassian.com" }
179
+ const out = revertPlaceholders(
180
+ docOf([para(`Inline smart link: <!-- adf:inlineCard attrs=${b64(attrs)} -->.`)])
181
+ ) as { content: Array<{ content: Array<{ type: string; attrs?: Record<string, unknown> }> }> }
182
+
183
+ expect(out.content[0]!.content[1]).toEqual({ type: "inlineCard", attrs })
184
+ })
185
+
186
+ it("rewrites encoded date and emoji placeholders into native inline nodes", () => {
187
+ const date = { type: "date", attrs: { timestamp: "1782259200000" } }
188
+ const emoji = { type: "emoji", attrs: { shortName: ":white_check_mark:", text: "✅" } }
189
+ const out = revertPlaceholders(
190
+ docOf([para(`Example <!-- adf:date node=${b64(date)} --> <!-- adf:emoji node=${b64(emoji)} -->`)])
191
+ ) as { content: Array<{ content: Array<unknown> }> }
192
+
193
+ expect(out.content[0]!.content).toContainEqual(date)
194
+ expect(out.content[0]!.content).toContainEqual(emoji)
195
+ })
196
+
88
197
  it("restores the full attrs (parameters included) from an attrs blob", () => {
89
198
  const attrs = {
90
199
  extensionKey: "toc",
@@ -135,6 +244,110 @@ describe("revertPlaceholders", () => {
135
244
  expect(out.content[1]).toEqual(para("after"))
136
245
  })
137
246
 
247
+ it("re-attaches the blocks between panel markers as a panel body", () => {
248
+ const attrs = { panelType: "warning" }
249
+ const blob = Buffer.from(JSON.stringify(attrs)).toString("base64")
250
+ const out = revertPlaceholders(
251
+ docOf([
252
+ para(`<!-- adf:panel type=warning attrs=${blob} -->`),
253
+ para("panel body"),
254
+ para(`<!-- adf:/panel -->`),
255
+ para("after")
256
+ ])
257
+ ) as { content: Array<{ type: string; attrs?: Record<string, unknown>; content?: ReadonlyArray<unknown> }> }
258
+
259
+ expect(out.content).toHaveLength(2)
260
+ expect(out.content[0]).toEqual({
261
+ type: "panel",
262
+ attrs,
263
+ content: [para("panel body")]
264
+ })
265
+ expect(out.content[1]).toEqual(para("after"))
266
+ })
267
+
268
+ it("re-attaches paragraph-level marks from paragraph markers", () => {
269
+ const marks = [{ type: "alignment", attrs: { align: "center" } }]
270
+ const out = revertPlaceholders(
271
+ docOf([
272
+ para(`<!-- adf:paragraph marks=${b64(marks)} -->`),
273
+ para("Centered paragraph for alignment validation."),
274
+ para(`<!-- adf:/paragraph -->`)
275
+ ])
276
+ ) as { content: Array<{ type: string; marks?: unknown; content?: ReadonlyArray<unknown> }> }
277
+
278
+ expect(out.content).toEqual([{
279
+ type: "paragraph",
280
+ marks,
281
+ content: [{ type: "text", text: "Centered paragraph for alignment validation." }]
282
+ }])
283
+ })
284
+
285
+ it("restores encoded native block nodes", () => {
286
+ const taskList = {
287
+ type: "taskList",
288
+ attrs: { localId: "tasks-1" },
289
+ content: [{
290
+ type: "taskItem",
291
+ attrs: { localId: "task-1", state: "DONE" },
292
+ content: [{ type: "text", text: "Existing primitive coverage reviewed" }]
293
+ }]
294
+ }
295
+ const decisionList = {
296
+ type: "decisionList",
297
+ attrs: { localId: "decisions-1" },
298
+ content: [{
299
+ type: "decisionItem",
300
+ attrs: { localId: "decision-1", state: "DECIDED" },
301
+ content: [{ type: "text", text: "Decide whether to maintain a separate asset for advanced macros." }]
302
+ }]
303
+ }
304
+ const expand = {
305
+ type: "expand",
306
+ attrs: { title: "Expandable supplementary content" },
307
+ content: [para("This section can be expanded.")]
308
+ }
309
+ const table = {
310
+ type: "table",
311
+ content: [{ type: "tableRow", content: [{ type: "tableCell", content: [para("Date")] }] }]
312
+ }
313
+ const layoutSection = {
314
+ type: "layoutSection",
315
+ content: [{ type: "layoutColumn", attrs: { width: 50 }, content: [para("Left column")] }]
316
+ }
317
+ const blockCard = { type: "blockCard", attrs: { url: "https://www.atlassian.com/software/confluence" } }
318
+ const embedCard = {
319
+ type: "embedCard",
320
+ attrs: { url: "https://www.atlassian.com/software/confluence", layout: "center" }
321
+ }
322
+ const out = revertPlaceholders(
323
+ docOf([
324
+ para(`<!-- adf:taskList node=${b64(taskList)} -->`),
325
+ para("[x] Existing primitive coverage reviewed"),
326
+ para("<!-- adf:/taskList -->"),
327
+ para(`<!-- adf:decisionList node=${b64(decisionList)} -->`),
328
+ para("This page will act as the baseline integration test asset for editor primitive coverage."),
329
+ para("<!-- adf:/decisionList -->"),
330
+ para(`<!-- adf:expand node=${b64(expand)} -->`),
331
+ para("This section can be expanded."),
332
+ para("<!-- adf:/expand -->"),
333
+ para(`<!-- adf:table node=${b64(table)} -->`),
334
+ para("| Date |"),
335
+ para("<!-- adf:/table -->"),
336
+ para(`<!-- adf:layoutSection node=${b64(layoutSection)} -->`),
337
+ para("Left column"),
338
+ para("<!-- adf:/layoutSection -->"),
339
+ para(`<!-- adf:blockCard node=${b64(blockCard)} -->`),
340
+ para("https://www.atlassian.com/software/confluence"),
341
+ para("<!-- adf:/blockCard -->"),
342
+ para(`<!-- adf:embedCard node=${b64(embedCard)} -->`),
343
+ para("https://www.atlassian.com/software/confluence"),
344
+ para("<!-- adf:/embedCard -->")
345
+ ])
346
+ ) as { content: Array<unknown> }
347
+
348
+ expect(out.content).toEqual([taskList, decisionList, expand, table, layoutSection, blockCard, embedCard])
349
+ })
350
+
138
351
  it("reverts an extension marker nested inside a bodiedExtension body", () => {
139
352
  const out = revertPlaceholders(
140
353
  docOf([
@@ -23,12 +23,12 @@ describe("AdfSchemaValidator", () => {
23
23
  type: "doc",
24
24
  content: [{ type: "paragraph", content: [{ type: "text", text: 42 }] }]
25
25
  }
26
- const result = yield* Effect.either(v.check(doc, "incoming"))
27
- expect(result._tag).toBe("Left")
28
- if (result._tag === "Left") {
29
- expect(result.left._tag).toBe("AdfSchemaError")
30
- expect(result.left.direction).toBe("incoming")
31
- expect(result.left.issues.length).toBeGreaterThan(0)
26
+ const result = yield* Effect.result(v.check(doc, "incoming"))
27
+ expect(result._tag).toBe("Failure")
28
+ if (result._tag === "Failure") {
29
+ expect(result.failure._tag).toBe("AdfSchemaError")
30
+ expect(result.failure.direction).toBe("incoming")
31
+ expect(result.failure.issues.length).toBeGreaterThan(0)
32
32
  }
33
33
  }).pipe(Effect.provide(AdfSchemaValidatorLayer)))
34
34
  })
@@ -4,9 +4,18 @@ import { walk } from "../src/AdfWalker.js"
4
4
 
5
5
  const doc = (content: ReadonlyArray<unknown>): DocNode => ({ version: 1, type: "doc", content } as unknown as DocNode)
6
6
 
7
- // Expected `attrs=` blob: base64 of the attrs JSON with keys sorted (write
8
- // the literal in sorted key order so JSON.stringify matches the walker).
9
- const b64 = (attrs: Record<string, unknown>): string => Buffer.from(JSON.stringify(attrs)).toString("base64")
7
+ const stableStringify = (v: unknown): string => {
8
+ if (Array.isArray(v)) return `[${v.map(stableStringify).join(",")}]`
9
+ if (v !== null && typeof v === "object") {
10
+ return `{${
11
+ Object.entries(v as Record<string, unknown>)
12
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
13
+ .map(([k, value]) => `${JSON.stringify(k)}:${stableStringify(value)}`)
14
+ .join(",")
15
+ }}`
16
+ }
17
+ return JSON.stringify(v) ?? "null"
18
+ }
10
19
 
11
20
  describe("AdfWalker", () => {
12
21
  it("emits a heading at the right level", () => {
@@ -159,34 +168,57 @@ describe("AdfWalker", () => {
159
168
  expect(r.markdown).toContain("| 1 | 2 |")
160
169
  })
161
170
 
162
- it("renders a panel as a GitHub admonition", () => {
171
+ it("renders a panel as a Confluence-preserving placeholder", () => {
163
172
  const r = walk(doc([{
164
173
  type: "panel",
165
174
  attrs: { panelType: "warning" },
166
175
  content: [{ type: "paragraph", content: [{ type: "text", text: "be careful" }] }]
167
176
  }]))
168
- expect(r.markdown).toContain("[!WARNING]")
177
+ expect(r.markdown).toContain(
178
+ `<!-- adf:panel type=warning attrs=${stableStringify({ panelType: "warning" })} -->`
179
+ )
169
180
  expect(r.markdown).toContain("be careful")
181
+ expect(r.markdown).toContain("<!-- adf:/panel -->")
170
182
  })
171
183
 
172
184
  it("renders task lists with checkbox state", () => {
173
- const r = walk(doc([{
185
+ const node = {
174
186
  type: "taskList",
187
+ attrs: { localId: "tasks-1" },
175
188
  content: [
176
189
  {
177
190
  type: "taskItem",
178
- attrs: { state: "DONE" },
191
+ attrs: { localId: "task-1", state: "DONE" },
179
192
  content: [{ type: "text", text: "done" }]
180
193
  },
181
194
  {
182
195
  type: "taskItem",
183
- attrs: { state: "TODO" },
196
+ attrs: { localId: "task-2", state: "TODO" },
184
197
  content: [{ type: "text", text: "todo" }]
185
198
  }
186
199
  ]
187
- }]))
200
+ }
201
+ const r = walk(doc([node]))
202
+ expect(r.markdown).toContain(`<!-- adf:taskList node=${stableStringify(node)} -->`)
188
203
  expect(r.markdown).toContain("- [x] done")
189
204
  expect(r.markdown).toContain("- [ ] todo")
205
+ expect(r.markdown).toContain("<!-- adf:/taskList -->")
206
+ })
207
+
208
+ it("wraps decision lists so they survive push as native decisions", () => {
209
+ const node = {
210
+ type: "decisionList",
211
+ attrs: { localId: "decisions-1" },
212
+ content: [{
213
+ type: "decisionItem",
214
+ attrs: { localId: "decision-1", state: "DECIDED" },
215
+ content: [{ type: "text", text: "decide" }]
216
+ }]
217
+ }
218
+ const r = walk(doc([node]))
219
+ expect(r.markdown).toContain(`<!-- adf:decisionList node=${stableStringify(node)} -->`)
220
+ expect(r.markdown).toContain("- 🔘 decide")
221
+ expect(r.markdown).toContain("<!-- adf:/decisionList -->")
190
222
  })
191
223
 
192
224
  it("renders every child of a mediaGroup", () => {
@@ -237,23 +269,51 @@ describe("AdfWalker", () => {
237
269
  expect(r.markdown).not.toContain("confluence-mention")
238
270
  })
239
271
 
240
- it("preserves the full attrs (parameters included) in the extension placeholder", () => {
272
+ it("renders a representable TOC extension as readable native syntax", () => {
273
+ const r = walk(doc([{
274
+ type: "extension",
275
+ attrs: {
276
+ extensionKey: "toc",
277
+ extensionType: "com.atlassian.confluence.macro.core"
278
+ }
279
+ }]))
280
+ expect(r.markdown).toContain("[[toc]]")
281
+ expect(r.warnings).not.toContainEqual(
282
+ expect.objectContaining({ _tag: "UnsupportedExtension", extensionKey: "toc" })
283
+ )
284
+ })
285
+
286
+ it("renders representable TOC levels in readable native syntax", () => {
241
287
  const r = walk(doc([{
242
288
  type: "extension",
243
289
  attrs: {
244
290
  extensionType: "com.atlassian.confluence.macro.core",
245
291
  extensionKey: "toc",
246
- parameters: { macroParams: { maxLevel: { value: "3" } } }
292
+ parameters: {
293
+ macroParams: {
294
+ minLevel: { value: "2" },
295
+ maxLevel: { value: "4" }
296
+ }
297
+ }
247
298
  }
248
299
  }]))
249
- const attrs = b64({
300
+ expect(r.markdown).toContain("[[toc:min=2,max=4]]")
301
+ })
302
+
303
+ it("falls back to a generic placeholder when TOC attrs are not fully representable", () => {
304
+ const rawAttrs = {
250
305
  extensionKey: "toc",
251
306
  extensionType: "com.atlassian.confluence.macro.core",
307
+ layout: "default",
308
+ localId: "abc-123",
252
309
  parameters: { macroParams: { maxLevel: { value: "3" } } }
253
- })
310
+ }
311
+ const r = walk(doc([{ type: "extension", attrs: rawAttrs }]))
312
+ const attrs = stableStringify(rawAttrs)
254
313
  expect(r.markdown).toContain(
255
314
  `<!-- adf:extension key=toc type=com.atlassian.confluence.macro.core attrs=${attrs} -->`
256
315
  )
316
+ expect(r.markdown).not.toContain("[[toc")
257
317
  expect(
258
318
  r.warnings.some((w) =>
259
319
  w._tag === "UnsupportedExtension" && w.extensionKey === "toc" && w.nodeType === "extension"
@@ -261,6 +321,27 @@ describe("AdfWalker", () => {
261
321
  ).toBe(true)
262
322
  })
263
323
 
324
+ it("falls back to a generic placeholder for Confluence TOC macroMetadata", () => {
325
+ const rawAttrs = {
326
+ extensionKey: "toc",
327
+ extensionType: "com.atlassian.confluence.macro.core",
328
+ layout: "default",
329
+ parameters: {
330
+ macroMetadata: {
331
+ schemaVersion: { value: "1" },
332
+ title: "Table of Contents"
333
+ },
334
+ macroParams: {}
335
+ }
336
+ }
337
+ const r = walk(doc([{ type: "extension", attrs: rawAttrs }]))
338
+ const attrs = stableStringify(rawAttrs)
339
+ expect(r.markdown).toContain(
340
+ `<!-- adf:extension key=toc type=com.atlassian.confluence.macro.core attrs=${attrs} -->`
341
+ )
342
+ expect(r.markdown).not.toContain("[[toc")
343
+ })
344
+
264
345
  it("emits the same attrs blob regardless of source key order", () => {
265
346
  const a = walk(doc([{ type: "extension", attrs: { extensionKey: "toc", extensionType: "t" } }]))
266
347
  const b = walk(doc([{ type: "extension", attrs: { extensionType: "t", extensionKey: "toc" } }]))
@@ -283,8 +364,8 @@ describe("AdfWalker", () => {
283
364
  content: [{ type: "paragraph", content: [{ type: "text", text: "body" }] }]
284
365
  }
285
366
  ]))
286
- const inlineAttrs = b64({ extensionKey: "jira-issue", extensionType: "com.example" })
287
- const bodiedAttrs = b64({ extensionKey: "details", extensionType: "com.example" })
367
+ const inlineAttrs = stableStringify({ extensionKey: "jira-issue", extensionType: "com.example" })
368
+ const bodiedAttrs = stableStringify({ extensionKey: "details", extensionType: "com.example" })
288
369
  expect(r.markdown).toContain(
289
370
  `<!-- adf:inlineExtension key=jira-issue type=com.example attrs=${inlineAttrs} -->`
290
371
  )
@@ -325,7 +406,7 @@ describe("AdfWalker", () => {
325
406
  }]
326
407
  }]))
327
408
  expect(r.markdown).not.toContain("adf:/bodiedExtension")
328
- expect(r.markdown).not.toContain("body")
409
+ expect(r.markdown).not.toContain("\n\nbody\n\n")
329
410
  expect(r.markdown).toContain("<!-- adf:bodiedExtension key=details type=com.example")
330
411
  })
331
412
 
@@ -362,6 +443,42 @@ describe("AdfWalker", () => {
362
443
  expect(r.markdown).toContain("![diagram](https://x.test/d.png)\n_Figure 1_")
363
444
  })
364
445
 
446
+ it("renders layout sections and columns as visible markdown content", () => {
447
+ const r = walk(doc([{
448
+ type: "layoutSection",
449
+ content: [
450
+ {
451
+ type: "layoutColumn",
452
+ attrs: { width: 50 },
453
+ content: [{ type: "paragraph", content: [{ type: "text", text: "left" }] }]
454
+ },
455
+ {
456
+ type: "layoutColumn",
457
+ attrs: { width: 50 },
458
+ content: [{ type: "paragraph", content: [{ type: "text", text: "right" }] }]
459
+ }
460
+ ]
461
+ }]))
462
+ expect(r.markdown).toContain("left\n\nright")
463
+ expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "layoutSection")).toBe(false)
464
+ expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "layoutColumn")).toBe(false)
465
+ })
466
+
467
+ it("renders block and embed smart cards from direct and nested urls", () => {
468
+ const blockCard = { type: "blockCard", attrs: { url: "https://x.test/block" } }
469
+ const embedCard = { type: "embedCard", attrs: { data: { url: "https://x.test/embed" } } }
470
+ const r = walk(doc([
471
+ blockCard,
472
+ embedCard
473
+ ]))
474
+ expect(r.markdown).toContain(`<!-- adf:blockCard node=${stableStringify(blockCard)} -->`)
475
+ expect(r.markdown).toContain("<https://x.test/block>")
476
+ expect(r.markdown).toContain(`<!-- adf:embedCard node=${stableStringify(embedCard)} -->`)
477
+ expect(r.markdown).toContain("<https://x.test/embed>")
478
+ expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "blockCard")).toBe(false)
479
+ expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "embedCard")).toBe(false)
480
+ })
481
+
365
482
  it("backslash-escapes nestedExpand titles inside table cells (inline HTML context)", () => {
366
483
  const r = walk(doc([{
367
484
  type: "table",
@@ -386,7 +503,8 @@ describe("AdfWalker", () => {
386
503
  attrs: { title: `v2 *beta* <a href="x">` },
387
504
  content: [{ type: "paragraph", content: [{ type: "text", text: "inner" }] }]
388
505
  }]))
389
- expect(r.markdown).toContain(`<summary>v2 *beta* &lt;a href=&quot;x&quot;&gt;</summary>`)
506
+ expect(r.markdown).toContain(`<!-- adf:expand node=`)
507
+ expect(r.markdown).toContain(`v2 *beta* <a href="x">`)
390
508
  expect(r.markdown).not.toContain("\\*beta\\*")
391
509
  })
392
510
 
@@ -465,13 +583,39 @@ describe("AdfWalker", () => {
465
583
  type: "paragraph",
466
584
  content: [
467
585
  { type: "text", text: "before " },
468
- { type: "inlineCard", attrs: { data: { url: "https://hidden.test" } } },
586
+ { type: "inlineCard", attrs: { data: { title: "hidden" } } },
469
587
  { type: "text", text: " after" }
470
588
  ]
471
589
  }]))
472
590
  expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "inlineCard")).toBe(true)
473
591
  })
474
592
 
593
+ it("renders inline cards from nested data urls", () => {
594
+ const r = walk(doc([{
595
+ type: "paragraph",
596
+ content: [
597
+ { type: "text", text: "see " },
598
+ { type: "inlineCard", attrs: { data: { url: "https://x.test/inline" } } }
599
+ ]
600
+ }]))
601
+ expect(r.markdown).toContain(
602
+ `see <!-- adf:inlineCard attrs=${stableStringify({ data: { url: "https://x.test/inline" } })} -->`
603
+ )
604
+ expect(r.warnings.some((w) => w._tag === "UnsupportedNode" && w.nodeType === "inlineCard")).toBe(false)
605
+ })
606
+
607
+ it("wraps paragraph-level marks so alignment and indentation survive push", () => {
608
+ const marks = [{ type: "alignment", attrs: { align: "center" } }]
609
+ const r = walk(doc([{
610
+ type: "paragraph",
611
+ marks,
612
+ content: [{ type: "text", text: "centered" }]
613
+ }]))
614
+ expect(r.markdown).toContain(`<!-- adf:paragraph marks=${stableStringify(marks)} -->`)
615
+ expect(r.markdown).toContain("centered")
616
+ expect(r.markdown).toContain("<!-- adf:/paragraph -->")
617
+ })
618
+
475
619
  it("does not double-wrap an em-marked caption", () => {
476
620
  const r = walk(doc([{
477
621
  type: "mediaSingle",
@@ -505,7 +649,7 @@ describe("AdfWalker", () => {
505
649
  expect(r.markdown).toContain("_orphan_")
506
650
  })
507
651
 
508
- it("maps note panels to IMPORTANT and success panels to TIP", () => {
652
+ it("preserves note and success panel types", () => {
509
653
  const r = walk(doc([
510
654
  {
511
655
  type: "panel",
@@ -518,8 +662,10 @@ describe("AdfWalker", () => {
518
662
  content: [{ type: "paragraph", content: [{ type: "text", text: "s" }] }]
519
663
  }
520
664
  ]))
521
- expect(r.markdown).toContain("[!IMPORTANT]")
522
- expect(r.markdown).toContain("[!TIP]")
665
+ expect(r.markdown).toContain(`<!-- adf:panel type=note attrs=${stableStringify({ panelType: "note" })} -->`)
666
+ expect(r.markdown).toContain(
667
+ `<!-- adf:panel type=success attrs=${stableStringify({ panelType: "success" })} -->`
668
+ )
523
669
  })
524
670
 
525
671
  it("ends output with exactly one newline", () => {
@@ -14,12 +14,12 @@ describe("AtlaskitTransformers", () => {
14
14
  it.effect("surfaces synchronous throws as AtlaskitTransformersError", () =>
15
15
  Effect.gen(function*() {
16
16
  const t = yield* AtlaskitTransformers
17
- const result = yield* Effect.either(t.use(() => {
17
+ const result = yield* Effect.result(t.use(() => {
18
18
  throw new Error("boom")
19
19
  }))
20
- expect(result._tag).toBe("Left")
21
- if (result._tag === "Left") {
22
- expect(result.left._tag).toBe("AtlaskitTransformersError")
20
+ expect(result._tag).toBe("Failure")
21
+ if (result._tag === "Failure") {
22
+ expect(result.failure._tag).toBe("AtlaskitTransformersError")
23
23
  }
24
24
  }).pipe(Effect.provide(AtlaskitTransformersLayer)))
25
25
  })
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from "@effect/vitest"
2
- import * as Either from "effect/Either"
2
+ import * as Result from "effect/Result"
3
3
  import * as Schema from "effect/Schema"
4
4
  import { ContentHash, PageId, PageIdSchema, SpaceKey, SpaceKeySchema } from "../src/Brand.js"
5
5
 
@@ -17,13 +17,13 @@ describe("Brand", () => {
17
17
 
18
18
  describe("PageIdSchema", () => {
19
19
  it("decodes valid page IDs", () => {
20
- const result = Schema.decodeEither(PageIdSchema)("123456")
21
- expect(Either.isRight(result)).toBe(true)
20
+ const result = Schema.decodeUnknownResult(PageIdSchema)("123456")
21
+ expect(Result.isSuccess(result)).toBe(true)
22
22
  })
23
23
 
24
24
  it("rejects empty strings", () => {
25
- const result = Schema.decodeEither(PageIdSchema)("")
26
- expect(Either.isLeft(result)).toBe(true)
25
+ const result = Schema.decodeUnknownResult(PageIdSchema)("")
26
+ expect(Result.isFailure(result)).toBe(true)
27
27
  })
28
28
  })
29
29
 
@@ -40,18 +40,18 @@ describe("Brand", () => {
40
40
 
41
41
  describe("SpaceKeySchema", () => {
42
42
  it("decodes uppercase alphanumeric keys", () => {
43
- const result = Schema.decodeEither(SpaceKeySchema)("MYSPACE123")
44
- expect(Either.isRight(result)).toBe(true)
43
+ const result = Schema.decodeUnknownResult(SpaceKeySchema)("MYSPACE123")
44
+ expect(Result.isSuccess(result)).toBe(true)
45
45
  })
46
46
 
47
47
  it("rejects lowercase keys", () => {
48
- const result = Schema.decodeEither(SpaceKeySchema)("myspace")
49
- expect(Either.isLeft(result)).toBe(true)
48
+ const result = Schema.decodeUnknownResult(SpaceKeySchema)("myspace")
49
+ expect(Result.isFailure(result)).toBe(true)
50
50
  })
51
51
 
52
52
  it("rejects keys with special characters", () => {
53
- const result = Schema.decodeEither(SpaceKeySchema)("MY-SPACE")
54
- expect(Either.isLeft(result)).toBe(true)
53
+ const result = Schema.decodeUnknownResult(SpaceKeySchema)("MY-SPACE")
54
+ expect(Result.isFailure(result)).toBe(true)
55
55
  })
56
56
  })
57
57
 
@@ -1,5 +1,7 @@
1
+ import { NodeServices } from "@effect/platform-node"
1
2
  import { describe, expect, it } from "@effect/vitest"
2
3
  import * as Effect from "effect/Effect"
4
+ import * as Layer from "effect/Layer"
3
5
  import { GitService, layer as GitServiceLayer } from "../src/GitService.js"
4
6
  import { getConflictedFiles, GIT_LOG_FORMAT, parseGitLog, parseGitStatus } from "../src/internal/gitCommands.js"
5
7
 
@@ -7,6 +9,8 @@ import { getConflictedFiles, GIT_LOG_FORMAT, parseGitLog, parseGitStatus } from
7
9
  * Tests for git parsing utilities and GitService.
8
10
  */
9
11
  describe("GitService", () => {
12
+ const TestLayer = Layer.provideMerge(GitServiceLayer, NodeServices.layer)
13
+
10
14
  describe("parseGitStatus", () => {
11
15
  it("parses empty status", () => {
12
16
  const entries = parseGitStatus("")
@@ -197,13 +201,13 @@ M normal.ts`
197
201
  const git = yield* GitService
198
202
  const version = yield* git.validateGit()
199
203
  expect(version).toContain("git version")
200
- }).pipe(Effect.provide(GitServiceLayer)))
204
+ }).pipe(Effect.provide(TestLayer)))
201
205
 
202
206
  it.effect("isInitialized returns boolean", () =>
203
207
  Effect.gen(function*() {
204
208
  const git = yield* GitService
205
209
  const initialized = yield* git.isInitialized()
206
210
  expect(typeof initialized).toBe("boolean")
207
- }).pipe(Effect.provide(GitServiceLayer)))
211
+ }).pipe(Effect.provide(TestLayer)))
208
212
  })
209
213
  })