@wonseok-han/confluence-sync 1.7.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 -409
  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 +157 -86
  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 +83 -12
  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 +262 -207
  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 +365 -71
  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
@@ -0,0 +1,116 @@
1
+ /** Conservative source formatting: preserve code, HTML, frontmatter and link targets. */
2
+ import MarkdownIt from 'markdown-it';
3
+ import { splitFrontmatter } from './obsidian.js';
4
+ import { relaxEscapes } from './html-to-markdown.js';
5
+ const parser = new MarkdownIt({ html: true });
6
+ const width = (s) => Array.from(s).reduce((n, c) => n + (/\p{Script=Hangul}|\p{Script=Han}/u.test(c) ? 2 : 1), 0);
7
+ function cells(line) {
8
+ const result = [];
9
+ let part = '', slashes = 0, ticks = 0;
10
+ for (let i = 0; i < line.length; i++) {
11
+ const c = line[i];
12
+ if (c === '`' && slashes % 2 === 0) {
13
+ let end = i;
14
+ while (line[end] === '`')
15
+ end++;
16
+ const size = end - i;
17
+ ticks = ticks === size ? 0 : ticks || size;
18
+ part += line.slice(i, end);
19
+ i = end - 1;
20
+ slashes = 0;
21
+ continue;
22
+ }
23
+ if (c === '|' && !ticks && slashes % 2 === 0) {
24
+ result.push(part.trim());
25
+ part = '';
26
+ }
27
+ else
28
+ part += c;
29
+ slashes = c === '\\' ? slashes + 1 : 0;
30
+ }
31
+ result.push(part.trim());
32
+ if (line.trimStart().startsWith('|'))
33
+ result.shift();
34
+ if (line.trimEnd().endsWith('|') && !result.at(-1))
35
+ result.pop();
36
+ return result;
37
+ }
38
+ export function formatDocument(source) {
39
+ const { body } = splitFrontmatter(source);
40
+ const frontmatter = source.slice(0, source.length - body.length);
41
+ const separator = frontmatter ? body.match(/^(?:[ \t]*\r?\n)*/)?.[0] ?? '' : '';
42
+ const prefix = frontmatter + separator;
43
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
44
+ const text = body.slice(separator.length).replace(/\r\n/g, '\n'), lines = text.split('\n'), tokens = parser.parse(text, {});
45
+ const protectedLines = new Set(), rawHtmlLines = new Set(), headings = new Set();
46
+ // Raw HTML tables can contain blank lines that end a Markdown HTML token.
47
+ let tableStart = -1, tableDepth = 0;
48
+ for (const tag of text.matchAll(/<\/?table\b(?:[^"'<>]|"[^"]*"|'[^']*')*>/gi)) {
49
+ if (!tag[0].startsWith('</')) {
50
+ if (tableDepth++ === 0)
51
+ tableStart = tag.index;
52
+ }
53
+ else if (tableDepth && --tableDepth === 0) {
54
+ const start = text.slice(0, tableStart).split('\n').length - 1;
55
+ const end = text.slice(0, tag.index + tag[0].length).split('\n').length;
56
+ for (let i = start; i < end; i++) {
57
+ protectedLines.add(i);
58
+ rawHtmlLines.add(i);
59
+ }
60
+ }
61
+ }
62
+ // Inline code may span lines; keep its entire source lines untouched.
63
+ for (const match of text.matchAll(/(`+)([\s\S]*?)(?<!`)\1(?!`)/g)) {
64
+ const start = text.slice(0, match.index).split('\n').length - 1;
65
+ const end = start + match[0].split('\n').length;
66
+ for (let i = start; i < end; i++)
67
+ protectedLines.add(i);
68
+ }
69
+ for (const token of tokens) {
70
+ if (!token.map)
71
+ continue;
72
+ const [start, end] = token.map;
73
+ if (['fence', 'code_block', 'html_block', 'table_open'].includes(token.type)) {
74
+ for (let i = start; i < end; i++)
75
+ protectedLines.add(i);
76
+ }
77
+ if (token.type === 'heading_open' && !protectedLines.has(start) && token.level === 0 && end === start + 1 && /^ {0,3}#{1,6}\s/.test(lines[start])) {
78
+ headings.add(start);
79
+ lines[start] = lines[start].replace(/^ {0,3}(#{1,6})[ \t]+(.*?)(?:[ \t]+#+[ \t]*)?$/, '$1 $2');
80
+ }
81
+ if (token.type === 'list_item_open' && !protectedLines.has(start))
82
+ lines[start] = lines[start].replace(/^(\s*)(?:[-+*](\s+)|(\d+)[.)](\s+))/, (_m, indent, space, number, orderedSpace) => indent + (number ? number + '.' + orderedSpace : '-' + space));
83
+ if (token.type === 'table_open' && !rawHtmlLines.has(start) && token.level === 0) {
84
+ const rows = lines.slice(start, end).map(cells), count = rows[0]?.length;
85
+ if (count && rows.every(row => row.length === count)) {
86
+ const sizes = Array.from({ length: count }, (_, i) => Math.max(3, ...rows.map(row => width(row[i]))));
87
+ const formatted = rows.map((row, r) => '| ' + row.map((cell, i) => r === 1
88
+ ? (cell.startsWith(':') ? ':' : '') + '-'.repeat(Math.max(3, sizes[i] - Number(cell.startsWith(':')) - Number(cell.endsWith(':')))) + (cell.endsWith(':') ? ':' : '')
89
+ : cell + ' '.repeat(sizes[i] - width(cell))).join(' | ') + ' |');
90
+ if (parser.render(formatted.join('\n')) === parser.render(lines.slice(start, end).join('\n')))
91
+ lines.splice(start, end - start, ...formatted);
92
+ }
93
+ }
94
+ }
95
+ const out = [];
96
+ for (let i = 0; i < lines.length; i++) {
97
+ if (protectedLines.has(i)) {
98
+ out.push(lines[i]);
99
+ continue;
100
+ }
101
+ let line = lines[i].replace(/[\t ]+$/, m => / {2,}$/.test(m) && lines[i].trim() ? ' ' : '');
102
+ // Keep Markdown hard breaks; avoid link destinations, wiki targets and inline HTML.
103
+ if (!/[\[\]<>`]/.test(line) && !/^ {0,3}(?:>|[-+*]\s|\d+[.)]\s)/.test(line))
104
+ line = relaxEscapes(line);
105
+ if (!line.trim() && !out.at(-1)?.trim())
106
+ continue;
107
+ if (headings.has(i) && out.length && out.at(-1)?.trim())
108
+ out.push('');
109
+ out.push(line);
110
+ if (headings.has(i) && i + 1 < lines.length && lines[i + 1].trim())
111
+ out.push('');
112
+ }
113
+ while (out.length && !out.at(-1)?.trim())
114
+ out.pop();
115
+ return prefix + (out.length ? out.join(eol) + eol : '');
116
+ }
@@ -0,0 +1,30 @@
1
+ import MarkdownIt from 'markdown-it';
2
+ import { installCallouts } from './callouts.js';
3
+ /** Keep a raw table in one token, including blank lines between its rows. */
4
+ export function htmlTableMarkdown(format = 'html') {
5
+ const md = new MarkdownIt({ html: true, linkify: true, breaks: false });
6
+ md.block.ruler.before('html_block', 'html_table', (state, start, end, silent) => {
7
+ if (state.sCount[start] - state.blkIndent >= 4)
8
+ return false;
9
+ const source = state.getLines(start, end, state.blkIndent, false);
10
+ if (!/^ {0,3}<table(?:\s|>)/i.test(source))
11
+ return false;
12
+ let depth = 0;
13
+ for (const match of source.matchAll(/<\/?table\b(?:[^"'<>]|"[^"]*"|'[^']*')*>/gi)) {
14
+ depth += /^<\//.test(match[0]) ? -1 : 1;
15
+ if (depth)
16
+ continue;
17
+ if (silent)
18
+ return true;
19
+ const next = start + source.slice(0, match.index + match[0].length).split('\n').length;
20
+ const token = state.push('html_block', '', 0);
21
+ token.content = state.getLines(start, next, state.blkIndent, true);
22
+ token.map = [start, next];
23
+ state.line = next;
24
+ return true;
25
+ }
26
+ return false;
27
+ });
28
+ installCallouts(md, format);
29
+ return md;
30
+ }
@@ -4,6 +4,12 @@
4
4
  * storage/export_view 는 무손실 역변환이 아니므로 근사 결과다.
5
5
  */
6
6
  import TurndownService from 'turndown';
7
+ import { restoreFootnoteAnchors, installFootnoteRules } from './footnote-roundtrip.js';
8
+ import { linksToFootnotes } from '../conversion/footnotes.js';
9
+ import { mapMarkdownText } from '../conversion/pdf-pages.js';
10
+ import { restoreCalloutPanels, installPanelRule } from './callout-roundtrip.js';
11
+ import MarkdownIt from 'markdown-it';
12
+ import { applyTableWidths, hasWidths, tableWidths, restoreTableWidths } from './tables.js';
7
13
  /** storage(XHTML)의 code 매크로들에서 language 파라미터를 문서 순서대로 추출(미지정은 ''). */
8
14
  export function codeLanguagesFromStorage(storage) {
9
15
  const out = [];
@@ -23,16 +29,9 @@ const linkDest = (p) => (/\s/.test(p) ? `<${p}>` : p);
23
29
  * 줄 맨 앞의 진짜 마커 이스케이프는 보존하고, 그 뒤(줄 중간)의 것만 되돌린다. 코드블록은 건드리지 않는다.
24
30
  */
25
31
  export function relaxEscapes(md) {
26
- let inFence = false;
27
- return md
32
+ return mapMarkdownText(md, prose => prose
28
33
  .split('\n')
29
34
  .map((line) => {
30
- if (/^\s*```/.test(line)) {
31
- inFence = !inFence;
32
- return line;
33
- }
34
- if (inFence)
35
- return line;
36
35
  // 들여쓰기 + (줄 맨 앞의 이스케이프된 마커) 까지는 그대로 두고 이후만 완화
37
36
  const head = line.match(/^\s*(?:\\[-+>#]|\d+\\\.)?/)?.[0] ?? '';
38
37
  const rest = line
@@ -40,14 +39,16 @@ export function relaxEscapes(md) {
40
39
  // 줄 중간의 - + . > 는 마커가 아니므로 이스케이프 불필요
41
40
  .replace(/\\([-+.>])/g, '$1')
42
41
  // 단어 내부 밑줄은 CommonMark 에서 강조가 아니다 (:11_eleven_square_blue: 같은 이모지 코드)
43
- .replace(/(\w)\\_(?=\w)/g, '$1_')
42
+ .replace(/(?<=[\p{L}\p{N}\p{M}_])(?:\\_)+(?=[\p{L}\p{N}\p{M}_])/gu, run => run.replace(/\\/g, ''))
44
43
  // 링크가 아닌 대괄호 쌍(뒤에 ( 나 [ 가 오지 않음)은 이스케이프 불필요
45
44
  .replace(/\\\[([^[\]\n]*)\\\](?!\s*[([])/g, '[$1]');
46
45
  return head + rest;
47
46
  })
48
- .join('\n');
47
+ .join('\n'));
49
48
  }
50
49
  export function htmlToMarkdown(html, opts = {}) {
50
+ html = restoreFootnoteAnchors(restoreCalloutPanels(restoreTableWidths(html, opts.storage), opts.storage), opts.storage, opts.pageId);
51
+ const cellRenderer = new MarkdownIt({ html: true });
51
52
  const td = new TurndownService({
52
53
  headingStyle: 'atx',
53
54
  codeBlockStyle: 'fenced',
@@ -55,6 +56,8 @@ export function htmlToMarkdown(html, opts = {}) {
55
56
  hr: '---',
56
57
  emDelimiter: '_',
57
58
  });
59
+ installPanelRule(td, opts.obsidian ?? false);
60
+ installFootnoteRules(td);
58
61
  // Confluence export_view 는 색상 텍스트용 인라인 <style> 을 본문(제목 안까지) 끼워 넣는다.
59
62
  // turndown 은 기본적으로 이런 요소의 텍스트를 그대로 뱉으므로 통째로 제거한다.
60
63
  td.remove(['style', 'script', 'noscript', 'head', 'meta', 'link']);
@@ -62,7 +65,7 @@ export function htmlToMarkdown(html, opts = {}) {
62
65
  // 그러나 단어 내부 밑줄은 CommonMark 에서 강조가 아니므로(:11_eleven_square_blue: 같은 이모지 코드)
63
66
  // 양쪽이 단어 문자인 경우만 이스케이프를 되돌린다.
64
67
  const baseEscape = td.escape.bind(td);
65
- td.escape = (s) => baseEscape(s).replace(/(\w)\\_(?=\w)/g, '$1_');
68
+ td.escape = (s) => baseEscape(s).replace(/(?<=[\p{L}\p{N}\p{M}_])(?:\\_)+(?=[\p{L}\p{N}\p{M}_])/gu, run => run.replace(/\\/g, ''));
66
69
  // Confluence 는 리스트 항목 내용을 <li><p>…</p></li> 로 감싼다.
67
70
  // 기본 규칙대로면 문단으로 취급돼 항목마다 빈 줄이 생기므로(loose list),
68
71
  // li 안의 첫 문단은 빈 줄 없이 붙인다(두 번째 이후 문단은 기존대로 분리).
@@ -106,6 +109,10 @@ export function htmlToMarkdown(html, opts = {}) {
106
109
  const alt = el.getAttribute('alt') || '';
107
110
  const isAttachment = el.getAttribute('data-linked-resource-type') === 'attachment' ||
108
111
  /\/download\/(attachments|thumbnails)\//.test(src);
112
+ // export_view may include a Confluence macro loading indicator, not a page attachment.
113
+ if (!isAttachment && /(?:^|\s)waiting-image(?:\s|$)/.test(el.getAttribute('class') || '')
114
+ && /\/images\/icons\/wait\.gif(?:[?#]|$)/i.test(src))
115
+ return '';
109
116
  if (!isAttachment && /^https?:\/\//i.test(src)) {
110
117
  return `![${alt}](${linkDest(src)})`;
111
118
  }
@@ -113,7 +120,7 @@ export function htmlToMarkdown(html, opts = {}) {
113
120
  const name = alias || decodeURIComponent((src.split('?')[0].split('/').pop() || '').trim());
114
121
  if (name)
115
122
  opts.onImage?.(name);
116
- const dest = opts.assetPrefix ? `${opts.assetPrefix}/${name}` : name;
123
+ const dest = opts.attachmentDestination?.(name, src) ?? (opts.assetPrefix ? `${opts.assetPrefix}/${name}` : name);
117
124
  return `![${alt || name}](${linkDest(dest)})`;
118
125
  },
119
126
  });
@@ -121,6 +128,32 @@ export function htmlToMarkdown(html, opts = {}) {
121
128
  td.addRule('confTable', {
122
129
  filter: 'table',
123
130
  replacement: (_content, node) => {
131
+ const table = node;
132
+ const widths = tableWidths(table);
133
+ if (hasWidths(widths) || table.querySelector('th[colspan], td[colspan], th[rowspan], td[rowspan]')) {
134
+ // Reuse conversion rules for links/images, then encode the cells as HTML.
135
+ // Markdown inside a raw HTML block is not portable.
136
+ const copy = table.cloneNode(true);
137
+ for (const anchor of Array.from(copy.querySelectorAll('a[href]'))) {
138
+ const href = anchor.getAttribute('href');
139
+ if (!/\/download\/attachments\//.test(href))
140
+ continue;
141
+ const name = anchor.getAttribute('data-linked-resource-default-alias')
142
+ || decodeURIComponent(href.split('?')[0].split('#')[0].split('/').pop() || '');
143
+ if (!name)
144
+ continue;
145
+ opts.onImage?.(name);
146
+ anchor.setAttribute('href', opts.attachmentDestination?.(name, href) ?? (opts.assetPrefix ? `${opts.assetPrefix}/${name}` : name));
147
+ }
148
+ for (const cell of Array.from(copy.querySelectorAll('th, td'))) {
149
+ cell.innerHTML = cellRenderer.render(td.turndown(cell.innerHTML));
150
+ }
151
+ applyTableWidths(copy, widths);
152
+ copy.removeAttribute('data-table-width');
153
+ copy.removeAttribute('data-layout');
154
+ copy.removeAttribute('ac:local-id');
155
+ return `\n\n${copy.outerHTML}\n\n`;
156
+ }
124
157
  const cell = (c) => td.turndown(c.innerHTML || '').replace(/\n+/g, ' ').replace(/\|/g, '\\|').trim();
125
158
  const trs = Array.from(node.querySelectorAll('tr'));
126
159
  const matrix = trs.map((r) => Array.from(r.children).filter((c) => c.nodeName === 'TD' || c.nodeName === 'TH').map(cell));
@@ -135,5 +168,6 @@ export function htmlToMarkdown(html, opts = {}) {
135
168
  return `${out}\n`;
136
169
  },
137
170
  });
138
- return relaxEscapes(td.turndown(html)).trim() + '\n';
171
+ const result = relaxEscapes(td.turndown(html)).trim() + '\n';
172
+ return opts.obsidian ? linksToFootnotes(result) : result;
139
173
  }
@@ -5,10 +5,15 @@
5
5
  * - 로컬 이미지 → 첨부 참조(ri:attachment), 외부 URL 이미지는 그대로
6
6
  * 모든 경로는 baseDir 기준 상대경로로 해석한다.
7
7
  */
8
- import { readFileSync, existsSync } from 'node:fs';
9
- import { resolve, relative, dirname, basename } from 'node:path';
8
+ import { readFileSync, existsSync, statSync } from 'node:fs';
9
+ import { resolve, relative, dirname, basename, extname } from 'node:path';
10
10
  import { createHash } from 'node:crypto';
11
- import MarkdownIt from 'markdown-it';
11
+ import { isConfluenceWebPath } from '../confluence/links.js';
12
+ import { htmlTableMarkdown } from './html-tables.js';
13
+ import Token from 'markdown-it/lib/token.mjs';
14
+ import { footnotesToStorage, footnoteStorageComments } from './footnote-roundtrip.js';
15
+ import { createDocument } from '@mixmark-io/domino';
16
+ import { applyTableWidths, hasWidths, tableWidths } from './tables.js';
12
17
  import { resolveWikilinks } from './obsidian.js';
13
18
  import { decodeAnchor, anchorMacro } from './anchors.js';
14
19
  import { mermaidMacro } from './mermaid.js';
@@ -23,11 +28,11 @@ const decodePath = (s) => {
23
28
  return s;
24
29
  }
25
30
  };
26
- const md = new MarkdownIt({ html: true, linkify: true, breaks: false });
31
+ const md = htmlTableMarkdown('storage');
27
32
  const emptyCtx = () => ({
28
33
  fileDir: '', titleIndex: {}, anchorIndex: {}, selfRel: '', selfTitle: '',
29
34
  anchorNames: new Set(), bodySlugs: [], headingSeq: 0, mermaidSeq: 0, anchorsPlaced: 0,
30
- images: [], internalLinks: 0, anchorLinks: 0, deadAnchors: [], linkStack: [], linkedTitles: new Set(),
35
+ images: [], attachments: [], internalLinks: 0, anchorLinks: 0, deadAnchors: [], linkStack: [], linkedTitles: new Set(),
31
36
  });
32
37
  // 렌더 규칙은 md 인스턴스에 한 번만 등록되므로, 현재 변환 컨텍스트를 모듈 변수로 공유한다.
33
38
  let ctx = emptyCtx();
@@ -91,8 +96,29 @@ md.renderer.rules.fence = (tokens, idx) => {
91
96
  const code = `<ac:structured-macro ac:name="code">${langParam}<ac:plain-text-body><![CDATA[${safe}]]></ac:plain-text-body></ac:structured-macro>\n`;
92
97
  return code + (lang === 'mermaid' ? mermaidMacro(ctx.selfRel, ctx.mermaidSeq++) : '');
93
98
  };
99
+ /** 페이지 첨부 이름은 유일해야 한다. 동일 경로는 한 번만 업로드한다. */
100
+ function addAttachment(abs) {
101
+ const existing = ctx.attachments.find(a => a.abs === abs);
102
+ if (existing)
103
+ return existing.filename;
104
+ let filename = basename(abs);
105
+ if (ctx.attachments.some(a => a.filename === filename)) {
106
+ const ext = extname(filename), stem = basename(filename, ext);
107
+ const suffix = hashOf(relative(baseDir, abs).split('\\').join('/')).slice(0, 12);
108
+ filename = `${stem}-${suffix}${ext}`;
109
+ let n = 1;
110
+ while (ctx.attachments.some(a => a.filename === filename))
111
+ filename = `${stem}-${suffix}-${n++}${ext}`;
112
+ }
113
+ ctx.attachments.push({ filename, abs });
114
+ return filename;
115
+ }
94
116
  md.renderer.rules.link_open = (tokens, idx, opts, _env, self) => {
95
117
  const originalHref = tokens[idx].attrGet('href') || '';
118
+ if (isConfluenceWebPath(originalHref)) {
119
+ ctx.linkStack.push(false);
120
+ return self.renderToken(tokens, idx, opts);
121
+ }
96
122
  const href = ctx.rewriteHref?.(originalHref) ?? originalHref;
97
123
  tokens[idx].attrSet('href', href);
98
124
  const t = resolveInternalLink(href);
@@ -109,6 +135,17 @@ md.renderer.rules.link_open = (tokens, idx, opts, _env, self) => {
109
135
  const page = t.title ? `<ri:page ri:content-title="${escapeXml(t.title)}" />` : '';
110
136
  return `<ac:link${anchor}>${page}<ac:link-body>`;
111
137
  }
138
+ // 일반 로컬 파일 링크도 첨부로 전환한다. 문서·외부 URL·없는 대상은 유지한다.
139
+ const path = href.split('#')[0];
140
+ if (path && !/^[a-z][a-z\d+.-]*:|^\/\//i.test(path) && !/\.md$/i.test(decodePath(path))) {
141
+ const abs = resolve(baseDir, ctx.fileDir, decodePath(path));
142
+ if (existsSync(abs) && statSync(abs).isFile()) {
143
+ const filename = addAttachment(abs);
144
+ ctx.linkStack.push(true);
145
+ const fragment = href.includes('#') ? ` ac:anchor="${escapeXml(decodePath(href.slice(href.indexOf('#') + 1)))}"` : '';
146
+ return `<ac:link${fragment}><ri:attachment ri:filename="${escapeXml(filename)}" /><ac:link-body>`;
147
+ }
148
+ }
112
149
  ctx.linkStack.push(false);
113
150
  return self.renderToken(tokens, idx, opts);
114
151
  };
@@ -128,10 +165,43 @@ md.renderer.rules.image = (tokens, idx) => {
128
165
  }
129
166
  // markdown-it 이 링크 경로를 퍼센트 인코딩하므로 디코드해서 실제 파일명/경로로 복원(한글·공백 대응)
130
167
  const abs = resolve(baseDir, ctx.fileDir, decodePath(src.split('#')[0]));
131
- const filename = basename(abs);
168
+ const filename = addAttachment(abs);
132
169
  ctx.images.push({ filename, abs });
133
170
  return `<ac:image${widthAttr}><ri:attachment ri:filename="${escapeXml(filename)}" /></ac:image>`;
134
171
  };
172
+ // Raw HTML tables share the normal link/image rules (including attachment collection).
173
+ md.renderer.rules.html_block = (tokens, idx) => {
174
+ const html = tokens[idx].content;
175
+ if (!/<table[\s>]/i.test(html))
176
+ return html;
177
+ const doc = createDocument(html);
178
+ for (const table of Array.from(doc.querySelectorAll('table'))) {
179
+ const widths = tableWidths(table);
180
+ if (hasWidths(widths))
181
+ applyTableWidths(table, widths, true);
182
+ }
183
+ let output = doc.body.innerHTML;
184
+ for (const anchor of Array.from(doc.querySelectorAll('table a[href]'))) {
185
+ const token = new Token('link_open', 'a', 1);
186
+ token.attrs = Array.from(anchor.attributes).map(a => [a.name, a.value]);
187
+ const open = md.renderer.rules.link_open([token], 0, md.options, {}, md.renderer);
188
+ const close = md.renderer.rules.link_close([new Token('link_close', 'a', -1)], 0, md.options, {}, md.renderer);
189
+ output = output.replace(anchor.outerHTML, open + anchor.innerHTML + close);
190
+ }
191
+ for (const image of Array.from(doc.querySelectorAll('table img[src]'))) {
192
+ const token = new Token('image', 'img', 0);
193
+ token.attrs = Array.from(image.attributes).map(a => [a.name, a.value]);
194
+ const width = image.getAttribute('width') ?? image.getAttribute('style')?.match(/(?:^|;)\s*width:\s*(\d+(?:\.\d+)?)px/i)?.[1];
195
+ if (width && /^\d+$/.test(width))
196
+ token.attrSet('title', `width=${width}`);
197
+ output = output.replace(image.outerHTML, md.renderer.rules.image([token], 0, md.options, {}, md.renderer));
198
+ }
199
+ // Storage is XHTML; HTML's void elements need a closing slash.
200
+ for (const element of Array.from(doc.querySelectorAll('col, br, hr, img, input, wbr'))) {
201
+ output = output.split(element.outerHTML).join(element.outerHTML.slice(0, -1) + ' />');
202
+ }
203
+ return output + '\n';
204
+ };
135
205
  /** 첫 H1(`# 제목`)을 제목으로 추출하고 본문에서 제거 */
136
206
  export function splitTitleAndBody(markdown, fallback) {
137
207
  const lines = markdown.split('\n');
@@ -159,10 +229,11 @@ export function toStorage(markdown, rel, titleIndex, base, opts = {}) {
159
229
  bodySlugs: opts.bodySlugs ?? [],
160
230
  };
161
231
  const src = opts.resolveLink ? resolveWikilinks(markdown, opts.resolveLink) : markdown;
162
- const storage = md.render(src);
232
+ const storage = footnotesToStorage(md.render(src, { legacyCallouts: opts.legacyCallouts }));
163
233
  return {
164
234
  storage,
165
235
  images: ctx.images,
236
+ attachments: ctx.attachments,
166
237
  internalLinks: ctx.internalLinks,
167
238
  anchorLinks: ctx.anchorLinks,
168
239
  anchorsPlaced: ctx.anchorsPlaced,
@@ -171,13 +242,13 @@ export function toStorage(markdown, rel, titleIndex, base, opts = {}) {
171
242
  };
172
243
  }
173
244
  /**
174
- * 변경 감지용 문서 해시: 제목 + storage + 참조 로컬 이미지의 내용 해시.
175
- * 이미지 내용을 포함하므로, 같은 파일명으로 이미지만 교체해도 해시가 바뀌어 재동기화 대상이 된다.
176
- * 이미지가 없으면 hashOf(title + '\0' + storage) 와 동일(이미지 없는 문서는 기존 해시 유지).
245
+ * 변경 감지용 문서 해시: 제목 + storage + 참조 로컬 첨부의 내용 해시.
246
+ * 첨부 내용을 포함하므로, 같은 파일명으로 파일만 교체해도 해시가 바뀌어 재동기화 대상이 된다.
247
+ * 첨부가 없으면 hashOf(title + '\0' + storage) 와 동일(첨부 없는 문서는 기존 해시 유지).
177
248
  */
178
249
  export function docHash(title, r) {
179
- const parts = [title, r.storage];
180
- for (const img of r.images) {
250
+ const parts = [title, footnoteStorageComments(r.storage)];
251
+ for (const img of r.attachments) {
181
252
  let digest = 'missing';
182
253
  try {
183
254
  if (existsSync(img.abs))
@@ -38,6 +38,9 @@ export function buildFrontmatter(data) {
38
38
  }
39
39
  /** 공백이 있으면 <...> 로 감싼다(markdown-it 이 목적지를 통째로 파싱하도록). */
40
40
  const dest = (p) => (/\s/.test(p) ? `<${p}>` : p);
41
+ /** Wiki aliases display underscores literally; Markdown's escape must not leak. */
42
+ export const wikilinkDisplayText = (text) => text.replace(/\\([\\_])/g, '$1');
43
+ const markdownDisplayText = (text) => text.replace(/[\\_]/g, '\\$&');
41
44
  /**
42
45
  * 마크다운 본문에서 "산문" 부분에만 변환을 적용한다.
43
46
  * 코드블록(``` / ~~~)과 인라인 코드(`...`) 안은 그대로 둔다 — 링크처럼 생긴 예제 코드를
@@ -80,12 +83,12 @@ export function resolveWikilinks(md, resolve) {
80
83
  if (!w.target) {
81
84
  if (!slug)
82
85
  return whole; // 블록 참조뿐 → 갈 곳이 없으므로 원문 보존
83
- return `[${w.alias ?? w.fragment}](#${slug})`;
86
+ return `[${markdownDisplayText(w.alias ?? w.fragment ?? '')}](#${slug})`;
84
87
  }
85
88
  const found = resolve(w.target, w.embed);
86
89
  if (!found)
87
90
  return whole; // 해석 실패 → 원문 보존
88
- const label = w.alias ?? w.target;
91
+ const label = markdownDisplayText(w.alias ?? w.target);
89
92
  if (w.embed)
90
93
  return `![${label}](${dest(found + (/\.pdf$/i.test(w.target) && slug ? `#${slug}` : ''))})`;
91
94
  return `[${label}](${dest(found + (slug ? `#${slug}` : ''))})`;
@@ -103,6 +106,6 @@ export function linksToWikilinks(md, toWikilink) {
103
106
  if (bang === '!')
104
107
  return whole; // 이미지는 표준 링크 유지
105
108
  const d = rawDest.replace(/^<(.*)>$/, '$1');
106
- return toWikilink(d, label) ?? whole;
109
+ return toWikilink(d, wikilinkDisplayText(label)) ?? whole;
107
110
  }));
108
111
  }
@@ -0,0 +1,89 @@
1
+ import { createDocument } from '@mixmark-io/domino';
2
+ import { htmlTableMarkdown } from './html-tables.js';
3
+ /** Only explicit pixel widths are portable to Confluence storage. */
4
+ export function pixelWidth(value) {
5
+ const match = value?.trim().match(/^(\d+(?:\.\d+)?)(?:px)?$/i);
6
+ const width = match ? Number(match[1]) : 0;
7
+ return Number.isFinite(width) && width > 0 ? width : undefined;
8
+ }
9
+ function styleWidth(el) {
10
+ const value = el.getAttribute('style')?.match(/(?:^|;)\s*width\s*:\s*([^;]+)/i)?.[1];
11
+ return pixelWidth(value ?? null);
12
+ }
13
+ export function tableWidths(table) {
14
+ const columns = Array.from(table.children)
15
+ .filter(el => el.tagName === 'COLGROUP')
16
+ .flatMap(group => Array.from(group.children).filter(el => el.tagName === 'COL'))
17
+ .map(col => styleWidth(col) ?? pixelWidth(col.getAttribute('width')));
18
+ const width = pixelWidth(table.getAttribute('data-table-width')) ?? styleWidth(table)
19
+ ?? pixelWidth(table.getAttribute('width'))
20
+ ?? (columns.length && columns.every(w => w !== undefined) ? columns.reduce((sum, w) => sum + w, 0) : undefined);
21
+ return { width, columns };
22
+ }
23
+ export function hasWidths(widths) {
24
+ return widths.width !== undefined || widths.columns.some(w => w !== undefined);
25
+ }
26
+ export function applyTableWidths(table, widths, storage = false) {
27
+ if (widths.width !== undefined) {
28
+ const style = (table.getAttribute('style') ?? '').split(';')
29
+ .map(s => s.trim()).filter(s => s && !/^(?:width|table-layout)\s*:/i.test(s)).join('; ');
30
+ table.setAttribute('style', `${style ? style + '; ' : ''}width: ${widths.width}px; table-layout: fixed;`);
31
+ if (storage) {
32
+ table.setAttribute('data-table-width', String(widths.width));
33
+ if (!table.hasAttribute('data-layout'))
34
+ table.setAttribute('data-layout', 'default');
35
+ }
36
+ }
37
+ if (widths.columns.length) {
38
+ for (const group of Array.from(table.children).filter(el => el.tagName === 'COLGROUP'))
39
+ group.remove();
40
+ const group = table.ownerDocument.createElement('colgroup');
41
+ for (const width of widths.columns) {
42
+ const col = table.ownerDocument.createElement('col');
43
+ if (width !== undefined)
44
+ col.setAttribute('style', `width: ${width}px;`);
45
+ group.appendChild(col);
46
+ }
47
+ table.insertBefore(group, table.firstChild);
48
+ }
49
+ }
50
+ /** Read layout from storage, while retaining export_view's rendered cell contents. */
51
+ export function restoreTableWidths(html, storage) {
52
+ if (!storage)
53
+ return html;
54
+ const candidates = Array.from(createDocument(storage).querySelectorAll('table')).map(tableWidths);
55
+ if (!candidates.some(hasWidths))
56
+ return html;
57
+ const doc = createDocument(html);
58
+ const tables = Array.from(doc.querySelectorAll('table'));
59
+ // Macro-generated tables may change the count; avoid assigning unrelated metadata.
60
+ if (tables.length !== candidates.length)
61
+ return html;
62
+ tables.forEach((table, i) => { if (hasWidths(candidates[i]))
63
+ applyTableWidths(table, candidates[i]); });
64
+ return doc.body.innerHTML;
65
+ }
66
+ /** Rewrite real HTML table links, leaving fenced code examples intact. */
67
+ export function rewriteTableLinks(markdown, rewrite) {
68
+ if (!/<table[\s>]/i.test(markdown))
69
+ return markdown;
70
+ const tokens = htmlTableMarkdown().parse(markdown, {});
71
+ const lines = markdown.split('\n');
72
+ for (const token of tokens.reverse()) {
73
+ if (token.type !== 'html_block' || !token.map || !/<table[\s>]/i.test(token.content))
74
+ continue;
75
+ const doc = createDocument(token.content);
76
+ let changed = false;
77
+ for (const anchor of Array.from(doc.querySelectorAll('table a[href]'))) {
78
+ const href = anchor.getAttribute('href');
79
+ const next = rewrite(href);
80
+ if (next !== href) {
81
+ anchor.setAttribute('href', next);
82
+ changed = true;
83
+ }
84
+ }
85
+ if (changed)
86
+ lines.splice(token.map[0], token.map[1] - token.map[0], doc.body.innerHTML.trimEnd());
87
+ }
88
+ return lines.join('\n');
89
+ }
@@ -0,0 +1,4 @@
1
+ /** Network boundary shared by CLI and hosted Node execution. Browser builds bind
2
+ * this boundary to the same-origin Confluence gateway instead of replacing fetch globally.
3
+ */
4
+ export const confluenceFetch = (input, init) => globalThis.fetch(input, init);
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * 의존성 없는 ANSI 컬러 헬퍼.
3
3
  * 비활성 조건: NO_COLOR / TERM=dumb / --no-color / 출력이 TTY 가 아님(파이프·리다이렉트).
4
- * FORCE_COLOR 가 있으면 강제 활성.
4
+ * FORCE_COLOR=1은 파이프에서도 활성, FORCE_COLOR=0은 비활성. 명시적 비활성 조건이 우선한다.
5
5
  */
6
6
  const enabled = !process.env.NO_COLOR &&
7
7
  process.env.TERM !== 'dumb' &&
8
8
  !process.argv.includes('--no-color') &&
9
- (process.env.FORCE_COLOR ? true : process.stdout.isTTY === true);
9
+ (process.env.FORCE_COLOR === '0' ? false : process.env.FORCE_COLOR ? true : process.stdout.isTTY === true);
10
10
  const wrap = (open, close) => (s) => enabled ? `\x1b[${open}m${s}\x1b[${close}m` : String(s);
11
11
  export const bold = wrap(1, 22);
12
12
  export const dim = wrap(2, 22);