@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.
- package/README.md +44 -410
- package/dist/cli/args.js +1 -1
- package/dist/cli/help.js +214 -115
- package/dist/cli/init.js +44 -5
- package/dist/cli/main.js +42 -11
- package/dist/cli/status.js +83 -0
- package/dist/confluence/client.js +121 -57
- package/dist/confluence/config.js +12 -8
- package/dist/confluence/env-file.js +23 -0
- package/dist/confluence/links.js +18 -0
- package/dist/conversion/asset-paths.js +5 -0
- package/dist/conversion/attachments.js +29 -7
- package/dist/conversion/convert.js +10 -22
- package/dist/conversion/footnotes.js +114 -11
- package/dist/conversion/markdown.js +26 -0
- package/dist/conversion/pdf-pages.js +10 -8
- package/dist/documents/anchors.js +9 -0
- package/dist/documents/callout-roundtrip.js +75 -0
- package/dist/documents/callouts.js +74 -0
- package/dist/documents/catalog.js +2 -2
- package/dist/documents/footnote-roundtrip.js +96 -0
- package/dist/documents/format.js +116 -0
- package/dist/documents/html-tables.js +30 -0
- package/dist/documents/html-to-markdown.js +47 -13
- package/dist/documents/markdown.js +46 -4
- package/dist/documents/obsidian.js +6 -3
- package/dist/documents/tables.js +89 -0
- package/dist/runtime/network.js +4 -0
- package/dist/shared/colors.js +2 -2
- package/dist/shared/progress.js +164 -0
- package/dist/shared/version.js +12 -0
- package/dist/site/assets/Monaco-LICENSE.txt +21 -0
- package/dist/site/assets/Monaco-ThirdPartyNotices.txt +448 -0
- package/dist/site/assets/PDFJS-LICENSE.txt +177 -0
- package/dist/site/assets/app.css +1 -0
- package/dist/site/assets/app.js +4 -0
- package/dist/site/assets/chunks/chunk-TEW74QPN.js +35 -0
- package/dist/site/assets/chunks/markdown-S6623E66.js +1 -0
- package/dist/site/assets/chunks/monaco-36ZGUH4Y.js +897 -0
- package/dist/site/assets/chunks/monaco-HFLEBJTI.css +1 -0
- package/dist/site/assets/chunks/pdf-DDN7TXTP.js +55 -0
- package/dist/site/assets/confluence-env-example.txt +32 -0
- package/dist/site/assets/editor.worker.js +1 -0
- package/dist/site/assets/favicon.svg +3 -0
- package/dist/site/assets/guide/01-account-settings.png +0 -0
- package/dist/site/assets/guide/02-atlassian-security.png +0 -0
- package/dist/site/assets/guide/03-api-tokens.png +0 -0
- package/dist/site/assets/guide/04-scope-api-token-step1.png +0 -0
- package/dist/site/assets/guide/05-scope-api-token-step2.png +0 -0
- package/dist/site/assets/guide/06-scope-api-token-step3.png +0 -0
- package/dist/site/assets/guide/07-scope-api-token-step4.png +0 -0
- package/dist/site/assets/guide/web/document-preview.png +0 -0
- package/dist/site/assets/guide/web/remote-diff.png +0 -0
- package/dist/site/assets/guide/web/sync-workspace.png +0 -0
- package/dist/site/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Add-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
- package/dist/site/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
- package/dist/site/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Ext-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GB-H.bcmap +4 -0
- package/dist/site/assets/pdf/cmaps/GB-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBT-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Hankaku.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Hiragana.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Katakana.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/LICENSE +36 -0
- package/dist/site/assets/pdf/cmaps/NWP-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/NWP-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/Roman.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/V.bcmap +0 -0
- package/dist/site/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
- package/dist/site/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
- package/dist/site/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/dist/site/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/dist/site/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
- package/dist/site/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
- package/dist/site/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
- package/dist/site/assets/pdf/wasm/LICENSE_QCMS +21 -0
- package/dist/site/assets/pdf/wasm/jbig2.wasm +0 -0
- package/dist/site/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
- package/dist/site/assets/pdf/wasm/openjpeg.wasm +0 -0
- package/dist/site/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
- package/dist/site/assets/pdf/wasm/qcms_bg.wasm +0 -0
- package/dist/site/assets/pdf/wasm/quickjs-eval.js +16 -0
- package/dist/site/assets/pdf/wasm/quickjs-eval.wasm +0 -0
- package/dist/site/assets/pdf.worker.min.mjs +29 -0
- package/dist/site/assets/workspace.worker.js +409 -0
- package/dist/site/index.html +253 -0
- package/dist/sync/baseline.js +45 -0
- package/dist/sync/changes.js +51 -0
- package/dist/sync/diff.js +80 -0
- package/dist/sync/fetch.js +287 -0
- package/dist/sync/ignore.js +4 -4
- package/dist/sync/local-state.js +12 -0
- package/dist/sync/mapping.js +31 -8
- package/dist/sync/metadata.js +57 -0
- package/dist/sync/prepare.js +52 -0
- package/dist/sync/pull.js +618 -141
- package/dist/sync/push.js +260 -213
- package/dist/sync/reconcile.js +51 -0
- package/dist/sync/references.js +2 -2
- package/dist/sync/remap.js +17 -5
- package/dist/sync/render.js +3 -2
- package/dist/sync/restore.js +28 -0
- package/dist/sync/scope.js +47 -0
- package/dist/sync/staging.js +193 -0
- package/dist/sync/workspace.js +100 -0
- package/dist/web/assets/PDFJS-LICENSE.txt +177 -0
- package/dist/web/assets/app.css +1 -1
- package/dist/web/assets/app.js +3 -938
- package/dist/web/assets/chunks/chunk-TEW74QPN.js +35 -0
- package/dist/web/assets/chunks/markdown-S6623E66.js +1 -0
- package/dist/web/assets/chunks/monaco-36ZGUH4Y.js +897 -0
- package/dist/web/assets/chunks/monaco-HFLEBJTI.css +1 -0
- package/dist/web/assets/chunks/pdf-DDN7TXTP.js +55 -0
- package/dist/web/assets/confluence-env-example.txt +32 -0
- package/dist/web/assets/editor.worker.js +1 -30
- package/dist/web/assets/favicon.svg +3 -0
- package/dist/web/assets/guide/01-account-settings.png +0 -0
- package/dist/web/assets/guide/02-atlassian-security.png +0 -0
- package/dist/web/assets/guide/03-api-tokens.png +0 -0
- package/dist/web/assets/guide/04-scope-api-token-step1.png +0 -0
- package/dist/web/assets/guide/05-scope-api-token-step2.png +0 -0
- package/dist/web/assets/guide/06-scope-api-token-step3.png +0 -0
- package/dist/web/assets/guide/07-scope-api-token-step4.png +0 -0
- package/dist/web/assets/guide/web/document-preview.png +0 -0
- package/dist/web/assets/guide/web/remote-diff.png +0 -0
- package/dist/web/assets/guide/web/sync-workspace.png +0 -0
- package/dist/web/assets/pdf/cmaps/78-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Add-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5pc-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/B5pc-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS1-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS1-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/CNS2-V.bcmap +3 -0
- package/dist/web/assets/pdf/cmaps/ETHK-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETHK-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETen-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETen-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/ETenms-B5-H.bcmap +3 -0
- package/dist/web/assets/pdf/cmaps/ETenms-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Ext-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GB-H.bcmap +4 -0
- package/dist/web/assets/pdf/cmaps/GB-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK2K-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBK2K-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBT-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdla-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdla-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm314-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm314-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm471-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKm471-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKscs-B5-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/HKscs-B5-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Hankaku.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Hiragana.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-Johab-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-Johab-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Katakana.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/LICENSE +36 -0
- package/dist/web/assets/pdf/cmaps/NWP-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/NWP-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/RKSJ-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/RKSJ-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/Roman.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/V.bcmap +0 -0
- package/dist/web/assets/pdf/cmaps/WP-Symbol.bcmap +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitDingbats.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixed.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerif.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/FoxitSymbol.pfb +0 -0
- package/dist/web/assets/pdf/standard_fonts/LICENSE_FOXIT +27 -0
- package/dist/web/assets/pdf/standard_fonts/LICENSE_LIBERATION +363 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/dist/web/assets/pdf/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/dist/web/assets/pdf/wasm/LICENSE_JBIG2 +196 -0
- package/dist/web/assets/pdf/wasm/LICENSE_OPENJPEG +39 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_JBIG2 +13 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_OPENJPEG +22 -0
- package/dist/web/assets/pdf/wasm/LICENSE_PDFJS_QCMS +19 -0
- package/dist/web/assets/pdf/wasm/LICENSE_QCMS +21 -0
- package/dist/web/assets/pdf/wasm/jbig2.wasm +0 -0
- package/dist/web/assets/pdf/wasm/jbig2_nowasm_fallback.js +15 -0
- package/dist/web/assets/pdf/wasm/openjpeg.wasm +0 -0
- package/dist/web/assets/pdf/wasm/openjpeg_nowasm_fallback.js +17 -0
- package/dist/web/assets/pdf/wasm/qcms_bg.wasm +0 -0
- package/dist/web/assets/pdf/wasm/quickjs-eval.js +16 -0
- package/dist/web/assets/pdf/wasm/quickjs-eval.wasm +0 -0
- package/dist/web/assets/pdf.worker.min.mjs +29 -0
- package/dist/web/assets/workspace.worker.js +409 -0
- package/dist/web/document-source.js +14 -0
- package/dist/web/hosted-files.js +189 -0
- package/dist/web/hosted.js +316 -0
- package/dist/web/node-runner.js +26 -0
- package/dist/web/preview.js +74 -0
- package/dist/web/server.js +85 -240
- package/dist/web/sync.js +364 -70
- package/dist/web/table-editor-script.js +99 -0
- package/dist/web/table-format.js +224 -0
- package/dist/web/views/help.js +15 -10
- package/dist/web/views/sync-panel.js +90 -19
- package/dist/web/views/token-guide.js +27 -0
- package/dist/web/views/usage-guide.js +12 -0
- package/dist/web/views/workspace.js +85 -15
- package/dist/web/workspace-api.js +371 -0
- package/docs/user/CLI.md +366 -0
- package/docs/user/CONFIGURATION.md +125 -0
- package/docs/user/OBSIDIAN.md +117 -0
- package/docs/user/WEB.md +90 -0
- package/docs/user/images/web/document-preview.png +0 -0
- package/docs/user/images/web/remote-diff.png +0 -0
- package/docs/user/images/web/sync-workspace.png +0 -0
- 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
|
|
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
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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) =>
|
|
109
|
-
|
|
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 =
|
|
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`).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, '&').replace(/</g, '<').replace(/>/g, '>'));
|
|
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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
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 (
|
|
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
|
+
}
|