@wonseok-han/confluence-sync 1.8.0 → 2.0.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 (518) hide show
  1. package/README.md +44 -410
  2. package/dist/cli/args.js +1 -1
  3. package/dist/cli/help.js +214 -115
  4. package/dist/cli/init.js +44 -5
  5. package/dist/cli/main.js +42 -11
  6. package/dist/cli/status.js +83 -0
  7. package/dist/confluence/client.js +121 -57
  8. package/dist/confluence/config.js +12 -8
  9. package/dist/confluence/env-file.js +23 -0
  10. package/dist/confluence/links.js +18 -0
  11. package/dist/conversion/asset-paths.js +5 -0
  12. package/dist/conversion/attachments.js +29 -7
  13. package/dist/conversion/convert.js +10 -22
  14. package/dist/conversion/footnotes.js +114 -11
  15. package/dist/conversion/markdown.js +26 -0
  16. package/dist/conversion/pdf-pages.js +10 -8
  17. package/dist/documents/anchors.js +9 -0
  18. package/dist/documents/callout-roundtrip.js +75 -0
  19. package/dist/documents/callouts.js +74 -0
  20. package/dist/documents/catalog.js +2 -2
  21. package/dist/documents/footnote-roundtrip.js +96 -0
  22. package/dist/documents/format.js +116 -0
  23. package/dist/documents/html-tables.js +30 -0
  24. package/dist/documents/html-to-markdown.js +47 -13
  25. package/dist/documents/markdown.js +46 -4
  26. package/dist/documents/obsidian.js +6 -3
  27. package/dist/documents/tables.js +89 -0
  28. package/dist/runtime/network.js +4 -0
  29. package/dist/shared/colors.js +2 -2
  30. package/dist/shared/progress.js +164 -0
  31. package/dist/shared/version.js +12 -0
  32. package/dist/site/assets/Monaco-LICENSE.txt +21 -0
  33. package/dist/site/assets/Monaco-ThirdPartyNotices.txt +448 -0
  34. package/dist/site/assets/PDFJS-LICENSE.txt +177 -0
  35. package/dist/site/assets/app.css +1 -0
  36. package/dist/site/assets/app.js +4 -0
  37. package/dist/site/assets/chunks/chunk-TEW74QPN.js +35 -0
  38. package/dist/site/assets/chunks/markdown-S6623E66.js +1 -0
  39. package/dist/site/assets/chunks/monaco-36ZGUH4Y.js +897 -0
  40. package/dist/site/assets/chunks/monaco-HFLEBJTI.css +1 -0
  41. package/dist/site/assets/chunks/pdf-DDN7TXTP.js +55 -0
  42. package/dist/site/assets/confluence-env-example.txt +32 -0
  43. package/dist/site/assets/editor.worker.js +1 -0
  44. package/dist/site/assets/favicon.svg +3 -0
  45. package/dist/site/assets/guide/01-account-settings.png +0 -0
  46. package/dist/site/assets/guide/02-atlassian-security.png +0 -0
  47. package/dist/site/assets/guide/03-api-tokens.png +0 -0
  48. package/dist/site/assets/guide/04-scope-api-token-step1.png +0 -0
  49. package/dist/site/assets/guide/05-scope-api-token-step2.png +0 -0
  50. package/dist/site/assets/guide/06-scope-api-token-step3.png +0 -0
  51. package/dist/site/assets/guide/07-scope-api-token-step4.png +0 -0
  52. package/dist/site/assets/guide/web/document-preview.png +0 -0
  53. package/dist/site/assets/guide/web/remote-diff.png +0 -0
  54. package/dist/site/assets/guide/web/sync-workspace.png +0 -0
  55. package/dist/site/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
  56. package/dist/site/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
  57. package/dist/site/assets/pdf/cmaps/78-H.bcmap +0 -0
  58. package/dist/site/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
  59. package/dist/site/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
  60. package/dist/site/assets/pdf/cmaps/78-V.bcmap +0 -0
  61. package/dist/site/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
  62. package/dist/site/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
  63. package/dist/site/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
  64. package/dist/site/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
  65. package/dist/site/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
  66. package/dist/site/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
  67. package/dist/site/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
  68. package/dist/site/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
  69. package/dist/site/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
  70. package/dist/site/assets/pdf/cmaps/Add-H.bcmap +0 -0
  71. package/dist/site/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
  72. package/dist/site/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
  73. package/dist/site/assets/pdf/cmaps/Add-V.bcmap +0 -0
  74. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
  75. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
  76. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
  77. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
  78. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
  79. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
  80. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
  81. package/dist/site/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  82. package/dist/site/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
  83. package/dist/site/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
  84. package/dist/site/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
  85. package/dist/site/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
  86. package/dist/site/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
  87. package/dist/site/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
  88. package/dist/site/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  89. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
  90. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
  91. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
  92. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
  93. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
  94. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
  95. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
  96. package/dist/site/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  97. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
  98. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
  99. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
  100. package/dist/site/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  101. package/dist/site/assets/pdf/cmaps/B5-H.bcmap +0 -0
  102. package/dist/site/assets/pdf/cmaps/B5-V.bcmap +0 -0
  103. package/dist/site/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
  104. package/dist/site/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
  105. package/dist/site/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
  106. package/dist/site/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
  107. package/dist/site/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
  108. package/dist/site/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
  109. package/dist/site/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
  110. package/dist/site/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
  111. package/dist/site/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
  112. package/dist/site/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
  113. package/dist/site/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
  114. package/dist/site/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
  115. package/dist/site/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
  116. package/dist/site/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
  117. package/dist/site/assets/pdf/cmaps/EUC-H.bcmap +0 -0
  118. package/dist/site/assets/pdf/cmaps/EUC-V.bcmap +0 -0
  119. package/dist/site/assets/pdf/cmaps/Ext-H.bcmap +0 -0
  120. package/dist/site/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
  121. package/dist/site/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
  122. package/dist/site/assets/pdf/cmaps/Ext-V.bcmap +0 -0
  123. package/dist/site/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
  124. package/dist/site/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
  125. package/dist/site/assets/pdf/cmaps/GB-H.bcmap +4 -0
  126. package/dist/site/assets/pdf/cmaps/GB-V.bcmap +0 -0
  127. package/dist/site/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
  128. package/dist/site/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
  129. package/dist/site/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
  130. package/dist/site/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
  131. package/dist/site/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
  132. package/dist/site/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
  133. package/dist/site/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
  134. package/dist/site/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
  135. package/dist/site/assets/pdf/cmaps/GBT-H.bcmap +0 -0
  136. package/dist/site/assets/pdf/cmaps/GBT-V.bcmap +0 -0
  137. package/dist/site/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
  138. package/dist/site/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
  139. package/dist/site/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
  140. package/dist/site/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
  141. package/dist/site/assets/pdf/cmaps/H.bcmap +0 -0
  142. package/dist/site/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
  143. package/dist/site/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
  144. package/dist/site/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
  145. package/dist/site/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
  146. package/dist/site/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
  147. package/dist/site/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
  148. package/dist/site/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
  149. package/dist/site/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
  150. package/dist/site/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
  151. package/dist/site/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
  152. package/dist/site/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
  153. package/dist/site/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
  154. package/dist/site/assets/pdf/cmaps/Hankaku.bcmap +0 -0
  155. package/dist/site/assets/pdf/cmaps/Hiragana.bcmap +0 -0
  156. package/dist/site/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
  157. package/dist/site/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
  158. package/dist/site/assets/pdf/cmaps/KSC-H.bcmap +0 -0
  159. package/dist/site/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
  160. package/dist/site/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
  161. package/dist/site/assets/pdf/cmaps/KSC-V.bcmap +0 -0
  162. package/dist/site/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
  163. package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  164. package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  165. package/dist/site/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
  166. package/dist/site/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
  167. package/dist/site/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
  168. package/dist/site/assets/pdf/cmaps/Katakana.bcmap +0 -0
  169. package/dist/site/assets/pdf/cmaps/LICENSE +36 -0
  170. package/dist/site/assets/pdf/cmaps/NWP-H.bcmap +0 -0
  171. package/dist/site/assets/pdf/cmaps/NWP-V.bcmap +0 -0
  172. package/dist/site/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
  173. package/dist/site/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
  174. package/dist/site/assets/pdf/cmaps/Roman.bcmap +0 -0
  175. package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  176. package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  177. package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  178. package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  179. package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  180. package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  181. package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  182. package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  183. package/dist/site/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
  184. package/dist/site/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
  185. package/dist/site/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
  186. package/dist/site/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
  187. package/dist/site/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
  188. package/dist/site/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
  189. package/dist/site/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
  190. package/dist/site/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
  191. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  192. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  193. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  194. package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  195. package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  196. package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  197. package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  198. package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  199. package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  200. package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  201. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  202. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  203. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  204. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  205. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  206. package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  207. package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  208. package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  209. package/dist/site/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  210. package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  211. package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  212. package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  213. package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  214. package/dist/site/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
  215. package/dist/site/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
  216. package/dist/site/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
  217. package/dist/site/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
  218. package/dist/site/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
  219. package/dist/site/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
  220. package/dist/site/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
  221. package/dist/site/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
  222. package/dist/site/assets/pdf/cmaps/V.bcmap +0 -0
  223. package/dist/site/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
  224. package/dist/site/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
  225. package/dist/site/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
  226. package/dist/site/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
  227. package/dist/site/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  228. package/dist/site/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
  229. package/dist/site/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
  230. package/dist/site/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
  231. package/dist/site/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  232. package/dist/site/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
  233. package/dist/site/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
  234. package/dist/site/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
  235. package/dist/site/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
  236. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
  237. package/dist/site/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  238. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
  239. package/dist/site/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
  240. package/dist/site/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
  241. package/dist/site/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
  242. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  243. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  244. package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
  245. package/dist/site/assets/pdf/wasm/LICENSE_QCMS +21 -0
  246. package/dist/site/assets/pdf/wasm/jbig2.wasm +0 -0
  247. package/dist/site/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
  248. package/dist/site/assets/pdf/wasm/openjpeg.wasm +0 -0
  249. package/dist/site/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
  250. package/dist/site/assets/pdf/wasm/qcms_bg.wasm +0 -0
  251. package/dist/site/assets/pdf/wasm/quickjs-eval.js +16 -0
  252. package/dist/site/assets/pdf/wasm/quickjs-eval.wasm +0 -0
  253. package/dist/site/assets/pdf.worker.min.mjs +29 -0
  254. package/dist/site/assets/workspace.worker.js +409 -0
  255. package/dist/site/index.html +253 -0
  256. package/dist/sync/baseline.js +45 -0
  257. package/dist/sync/changes.js +51 -0
  258. package/dist/sync/diff.js +80 -0
  259. package/dist/sync/fetch.js +287 -0
  260. package/dist/sync/ignore.js +4 -4
  261. package/dist/sync/local-state.js +12 -0
  262. package/dist/sync/mapping.js +31 -8
  263. package/dist/sync/metadata.js +57 -0
  264. package/dist/sync/prepare.js +52 -0
  265. package/dist/sync/pull.js +618 -141
  266. package/dist/sync/push.js +260 -213
  267. package/dist/sync/reconcile.js +51 -0
  268. package/dist/sync/references.js +2 -2
  269. package/dist/sync/remap.js +17 -5
  270. package/dist/sync/render.js +3 -2
  271. package/dist/sync/restore.js +28 -0
  272. package/dist/sync/scope.js +47 -0
  273. package/dist/sync/staging.js +193 -0
  274. package/dist/sync/workspace.js +100 -0
  275. package/dist/web/assets/PDFJS-LICENSE.txt +177 -0
  276. package/dist/web/assets/app.css +1 -1
  277. package/dist/web/assets/app.js +3 -938
  278. package/dist/web/assets/chunks/chunk-TEW74QPN.js +35 -0
  279. package/dist/web/assets/chunks/markdown-S6623E66.js +1 -0
  280. package/dist/web/assets/chunks/monaco-36ZGUH4Y.js +897 -0
  281. package/dist/web/assets/chunks/monaco-HFLEBJTI.css +1 -0
  282. package/dist/web/assets/chunks/pdf-DDN7TXTP.js +55 -0
  283. package/dist/web/assets/confluence-env-example.txt +32 -0
  284. package/dist/web/assets/editor.worker.js +1 -30
  285. package/dist/web/assets/favicon.svg +3 -0
  286. package/dist/web/assets/guide/01-account-settings.png +0 -0
  287. package/dist/web/assets/guide/02-atlassian-security.png +0 -0
  288. package/dist/web/assets/guide/03-api-tokens.png +0 -0
  289. package/dist/web/assets/guide/04-scope-api-token-step1.png +0 -0
  290. package/dist/web/assets/guide/05-scope-api-token-step2.png +0 -0
  291. package/dist/web/assets/guide/06-scope-api-token-step3.png +0 -0
  292. package/dist/web/assets/guide/07-scope-api-token-step4.png +0 -0
  293. package/dist/web/assets/guide/web/document-preview.png +0 -0
  294. package/dist/web/assets/guide/web/remote-diff.png +0 -0
  295. package/dist/web/assets/guide/web/sync-workspace.png +0 -0
  296. package/dist/web/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
  297. package/dist/web/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
  298. package/dist/web/assets/pdf/cmaps/78-H.bcmap +0 -0
  299. package/dist/web/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
  300. package/dist/web/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
  301. package/dist/web/assets/pdf/cmaps/78-V.bcmap +0 -0
  302. package/dist/web/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
  303. package/dist/web/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
  304. package/dist/web/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
  305. package/dist/web/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
  306. package/dist/web/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
  307. package/dist/web/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
  308. package/dist/web/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
  309. package/dist/web/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
  310. package/dist/web/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
  311. package/dist/web/assets/pdf/cmaps/Add-H.bcmap +0 -0
  312. package/dist/web/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
  313. package/dist/web/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
  314. package/dist/web/assets/pdf/cmaps/Add-V.bcmap +0 -0
  315. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
  316. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
  317. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
  318. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
  319. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
  320. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
  321. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
  322. package/dist/web/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  323. package/dist/web/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
  324. package/dist/web/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
  325. package/dist/web/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
  326. package/dist/web/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
  327. package/dist/web/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
  328. package/dist/web/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
  329. package/dist/web/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  330. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
  331. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
  332. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
  333. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
  334. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
  335. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
  336. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
  337. package/dist/web/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  338. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
  339. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
  340. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
  341. package/dist/web/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  342. package/dist/web/assets/pdf/cmaps/B5-H.bcmap +0 -0
  343. package/dist/web/assets/pdf/cmaps/B5-V.bcmap +0 -0
  344. package/dist/web/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
  345. package/dist/web/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
  346. package/dist/web/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
  347. package/dist/web/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
  348. package/dist/web/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
  349. package/dist/web/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
  350. package/dist/web/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
  351. package/dist/web/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
  352. package/dist/web/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
  353. package/dist/web/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
  354. package/dist/web/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
  355. package/dist/web/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
  356. package/dist/web/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
  357. package/dist/web/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
  358. package/dist/web/assets/pdf/cmaps/EUC-H.bcmap +0 -0
  359. package/dist/web/assets/pdf/cmaps/EUC-V.bcmap +0 -0
  360. package/dist/web/assets/pdf/cmaps/Ext-H.bcmap +0 -0
  361. package/dist/web/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
  362. package/dist/web/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
  363. package/dist/web/assets/pdf/cmaps/Ext-V.bcmap +0 -0
  364. package/dist/web/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
  365. package/dist/web/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
  366. package/dist/web/assets/pdf/cmaps/GB-H.bcmap +4 -0
  367. package/dist/web/assets/pdf/cmaps/GB-V.bcmap +0 -0
  368. package/dist/web/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
  369. package/dist/web/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
  370. package/dist/web/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
  371. package/dist/web/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
  372. package/dist/web/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
  373. package/dist/web/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
  374. package/dist/web/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
  375. package/dist/web/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
  376. package/dist/web/assets/pdf/cmaps/GBT-H.bcmap +0 -0
  377. package/dist/web/assets/pdf/cmaps/GBT-V.bcmap +0 -0
  378. package/dist/web/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
  379. package/dist/web/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
  380. package/dist/web/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
  381. package/dist/web/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
  382. package/dist/web/assets/pdf/cmaps/H.bcmap +0 -0
  383. package/dist/web/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
  384. package/dist/web/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
  385. package/dist/web/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
  386. package/dist/web/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
  387. package/dist/web/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
  388. package/dist/web/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
  389. package/dist/web/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
  390. package/dist/web/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
  391. package/dist/web/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
  392. package/dist/web/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
  393. package/dist/web/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
  394. package/dist/web/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
  395. package/dist/web/assets/pdf/cmaps/Hankaku.bcmap +0 -0
  396. package/dist/web/assets/pdf/cmaps/Hiragana.bcmap +0 -0
  397. package/dist/web/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
  398. package/dist/web/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
  399. package/dist/web/assets/pdf/cmaps/KSC-H.bcmap +0 -0
  400. package/dist/web/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
  401. package/dist/web/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
  402. package/dist/web/assets/pdf/cmaps/KSC-V.bcmap +0 -0
  403. package/dist/web/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
  404. package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  405. package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  406. package/dist/web/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
  407. package/dist/web/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
  408. package/dist/web/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
  409. package/dist/web/assets/pdf/cmaps/Katakana.bcmap +0 -0
  410. package/dist/web/assets/pdf/cmaps/LICENSE +36 -0
  411. package/dist/web/assets/pdf/cmaps/NWP-H.bcmap +0 -0
  412. package/dist/web/assets/pdf/cmaps/NWP-V.bcmap +0 -0
  413. package/dist/web/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
  414. package/dist/web/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
  415. package/dist/web/assets/pdf/cmaps/Roman.bcmap +0 -0
  416. package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  417. package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  418. package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  419. package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  420. package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  421. package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  422. package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  423. package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  424. package/dist/web/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
  425. package/dist/web/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
  426. package/dist/web/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
  427. package/dist/web/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
  428. package/dist/web/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
  429. package/dist/web/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
  430. package/dist/web/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
  431. package/dist/web/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
  432. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  433. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  434. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  435. package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  436. package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  437. package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  438. package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  439. package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  440. package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  441. package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  442. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  443. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  444. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  445. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  446. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  447. package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  448. package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  449. package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  450. package/dist/web/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  451. package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  452. package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  453. package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  454. package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  455. package/dist/web/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
  456. package/dist/web/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
  457. package/dist/web/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
  458. package/dist/web/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
  459. package/dist/web/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
  460. package/dist/web/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
  461. package/dist/web/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
  462. package/dist/web/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
  463. package/dist/web/assets/pdf/cmaps/V.bcmap +0 -0
  464. package/dist/web/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
  465. package/dist/web/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
  466. package/dist/web/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
  467. package/dist/web/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
  468. package/dist/web/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
  469. package/dist/web/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
  470. package/dist/web/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
  471. package/dist/web/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
  472. package/dist/web/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
  473. package/dist/web/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
  474. package/dist/web/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
  475. package/dist/web/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
  476. package/dist/web/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
  477. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
  478. package/dist/web/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
  479. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
  480. package/dist/web/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
  481. package/dist/web/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
  482. package/dist/web/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
  483. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
  484. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
  485. package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
  486. package/dist/web/assets/pdf/wasm/LICENSE_QCMS +21 -0
  487. package/dist/web/assets/pdf/wasm/jbig2.wasm +0 -0
  488. package/dist/web/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
  489. package/dist/web/assets/pdf/wasm/openjpeg.wasm +0 -0
  490. package/dist/web/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
  491. package/dist/web/assets/pdf/wasm/qcms_bg.wasm +0 -0
  492. package/dist/web/assets/pdf/wasm/quickjs-eval.js +16 -0
  493. package/dist/web/assets/pdf/wasm/quickjs-eval.wasm +0 -0
  494. package/dist/web/assets/pdf.worker.min.mjs +29 -0
  495. package/dist/web/assets/workspace.worker.js +409 -0
  496. package/dist/web/document-source.js +14 -0
  497. package/dist/web/hosted-files.js +189 -0
  498. package/dist/web/hosted.js +316 -0
  499. package/dist/web/node-runner.js +26 -0
  500. package/dist/web/preview.js +74 -0
  501. package/dist/web/server.js +85 -240
  502. package/dist/web/sync.js +364 -70
  503. package/dist/web/table-editor-script.js +99 -0
  504. package/dist/web/table-format.js +224 -0
  505. package/dist/web/views/help.js +15 -10
  506. package/dist/web/views/sync-panel.js +90 -19
  507. package/dist/web/views/token-guide.js +27 -0
  508. package/dist/web/views/usage-guide.js +12 -0
  509. package/dist/web/views/workspace.js +85 -15
  510. package/dist/web/workspace-api.js +371 -0
  511. package/docs/user/CLI.md +366 -0
  512. package/docs/user/CONFIGURATION.md +125 -0
  513. package/docs/user/OBSIDIAN.md +117 -0
  514. package/docs/user/WEB.md +90 -0
  515. package/docs/user/images/web/document-preview.png +0 -0
  516. package/docs/user/images/web/remote-diff.png +0 -0
  517. package/docs/user/images/web/sync-workspace.png +0 -0
  518. package/package.json +23 -6
@@ -2,17 +2,79 @@ import MarkdownIt from 'markdown-it';
2
2
  import footnote from 'markdown-it-footnote';
3
3
  import { collectHeadings } from '../documents/anchors.js';
4
4
  import { mapMarkdownText, replaceGeneratedBlocks } from './pdf-pages.js';
5
+ /** Registered rule names survive minification; Function.name does not. */
6
+ function registeredRule(ruler, name) {
7
+ const before = ruler.getRules('');
8
+ ruler.disable(name);
9
+ const remaining = new Set(ruler.getRules(''));
10
+ ruler.enable(name);
11
+ const rule = before.find(fn => !remaining.has(fn));
12
+ if (!rule)
13
+ throw new Error(`각주 파서 규칙을 찾을 수 없습니다: ${name}`);
14
+ return rule;
15
+ }
16
+ /** Use the parser's balanced inline-note rule, preserving code and escaped examples. */
17
+ function extractInlineNotes(source) {
18
+ const md = new MarkdownIt({ html: true }).use(footnote);
19
+ const rule = registeredRule(md.inline.ruler, 'footnote_inline');
20
+ const definitions = [], labels = new Set();
21
+ let edits = [], depth = 0, serial = 0;
22
+ md.inline.ruler.at('footnote_inline', (state, silent) => {
23
+ const start = state.pos;
24
+ depth++;
25
+ let ok;
26
+ try {
27
+ ok = rule(state, silent);
28
+ }
29
+ finally {
30
+ depth--;
31
+ }
32
+ if (ok && !silent && depth === 0) {
33
+ let label;
34
+ do {
35
+ label = `csync-inline-${++serial}`;
36
+ } while (source.includes(`[^${label}]`));
37
+ labels.add(label);
38
+ definitions.push(`[^${label}]: ${state.src.slice(start + 2, state.pos - 1).replace(/\n/g, '\n ')}`);
39
+ edits.push({ start, end: state.pos, text: `[^${label}]` });
40
+ }
41
+ return ok;
42
+ });
43
+ const lines = source.split('\n'), offsets = [0];
44
+ for (const line of lines)
45
+ offsets.push(offsets[offsets.length - 1] + line.length + 1);
46
+ const spans = new MarkdownIt({ html: true }).parse(source, {}).filter(t => ['fence', 'code_block', 'html_block'].includes(t.type) && t.map)
47
+ .map(t => [offsets[t.map[0]], Math.min(offsets[t.map[1]], source.length)]);
48
+ const prose = (part) => {
49
+ edits = [];
50
+ md.inline.parse(part, md, {}, []);
51
+ for (const edit of edits.sort((a, b) => b.start - a.start))
52
+ part = part.slice(0, edit.start) + edit.text + part.slice(edit.end);
53
+ return part;
54
+ };
55
+ let cursor = 0, text = '';
56
+ for (const [start, end] of spans) {
57
+ if (start < cursor)
58
+ continue;
59
+ text += prose(source.slice(cursor, start)) + source.slice(start, end);
60
+ cursor = end;
61
+ }
62
+ text += prose(source.slice(cursor));
63
+ return { text: definitions.length ? text.trimEnd() + '\n\n' + definitions.join('\n\n') + '\n' : source, labels };
64
+ }
5
65
  /** 각주 확장을 일반 제목 앵커 + 위첨자 Markdown 링크로 내보낸다. */
6
66
  export function footnotesToLinks(source) {
7
- if (!source.includes('[^'))
67
+ if (!source.includes('[^') && !source.includes('^['))
8
68
  return source;
69
+ const inline = extractInlineNotes(source);
70
+ source = inline.text;
9
71
  const md = new MarkdownIt({ html: true }).use(footnote);
10
72
  const definitions = [];
11
73
  const lines = source.split('\n');
12
74
  const offsets = [0];
13
75
  for (const line of lines)
14
76
  offsets.push(offsets[offsets.length - 1] + line.length + 1);
15
- const defRule = md.block.ruler.getRules('').find((r) => r.name === 'footnote_def');
77
+ const defRule = registeredRule(md.block.ruler, 'footnote_def');
16
78
  md.block.ruler.at('footnote_def', (state, start, end, silent) => {
17
79
  const ok = defRule(state, start, end, silent);
18
80
  if (ok && !silent) {
@@ -33,7 +95,7 @@ export function footnotesToLinks(source) {
33
95
  const labels = new Set(definitions.map((d) => d.label));
34
96
  const notes = new Map();
35
97
  const edits = [];
36
- const refRule = md.inline.ruler.getRules('').find((r) => r.name === 'footnote_ref');
98
+ const refRule = registeredRule(md.inline.ruler, 'footnote_ref');
37
99
  let localEdits = [];
38
100
  md.inline.ruler.at('footnote_ref', (state, silent) => {
39
101
  const start = state.pos;
@@ -58,7 +120,7 @@ export function footnotesToLinks(source) {
58
120
  }
59
121
  return ok;
60
122
  });
61
- // 인라인 각주(^[...])는 이 변환의 대상이 아니다.
123
+ // Inline notes have already been assigned collision-free definition labels.
62
124
  md.inline.ruler.disable('footnote_inline');
63
125
  const replaceRefs = (text) => {
64
126
  localEdits = [];
@@ -91,20 +153,61 @@ export function footnotesToLinks(source) {
91
153
  for (const e of edits.sort((a, b) => b.start - a.start))
92
154
  result = result.slice(0, e.start) + e.text + result.slice(e.end);
93
155
  const bodies = new Map(definitions.map((d) => [d.label, d.body]));
94
- return result.trimEnd() + '\n\n' + [...notes].map(([label, note]) => `<!-- csync-footnote:v1 ${Buffer.from(JSON.stringify({ label, anchor: note.anchor })).toString('base64')} -->\n###### ${note.heading}\n\n${replaceRefs(bodies.get(label) ?? '')}\n<!-- /csync-footnote -->`).join('\n\n') + '\n';
156
+ return result.trimEnd() + '\n\n' + [...notes].map(([label, note]) => `<!-- csync-footnote:v1 ${Buffer.from(JSON.stringify({ label, anchor: note.anchor, ...(inline.labels.has(label) ? { inline: true } : {}) })).toString('base64')} -->\n###### ${note.heading}\n\n${replaceRefs(bodies.get(label) ?? '')}\n<!-- /csync-footnote -->`).join('\n\n') + '\n';
95
157
  }
96
158
  /** 생성 표식이 있는 각주만 복원한다. 설명의 사용자 수정은 유지한다. */
97
159
  export function linksToFootnotes(source) {
98
160
  const refs = new Map();
99
161
  const definitions = [];
100
- const text = replaceGeneratedBlocks(source, /<!-- csync-footnote:v1 ([A-Za-z0-9+/=]+) -->\n#{1,6} [^\n]+\n\n([\s\S]*?)\n<!-- \/csync-footnote -->/g, (_all, encoded, body) => {
101
- const { label, anchor } = JSON.parse(Buffer.from(encoded, 'base64').toString());
102
- refs.set(anchor, label);
103
- definitions.push(`[^${label}]: ${body.trimEnd().split('\n').join('\n ')}`);
162
+ const inlined = new Set();
163
+ const parser = new MarkdownIt({ html: true }).use(footnote);
164
+ const text = replaceGeneratedBlocks(source, /<!-- csync-footnote:v1 ([A-Za-z0-9+/=]+) -->\n+#{1,6} [^\n]+\n\n([\s\S]*?)\n<!-- \/csync-footnote -->/g, (_all, encoded, body) => {
165
+ const data = decodeFootnote(encoded);
166
+ if (!data)
167
+ return _all;
168
+ const { label, anchor } = data;
169
+ refs.set(anchor, { label, body: body.trimEnd(), inline: data.inline === true });
170
+ if (!data.inline)
171
+ definitions.push(`[^${label}]: ${body.trimEnd().split('\n').join('\n ')}`);
104
172
  return '';
105
173
  });
106
174
  if (!refs.size)
107
175
  return source;
108
- const replace = (s) => mapMarkdownText(s, p => p.replace(/<sup>\[\d+\]\(#([^\s)]+)\)<\/sup>/g, (all, anchor) => refs.has(decodeURIComponent(anchor)) ? `[^${refs.get(decodeURIComponent(anchor))}]` : all));
109
- return replace(text).trimEnd() + '\n\n' + definitions.map(replace).join('\n\n') + '\n';
176
+ const replace = (s) => mapMarkdownText(s, p => p.replace(/<sup>\[\d+\]\(#([^\s)]+)\)<\/sup>/g, (all, anchor) => {
177
+ const note = refs.get(safeDecode(anchor));
178
+ if (!note)
179
+ return all;
180
+ if (note.inline && !/\n\s*\n/.test(note.body)) {
181
+ const candidate = `^[${note.body}]`, tokens = [];
182
+ parser.inline.parse(candidate, parser, {}, tokens);
183
+ if (tokens.length === 1 && tokens[0].type === 'footnote_ref') {
184
+ inlined.add(safeDecode(anchor));
185
+ return candidate;
186
+ }
187
+ }
188
+ return `[^${note.label}]`;
189
+ }));
190
+ const main = replace(text).trimEnd();
191
+ // A remotely removed inline reference must not discard the remaining note text.
192
+ for (const [anchor, note] of refs)
193
+ if (note.inline && !inlined.has(anchor))
194
+ definitions.push(`[^${note.label}]: ${note.body.split('\n').join('\n ')}`);
195
+ const notes = definitions.map(replace).join('\n\n');
196
+ return main + (notes ? '\n\n' + notes : '') + '\n';
197
+ }
198
+ export function decodeFootnote(encoded) {
199
+ if (encoded.length > 8000)
200
+ return;
201
+ try {
202
+ const data = JSON.parse(Buffer.from(encoded, 'base64').toString('utf8'));
203
+ if (data && typeof data.label === 'string' && /^[^\s\[\]\r\n]+$/.test(data.label) && typeof data.anchor === 'string' && /^[\p{L}\p{N}_-]+$/u.test(data.anchor) && (data.inline === undefined || typeof data.inline === 'boolean'))
204
+ return data;
205
+ }
206
+ catch { /* Preserve malformed metadata rather than consuming unrelated content. */ }
207
+ }
208
+ function safeDecode(value) { try {
209
+ return decodeURIComponent(value);
110
210
  }
211
+ catch {
212
+ return value;
213
+ } }
@@ -0,0 +1,26 @@
1
+ /** Shared Obsidian → Markdown preparation for convert and publishing. */
2
+ import { relative, dirname, resolve } from 'node:path';
3
+ import { vaultResolver } from '../documents/catalog.js';
4
+ import { resolveWikilinks } from '../documents/obsidian.js';
5
+ import { attachmentMapper } from './attachments.js';
6
+ import { footnotesToLinks } from './footnotes.js';
7
+ import { extractPdfPages, mapMarkdownText } from './pdf-pages.js';
8
+ export async function prepareMarkdown(text, file, base, vault, output, dryRun, attachments = attachmentMapper(file, base), restoreAssets = true) {
9
+ const slash = (path) => path.split('\\').join('/');
10
+ const rel = slash(relative(base, file)), lookup = vaultResolver(rel, vault);
11
+ text = attachments.rewrite(text);
12
+ text = resolveWikilinks(text, (target, embed) => {
13
+ const imported = resolve(base, target);
14
+ if (attachments.copies.has(slash(relative(base, imported))))
15
+ return slash(relative(dirname(file), imported));
16
+ return lookup(target, embed);
17
+ });
18
+ text = footnotesToLinks(attachments.rewrite(text));
19
+ mapMarkdownText(text, part => {
20
+ if (/\[\[[^\]\n]*\.pdf#page=[^\]\n]*\]\]/i.test(part))
21
+ throw new Error(`PDF 위키링크를 해석하지 못했습니다 (${rel}). --base에 PDF가 포함되는지 확인하세요.`);
22
+ return part;
23
+ });
24
+ const pdf = await extractPdfPages(text, file, base, output, dryRun, attachments.source, restoreAssets);
25
+ return { ...pdf, copies: attachments.copies };
26
+ }
@@ -1,25 +1,27 @@
1
+ import { documentAttachmentDir } from './asset-paths.js';
1
2
  import { createHash } from 'node:crypto';
2
3
  import { readFileSync, existsSync, realpathSync } from 'node:fs';
3
4
  import { resolve, relative, dirname } from 'node:path';
4
5
  import { renderPdfPages } from './pdf-renderer.js';
5
6
  import MarkdownIt from 'markdown-it';
6
7
  import { collectHeadings } from '../documents/anchors.js';
8
+ import { isConfluenceWebPath } from '../confluence/links.js';
7
9
  const encode = (value) => Buffer.from(JSON.stringify(value)).toString('base64');
8
10
  const decode = (value) => JSON.parse(Buffer.from(value, 'base64').toString());
9
11
  const parser = new MarkdownIt({ html: true });
10
12
  /** 소스 위치를 유지하면서 코드·HTML 블록을 제외한 일반 텍스트를 처리한다. */
11
- export function mapMarkdownText(text, fn) {
13
+ export function mapMarkdownText(text, fn, htmlFn) {
12
14
  const lines = text.split('\n'), offsets = [0];
13
15
  for (const line of lines)
14
16
  offsets.push(offsets[offsets.length - 1] + line.length + 1);
15
17
  const spans = parser.parse(text, {}).filter(t => ['fence', 'code_block', 'html_block'].includes(t.type) && t.map)
16
- .map(t => [offsets[t.map[0]], Math.min(offsets[t.map[1]], text.length)]);
18
+ .map(t => [offsets[t.map[0]], Math.min(offsets[t.map[1]], text.length), t.type === 'html_block' ? 1 : 0]);
17
19
  let cursor = 0, result = '';
18
20
  const prose = (s) => protectInline(s, fn);
19
- for (const [start, end] of spans) {
21
+ for (const [start, end, html] of spans) {
20
22
  if (start < cursor)
21
23
  continue;
22
- result += prose(text.slice(cursor, start)) + text.slice(start, end);
24
+ result += prose(text.slice(cursor, start)) + (html && htmlFn ? htmlFn(text.slice(start, end)) : text.slice(start, end));
23
25
  cursor = end;
24
26
  }
25
27
  return result + prose(text.slice(cursor));
@@ -76,7 +78,7 @@ function requireLocal(abs, base) {
76
78
  if (rel === '..' || rel.startsWith('../') || rel.startsWith('..\\'))
77
79
  throw new Error(`PDF는 --base 안에 있어야 합니다: ${abs}`);
78
80
  }
79
- export async function extractPdfPages(text, file, base, output, dryRun, source = p => p) {
81
+ export async function extractPdfPages(text, file, base, output, dryRun, source = p => p, restoreAssets = true) {
80
82
  const assets = new Set(), headings = new Set(collectHeadings(text).map(h => h.slug));
81
83
  const pages = new Map();
82
84
  const hashes = new Map();
@@ -93,7 +95,7 @@ export async function extractPdfPages(text, file, base, output, dryRun, source =
93
95
  catch {
94
96
  return all;
95
97
  }
96
- if (/^[a-z][a-z\d+.-]*:/i.test(dest))
98
+ if (/^[a-z][a-z\d+.-]*:/i.test(dest) || isConfluenceWebPath(dest))
97
99
  return all;
98
100
  const m = dest.match(/^(.*\.pdf)#page=(\d+)$/i);
99
101
  if (!m)
@@ -124,7 +126,7 @@ export async function extractPdfPages(text, file, base, output, dryRun, source =
124
126
  anchor = `${initialAnchor}-${suffix}`;
125
127
  }
126
128
  headings.add(anchor);
127
- const assetRel = `attachments/pdf-pages/pdfjs-${key}.png`;
129
+ const assetRel = `${documentAttachmentDir(file, base)}/pdfjs-${key}.png`;
128
130
  const target = resolve(output, assetRel);
129
131
  jobs.push({ file: abs, page, target });
130
132
  const outputFile = resolve(output, relative(base, file));
@@ -141,7 +143,7 @@ export async function extractPdfPages(text, file, base, output, dryRun, source =
141
143
  const withInlineImages = replaceGeneratedBlocks(text, /<!-- csync-footnote:v1 [A-Za-z0-9+/=]+ -->\n[\s\S]*?<!-- \/csync-footnote -->/g, block => convertLinks(block, true));
142
144
  const converted = convertLinks(withInlineImages, false);
143
145
  if (!pages.size)
144
- return { text, assets: restorePdfReferences(text, file, base).assets, pages: 0 };
146
+ return { text, assets: restoreAssets ? restorePdfReferences(text, file, base).assets : [], pages: 0 };
145
147
  await renderPdfPages(jobs, dryRun);
146
148
  const gallery = [...pages.values()].filter(p => p.gallery).map(p => `### ${p.heading}\n\n![${p.heading}](<${p.image}>)`).join('\n\n');
147
149
  return { text: converted.trimEnd() + (gallery ? `\n\n<!-- csync-pdf-pages:v1 -->\n${gallery}\n<!-- /csync-pdf-pages -->\n` : '\n'), assets: [...assets], pages: pages.size };
@@ -9,6 +9,7 @@
9
9
  * 대신 링크 대상이 되는 헤딩 앞에 **Anchor 매크로로 이름을 직접 심고**, 링크는 그 이름을 가리킨다.
10
10
  * 이름은 마크다운 슬러그를 그대로 쓰므로 왕복도 정확해진다 — 양쪽 다 우리가 정한 값이다.
11
11
  */
12
+ import { rewriteTableLinks } from './tables.js';
12
13
  const FENCE = /^\s*(?:```|~~~)/;
13
14
  /**
14
15
  * `[[대상]]` · `[[대상|별칭]]` · `[[대상#헤딩]]` · `[[#헤딩]]` · `![[임베드]]`
@@ -170,6 +171,14 @@ export function collectLinkAnchors(md) {
170
171
  out.push({ dest: w.target, fragment: w.fragment, wiki: true }); // dest 가 비면 같은 문서
171
172
  }
172
173
  }
174
+ rewriteTableLinks(md, href => {
175
+ const d = decodeAnchor(href);
176
+ const i = d.indexOf('#');
177
+ if (i >= 0 && i < d.length - 1 && !/^[a-z][a-z\d+.-]*:|^\/\//i.test(d)) {
178
+ out.push({ dest: d.slice(0, i), fragment: d.slice(i + 1), wiki: false });
179
+ }
180
+ return href;
181
+ });
173
182
  return out;
174
183
  }
175
184
  /** Anchor 매크로 — 링크 대상 헤딩 바로 앞에 심어 이름을 고정한다. */
@@ -0,0 +1,75 @@
1
+ /** Recover panel structure using rendered bodies and storage-only callout metadata. */
2
+ import { createDocument } from '@mixmark-io/domino';
3
+ import { calloutMarker, calloutStyle, inferCallout } from './callouts.js';
4
+ const direct = (el, name) => Array.from(el.children).find(child => child.nodeName.toLowerCase() === name);
5
+ function metadata(panel) {
6
+ const body = direct(panel, 'ac:rich-text-body');
7
+ const anchor = body && direct(body, 'ac:structured-macro');
8
+ if (anchor?.getAttribute('ac:name') !== 'anchor')
9
+ return;
10
+ const value = direct(anchor, 'ac:parameter')?.textContent ?? '';
11
+ if (!value.startsWith(calloutMarker) || value.length > 2000)
12
+ return;
13
+ try {
14
+ const data = JSON.parse(Buffer.from(value.slice(calloutMarker.length), 'base64url').toString('utf8'));
15
+ if (typeof data.type === 'string' && /^[a-z\d_-]+$/i.test(data.type) && ['', '+', '-'].includes(data.fold) && typeof data.explicit === 'boolean')
16
+ return data;
17
+ }
18
+ catch { /* Older or edited metadata is handled as an ordinary panel. */ }
19
+ }
20
+ function panelParts(panel) {
21
+ const children = Array.from(panel.children);
22
+ return { header: children.find(el => el.classList.contains('panelHeader')), body: children.find(el => el.classList.contains('panelContent')) };
23
+ }
24
+ export function restoreCalloutPanels(html, storage) {
25
+ const doc = createDocument(html);
26
+ for (const el of Array.from(doc.querySelectorAll('[data-csync-callout]')))
27
+ el.removeAttribute('data-csync-callout');
28
+ const panels = Array.from(doc.querySelectorAll('div.panel')).filter(panel => !!panelParts(panel).body);
29
+ // Storage is XML; protect code CDATA before parsing its macro hierarchy as HTML.
30
+ const safeStorage = storage?.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, (_all, text) => text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'));
31
+ const stored = safeStorage ? Array.from(createDocument(safeStorage).querySelectorAll('*')).filter(el => el.nodeName.toLowerCase() === 'ac:structured-macro' && el.getAttribute('ac:name') === 'panel') : [];
32
+ // Never shift metadata onto another panel if export_view omitted or added a panel.
33
+ const aligned = panels.length === stored.length;
34
+ panels.forEach((panel, i) => {
35
+ const { header, body } = panelParts(panel);
36
+ const title = header?.textContent?.trim() ?? '';
37
+ const source = aligned ? stored[i] : undefined;
38
+ const parameter = (name) => source && Array.from(source.children).find(el => el.nodeName.toLowerCase() === 'ac:parameter' && el.getAttribute('ac:name') === name)?.textContent?.trim();
39
+ const data = source && parameter('title') === title ? metadata(source) : undefined;
40
+ const background = parameter('bgColor') ?? '';
41
+ panel.setAttribute('data-csync-callout', JSON.stringify({ type: data?.type ?? inferCallout(title, background), fold: data?.fold ?? '', explicit: data?.explicit ?? true, title }));
42
+ // Our invisible anchor is metadata, never a Markdown link target or body text.
43
+ for (const anchor of Array.from(body.querySelectorAll('[id], [name]'))) {
44
+ if ((anchor.getAttribute('id') ?? '').includes(calloutMarker) || (anchor.getAttribute('name') ?? '').includes(calloutMarker))
45
+ anchor.remove();
46
+ }
47
+ for (const anchor of Array.from(body.querySelectorAll('*'))) {
48
+ if (anchor.nodeName.toLowerCase() === 'ac:structured-macro' && anchor.getAttribute('ac:name') === 'anchor' && direct(anchor, 'ac:parameter')?.textContent?.startsWith(calloutMarker))
49
+ anchor.remove();
50
+ }
51
+ });
52
+ return doc.body.innerHTML;
53
+ }
54
+ export function installPanelRule(td, obsidian) {
55
+ // Keep the header in the DOM until conversion so title-only panels are not blank.
56
+ td.addRule('confluencePanelTitle', {
57
+ filter: node => {
58
+ const el = node;
59
+ return !!el.classList?.contains('panelHeader') && !!el.parentElement?.hasAttribute('data-csync-callout');
60
+ },
61
+ replacement: () => '',
62
+ });
63
+ td.addRule('confluencePanel', {
64
+ filter: node => node.hasAttribute?.('data-csync-callout') ?? false,
65
+ replacement: (content, node) => {
66
+ const { type, fold, explicit, title } = JSON.parse(node.getAttribute('data-csync-callout'));
67
+ const textTitle = String(title).replace(/[\r\n]+/g, ' ').trim();
68
+ const quote = (text) => text.split('\n').map(line => line ? `> ${line}` : '>').join('\n');
69
+ const head = obsidian
70
+ ? `[!${type}]${fold}${textTitle && (explicit || textTitle !== calloutStyle(type).title) ? ` ${textTitle}` : ''}`
71
+ : textTitle ? `**${td.escape(textTitle)}**` : '';
72
+ return `\n\n${quote([head, content.trim()].filter(Boolean).join(obsidian ? '\n' : '\n\n'))}\n\n`;
73
+ },
74
+ });
75
+ }
@@ -0,0 +1,74 @@
1
+ import { anchorMacro } from './anchors.js';
2
+ export const calloutMarker = 'csync-callout-v1-';
3
+ const styles = {
4
+ note: { title: '노트', color: '#526078', background: '#f4f5f7' },
5
+ abstract: { title: '요약', color: '#006b76', background: '#e6fcff' },
6
+ info: { title: '안내', color: '#0747a6', background: '#deebff' },
7
+ todo: { title: '할 일', color: '#0747a6', background: '#deebff' },
8
+ tip: { title: '팁', color: '#006b76', background: '#e6fcff' },
9
+ success: { title: '성공', color: '#006644', background: '#e3fcef' },
10
+ question: { title: '질문', color: '#974f0c', background: '#fff0b3' },
11
+ warning: { title: '주의', color: '#974f0c', background: '#fff0b3' },
12
+ failure: { title: '실패', color: '#ae2a19', background: '#ffebe6' },
13
+ danger: { title: '위험', color: '#ae2a19', background: '#ffebe6' },
14
+ bug: { title: '버그', color: '#ae2a19', background: '#ffebe6' },
15
+ example: { title: '예시', color: '#403294', background: '#eae6ff' },
16
+ quote: { title: '인용', color: '#526078', background: '#f4f5f7' },
17
+ };
18
+ const aliases = { summary: 'abstract', tldr: 'abstract', hint: 'tip', important: 'tip', check: 'success', done: 'success', help: 'question', faq: 'question', caution: 'warning', attention: 'warning', fail: 'failure', missing: 'failure', error: 'danger', cite: 'quote' };
19
+ export function calloutStyle(raw) {
20
+ const type = Object.hasOwn(aliases, raw.toLowerCase()) ? aliases[raw.toLowerCase()] : raw.toLowerCase();
21
+ return Object.hasOwn(styles, type) ? styles[type] : styles.note;
22
+ }
23
+ export function inferCallout(title, background) {
24
+ return Object.entries(styles).find(([, style]) => style.title === title && style.background === background.toLowerCase())?.[0] ?? 'note';
25
+ }
26
+ const escape = (value) => value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
27
+ /** Transform actual quote tokens, leaving code examples and ordinary quotes untouched. */
28
+ export function installCallouts(md, format) {
29
+ md.core.ruler.after('inline', 'obsidian_callouts', state => {
30
+ // Compatibility rendering is read-only and only used to verify older baselines.
31
+ if (state.env?.legacyCallouts === true)
32
+ return;
33
+ const tokens = state.tokens;
34
+ let serial = 0;
35
+ for (let i = 0; i < tokens.length; i++) {
36
+ if (tokens[i].type !== 'blockquote_open' || tokens[i + 1]?.type !== 'paragraph_open' || tokens[i + 2]?.type !== 'inline' || tokens[i + 3]?.type !== 'paragraph_close')
37
+ continue;
38
+ const inline = tokens[i + 2], newline = inline.content.indexOf('\n');
39
+ const header = newline < 0 ? inline.content : inline.content.slice(0, newline);
40
+ const match = header.match(/^\[!([a-z\d_-]+)\]([+-]?)(?:[ \t]+(.*))?[ \t]*$/i);
41
+ if (!match)
42
+ continue;
43
+ let end = i + 1, depth = 1;
44
+ for (; end < tokens.length; end++) {
45
+ if (tokens[end].type === 'blockquote_open')
46
+ depth++;
47
+ if (tokens[end].type === 'blockquote_close' && --depth === 0)
48
+ break;
49
+ }
50
+ if (end === tokens.length)
51
+ continue;
52
+ const style = calloutStyle(match[1]);
53
+ const marker = format === 'html' || state.env?.legacyCallouts === 'panels' ? '' : anchorMacro(calloutMarker + Buffer.from(JSON.stringify({ type: match[1], fold: match[2], explicit: !!match[3]?.trim(), index: serial++ })).toString('base64url'));
54
+ tokens[i].type = 'callout_open';
55
+ tokens[i].meta = { ...style, title: match[3]?.trim() || style.title, marker };
56
+ tokens[end].type = 'callout_close';
57
+ if (newline < 0)
58
+ tokens.splice(i + 1, 3);
59
+ else {
60
+ inline.content = inline.content.slice(newline + 1);
61
+ inline.children = [];
62
+ state.md.inline.parse(inline.content, state.md, state.env, inline.children);
63
+ }
64
+ }
65
+ });
66
+ md.renderer.rules.callout_open = (tokens, idx) => {
67
+ const { title, color, background, marker } = tokens[idx].meta;
68
+ if (format === 'html')
69
+ return `<blockquote style="background-color:${background};color:${color}"><p><strong>${escape(title)}</strong></p>\n`;
70
+ const parameter = (name, value) => `<ac:parameter ac:name="${name}">${escape(value)}</ac:parameter>`;
71
+ return '<ac:structured-macro ac:name="panel">' + parameter('title', title) + parameter('borderColor', color) + parameter('titleColor', color) + parameter('titleBGColor', background) + parameter('bgColor', background) + '<ac:rich-text-body>\n' + marker;
72
+ };
73
+ md.renderer.rules.callout_close = () => format === 'html' ? '</blockquote>\n' : '</ac:rich-text-body></ac:structured-macro>\n';
74
+ }
@@ -168,7 +168,7 @@ export function buildFolderIndex(rels) {
168
168
  const parentDirOf = (dir) => (dir.includes('/') ? dir.slice(0, dir.lastIndexOf('/')) : '');
169
169
  /**
170
170
  * dir 의 직계 자식을 담는 "컨테이너"의 mapping 키.
171
- * - 루트('') → null (CONFLUENCE_PARENT_ID)
171
+ * - 루트('') → null (저장된 원격 스코프)
172
172
  * - README 가 있는 폴더 → 그 README 페이지 키
173
173
  * - README 가 없는 폴더 → 폴더 노드 키(`<dir>/`, 끝에 슬래시로 구분)
174
174
  */
@@ -226,7 +226,7 @@ export function resolveSelection(rels, positionals, baseDir) {
226
226
  console.error(` ⚠ base 밖 경로 무시: ${p}`);
227
227
  continue;
228
228
  }
229
- const matched = rels.filter((r) => r === relToBase || r.startsWith(relToBase + '/'));
229
+ const matched = rels.filter((r) => !relToBase || r === relToBase || r.startsWith(relToBase + '/'));
230
230
  if (matched.length === 0)
231
231
  console.error(` ⚠ 매칭되는 문서 없음: ${p}`);
232
232
  matched.forEach((m) => set.add(m));
@@ -0,0 +1,96 @@
1
+ /** Footnote restoration metadata uses native invisible Confluence anchors. */
2
+ import { createDocument } from '@mixmark-io/domino';
3
+ import { anchorMacro, matchConfluenceAnchor } from './anchors.js';
4
+ import { decodeFootnote } from '../conversion/footnotes.js';
5
+ const prefix = 'csync-footnote-v1-';
6
+ const startComment = (encoded) => `<!-- csync-footnote:v1 ${encoded} -->`;
7
+ const endComment = '<!-- /csync-footnote -->';
8
+ const markerName = (encoded, end) => prefix + (end ? 'end-' : 'start-') + Buffer.from(encoded, 'base64').toString('base64url');
9
+ /** CDATA code examples and unrelated comments are never rewritten. */
10
+ export function footnotesToStorage(storage) {
11
+ let current;
12
+ return storage.replace(/<!\[CDATA\[[\s\S]*?\]\]>|<!-- csync-footnote:v1 ([A-Za-z0-9+/=]+) -->|<!-- \/csync-footnote -->/g, (whole, encoded) => {
13
+ if (encoded) {
14
+ if (!decodeFootnote(encoded))
15
+ return whole;
16
+ current = encoded;
17
+ return anchorMacro(markerName(encoded, false));
18
+ }
19
+ if (whole === endComment && current) {
20
+ const end = anchorMacro(markerName(current, true));
21
+ current = undefined;
22
+ return end;
23
+ }
24
+ return whole;
25
+ });
26
+ }
27
+ /** Keep pre-metadata document hashes stable; the visible body is still hashed. */
28
+ export function footnoteStorageComments(storage) {
29
+ return storage.replace(/<!\[CDATA\[[\s\S]*?\]\]>|<ac:structured-macro ac:name="anchor"><ac:parameter ac:name="">csync-footnote-v1-(start|end)-([A-Za-z0-9_-]+)<\/ac:parameter><\/ac:structured-macro>/g, (whole, kind, encoded) => {
30
+ if (!kind || !encoded)
31
+ return whole;
32
+ const base64 = Buffer.from(encoded, 'base64url').toString('base64');
33
+ return decodeFootnote(base64) ? kind === 'start' ? startComment(base64) : endComment : whole;
34
+ });
35
+ }
36
+ export function restoreFootnoteAnchors(html, storage, pageId) {
37
+ const doc = createDocument(html);
38
+ for (const node of Array.from(doc.querySelectorAll('[data-csync-footnote]')))
39
+ node.removeAttribute('data-csync-footnote');
40
+ if (!storage?.includes(prefix))
41
+ return doc.body.innerHTML;
42
+ const names = new Map();
43
+ // Only accept markers paired in storage, not look-alike anchors in the rendered body.
44
+ const starts = new Set(), ends = new Set();
45
+ for (const match of storage.matchAll(/<ac:structured-macro\b[^>]*ac:name="anchor"[^>]*>\s*<ac:parameter\b[^>]*ac:name=""[^>]*>csync-footnote-v1-(start|end)-([A-Za-z0-9_-]+)<\/ac:parameter>\s*<\/ac:structured-macro>/g)) {
46
+ const encoded = Buffer.from(match[2], 'base64url').toString('base64');
47
+ if (decodeFootnote(encoded))
48
+ (match[1] === 'start' ? starts : ends).add(encoded);
49
+ }
50
+ for (const encoded of starts)
51
+ if (ends.has(encoded)) {
52
+ names.set(markerName(encoded, false), { encoded, end: false });
53
+ names.set(markerName(encoded, true), { encoded, end: true });
54
+ }
55
+ if (!names.size)
56
+ return doc.body.innerHTML;
57
+ const found = new Map();
58
+ for (const node of Array.from(doc.querySelectorAll('[id], [name]'))) {
59
+ const id = node.getAttribute('id') ?? node.getAttribute('name') ?? '';
60
+ const entry = [...names].find(([name]) => id.endsWith(name));
61
+ if (entry) {
62
+ const nodes = found.get(entry[0]) ?? [];
63
+ nodes.push(node);
64
+ found.set(entry[0], nodes);
65
+ }
66
+ }
67
+ const active = [...starts].filter(encoded => found.get(markerName(encoded, false))?.length === 1 && found.get(markerName(encoded, true))?.length === 1);
68
+ const headings = active.map(encoded => { const meta = decodeFootnote(encoded); return { text: meta.anchor, slug: meta.anchor, level: 6 }; });
69
+ for (const link of Array.from(doc.querySelectorAll('sup a[href]'))) {
70
+ const href = link.getAttribute('href');
71
+ const target = href.match(/\/pages\/(\d+)/)?.[1] ?? href.match(/[?&]pageId=(\d+)/)?.[1];
72
+ if (!href.startsWith('#') && (!pageId || target !== pageId))
73
+ continue;
74
+ const fragment = href.split('#').slice(1).join('#');
75
+ const match = matchConfluenceAnchor(fragment, headings, '');
76
+ if (match)
77
+ link.setAttribute('href', `#${match.slug}`);
78
+ }
79
+ for (const encoded of active)
80
+ for (const end of [false, true]) {
81
+ const node = found.get(markerName(encoded, end))[0];
82
+ node.setAttribute('data-csync-footnote', JSON.stringify({ encoded, end }));
83
+ node.textContent = 'csync-footnote-marker';
84
+ }
85
+ return doc.body.innerHTML;
86
+ }
87
+ export function installFootnoteRules(td) {
88
+ td.addRule('confluenceFootnoteMetadata', {
89
+ filter: node => !!node.hasAttribute?.('data-csync-footnote'),
90
+ replacement: (_content, node) => {
91
+ const { encoded, end } = JSON.parse(node.getAttribute('data-csync-footnote'));
92
+ return `\n\n${end ? endComment : startComment(encoded)}\n\n`;
93
+ },
94
+ });
95
+ td.addRule('superscript', { filter: 'sup', replacement: content => `<sup>${content}</sup>` });
96
+ }