@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.
- package/README.md +44 -409
- 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 +157 -86
- 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 +83 -12
- 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 +262 -207
- 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 +365 -71
- 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
package/dist/sync/push.js
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
|
+
import { progressStep } from '../shared/progress.js';
|
|
2
|
+
import { storeBaseline } from './baseline.js';
|
|
3
|
+
import { buildTreeRenderer } from './render.js';
|
|
4
|
+
import { localStateHash } from './local-state.js';
|
|
5
|
+
import { loadIndex, stagedPaths, assertStaged, completeStaged } from './staging.js';
|
|
1
6
|
/** Incremental Confluence push and local preview orchestration. */
|
|
7
|
+
import { mappingPath } from './metadata.js';
|
|
2
8
|
import { positionalArgs } from '../cli/args.js';
|
|
3
|
-
import { existsSync, statSync } from 'node:fs';
|
|
9
|
+
import { existsSync, statSync, readFileSync } from 'node:fs';
|
|
4
10
|
import { resolve, relative } from 'node:path';
|
|
5
11
|
import { readEnv, requireEnv } from '../confluence/config.js';
|
|
6
12
|
import { docHash } from '../documents/markdown.js';
|
|
7
|
-
import {
|
|
13
|
+
import { preparePushTree } from './prepare.js';
|
|
8
14
|
import { collectMarkdown, buildFolderIndex, readDoc, parentKeyOf, containerKeyOf, sortForSync, resolveSelection, withParents, } from '../documents/catalog.js';
|
|
9
15
|
import { loadMapping, saveMapping } from './mapping.js';
|
|
10
16
|
import { createClient } from '../confluence/client.js';
|
|
11
17
|
import { buildIgnorer } from './ignore.js';
|
|
12
|
-
import {
|
|
18
|
+
import { resolveSyncBase, loadWorkspace, inScope, inNestedWorkspace, assertWorkspaceConnection, requireScope } from './workspace.js';
|
|
19
|
+
import { verifyScope } from './scope.js';
|
|
20
|
+
import { reconcilePages } from './reconcile.js';
|
|
21
|
+
import { bold, dim, red, green, yellow, cyan, gray } from '../shared/colors.js';
|
|
13
22
|
export async function runPush(argv) {
|
|
23
|
+
if (argv.includes('--rebuild'))
|
|
24
|
+
throw new Error('--rebuild는 v2에서 제거되었습니다. 파일 이동·갱신은 push, 본문 강제 갱신은 push --force를 사용하세요. 기존 페이지는 삭제하지 않습니다.');
|
|
25
|
+
if (argv.includes('--scope'))
|
|
26
|
+
throw new Error('--scope는 제거되었습니다. 기준 폴더 안에서 추가한 문서만 업로드합니다.');
|
|
14
27
|
const DRY_RUN = argv.includes('--dry-run');
|
|
15
28
|
const LIST = argv.includes('--list');
|
|
16
|
-
const REBUILD = argv.includes('--rebuild');
|
|
17
29
|
const FORCE = argv.includes('--force');
|
|
18
30
|
const VERIFY = argv.includes('--verify');
|
|
19
31
|
function optVal(name) {
|
|
@@ -30,11 +42,11 @@ export async function runPush(argv) {
|
|
|
30
42
|
}
|
|
31
43
|
const EXCLUDES = optVals('--exclude');
|
|
32
44
|
const positionals = positionalArgs(argv);
|
|
33
|
-
const baseInput = optVal('--base')
|
|
45
|
+
const baseInput = resolveSyncBase(optVal('--base'));
|
|
34
46
|
if (!baseInput) {
|
|
35
47
|
console.error(red('✗ 동기화 루트가 지정되지 않았습니다.') + '\n' +
|
|
36
48
|
' --base <dir> 인자 또는 env CONFLUENCE_SYNC_BASE 로 동기화할 디렉토리를 지정하세요.\n' +
|
|
37
|
-
` 예) ${cyan('confluence-sync --base ./docs')}\n` +
|
|
49
|
+
` 예) ${cyan('confluence-sync push --base ./docs')}\n` +
|
|
38
50
|
` 설정(.env)을 만들려면: ${cyan('confluence-sync init')}\n` +
|
|
39
51
|
` 전체 도움말: ${cyan('confluence-sync --help')}`);
|
|
40
52
|
process.exit(1);
|
|
@@ -42,27 +54,35 @@ export async function runPush(argv) {
|
|
|
42
54
|
const BASE_DIR = resolve(baseInput);
|
|
43
55
|
// mapping 은 base 루트에 둔다(문서셋에 종속). --mapping 으로 위치 override 가능.
|
|
44
56
|
const mappingOpt = optVal('--mapping');
|
|
45
|
-
const MAPPING_PATH = mappingOpt ? resolve(mappingOpt) :
|
|
46
|
-
const env = readEnv();
|
|
57
|
+
const MAPPING_PATH = mappingOpt ? resolve(mappingOpt) : mappingPath(BASE_DIR);
|
|
58
|
+
const env = readEnv(BASE_DIR);
|
|
59
|
+
const workspace = loadWorkspace(BASE_DIR);
|
|
60
|
+
const remoteScope = requireScope(workspace);
|
|
61
|
+
if ((!DRY_RUN && !LIST) || (VERIFY && !LIST))
|
|
62
|
+
assertWorkspaceConnection(workspace, env);
|
|
47
63
|
if (!existsSync(BASE_DIR) || !statSync(BASE_DIR).isDirectory()) {
|
|
48
64
|
console.error(red(`동기화 루트가 디렉토리가 아닙니다: ${BASE_DIR}`));
|
|
49
65
|
process.exit(1);
|
|
50
66
|
}
|
|
51
|
-
if (!DRY_RUN && !LIST)
|
|
67
|
+
if ((!DRY_RUN && !LIST) || (VERIFY && !LIST))
|
|
52
68
|
requireEnv(env); // list/dry 는 Confluence 호출이 없어 인증 불필요
|
|
53
69
|
const ignorer = buildIgnorer(BASE_DIR, EXCLUDES);
|
|
54
70
|
const collected = collectMarkdown(BASE_DIR).map((f) => relative(BASE_DIR, f).split('\\').join('/'));
|
|
55
|
-
const allRel = collected.filter((r) => !ignorer.ignores(r)); // 제외된 문서는 모든 단계에서 빠짐
|
|
71
|
+
const allRel = collected.filter((r) => !ignorer.ignores(r) && !inNestedWorkspace(BASE_DIR, r)); // 제외된 문서는 모든 단계에서 빠짐
|
|
56
72
|
const ignoredCount = collected.length - allRel.length;
|
|
57
73
|
const folderIndex = buildFolderIndex(allRel);
|
|
58
74
|
// 링크·섹션 링크 변환은 항상 트리 전체 기준이다. 선택 동기화여도 대상 문서의 제목·헤딩을 알아야 하고,
|
|
59
75
|
// 다른 문서가 이 문서의 섹션을 가리킬 수 있다. 제외된 문서는 링크 대상에서도 빠진다.
|
|
60
|
-
const
|
|
61
|
-
// 사용자가 실제로 고른 문서. 경로 인자가 없으면
|
|
62
|
-
const
|
|
76
|
+
const titleIndex = Object.fromEntries(allRel.map(rel => [rel, readDoc(BASE_DIR, rel).title]));
|
|
77
|
+
// 사용자가 실제로 고른 문서. 경로 인자가 없으면 저장된 업로드 선택만 사용한다.
|
|
78
|
+
const staged = !positionals.length && !LIST ? loadIndex(BASE_DIR).entries : undefined;
|
|
79
|
+
const requested = positionals.length ? resolveSelection(allRel, positionals, BASE_DIR) : LIST ? allRel : stagedPaths(BASE_DIR);
|
|
80
|
+
if (requested.some(rel => !allRel.includes(rel)))
|
|
81
|
+
throw new Error('업로드 대상 문서가 없거나 제외되었습니다. unstage 후 다시 추가하세요.');
|
|
82
|
+
const picked = requested.filter(rel => inScope(rel, workspace));
|
|
63
83
|
const explicit = new Set(picked);
|
|
64
84
|
// 상위 README 를 함께 넣는 것은 **자식의 부모 pageId 를 얻기 위해서**다(발행 대상이 아니다).
|
|
65
|
-
const selected =
|
|
85
|
+
const selected = withParents(picked, folderIndex);
|
|
66
86
|
const files = sortForSync(selected);
|
|
67
87
|
/** 딸려온 상위 README 인가 — 이미 페이지가 있으면 내용은 건드리지 않는다. */
|
|
68
88
|
const isCarriedParent = (rel) => !explicit.has(rel);
|
|
@@ -71,7 +91,7 @@ export async function runPush(argv) {
|
|
|
71
91
|
(files.length > explicit.size ? dim(` (+상위 ${files.length - explicit.size})`) : '')
|
|
72
92
|
: `${files.length}건`;
|
|
73
93
|
const ignoredNote = ignoredCount ? dim(` (제외 ${ignoredCount})`) : '';
|
|
74
|
-
console.log(`${dim('base:')} ${cyan(BASE_DIR)}\n${dim('대상:')} ${scope}${ignoredNote}`);
|
|
94
|
+
console.log(`${dim('base:')} ${cyan(BASE_DIR)}\n${dim('스페이스 루트:')} ${cyan(`${remoteScope.path} (#${remoteScope.id})`)}\n${dim('작업공간:')} ${cyan(BASE_DIR)}\n${dim('대상:')} ${scope}${ignoredNote}`);
|
|
75
95
|
// ---- 경로 헬퍼 ----
|
|
76
96
|
const isReadmeFile = (p) => /README\.md$/.test(p);
|
|
77
97
|
const segOf = (s) => (s === '' ? 0 : s.split('/').length);
|
|
@@ -100,220 +120,255 @@ export async function runPush(argv) {
|
|
|
100
120
|
}
|
|
101
121
|
return;
|
|
102
122
|
}
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
throw new Error(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
for (const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
const originalMapping = loadMapping(MAPPING_PATH);
|
|
124
|
+
const mapping = reconcilePages(BASE_DIR, originalMapping, allRel, picked, remoteScope);
|
|
125
|
+
const relinked = new Set(picked.filter(rel => !originalMapping[rel] && mapping[rel]?.pageId));
|
|
126
|
+
for (const rel of files)
|
|
127
|
+
if (isCarriedParent(rel) && !mapping[rel]?.pageId)
|
|
128
|
+
throw new Error(`상위 문서의 매핑이 없습니다: ${rel}. 먼저 Pull로 기존 상위 문서를 연결하거나 상위 문서도 함께 추가하세요.`);
|
|
129
|
+
const root = remoteScope;
|
|
130
|
+
if (root.type === 'page' && explicit.has('README.md') && mapping['README.md']?.pageId !== root.id)
|
|
131
|
+
throw new Error('루트 README.md는 선택한 원격 페이지의 본문입니다. pull로 기준을 확보하거나 새 하위 문서는 다른 파일명을 사용하세요.');
|
|
132
|
+
const rootParent = root.id;
|
|
133
|
+
console.log(dim('Markdown 전처리: 위키링크·각주·PDF 페이지 참조를 준비합니다. 원본은 변경하지 않습니다.'));
|
|
134
|
+
progressStep('선택한 문서·첨부 전처리');
|
|
135
|
+
const prepared = await preparePushTree(BASE_DIR, allRel, picked, { referenceRoots: optVals('--reference-root'), baseUrl: env.baseUrl });
|
|
136
|
+
try {
|
|
137
|
+
const { render, docs } = prepared;
|
|
138
|
+
const hashes = Object.fromEntries(picked.map(rel => [rel, docHash(docs[rel].title, render(rel, docs[rel].body, docs[rel].title))]));
|
|
139
|
+
if (staged)
|
|
140
|
+
for (const rel of picked)
|
|
141
|
+
assertStaged(BASE_DIR, rel, hashes[rel], staged[rel]);
|
|
142
|
+
const sourceTexts = Object.fromEntries(picked.map(rel => [rel, readFileSync(resolve(BASE_DIR, rel), 'utf8')]));
|
|
143
|
+
const localHashes = Object.fromEntries(picked.map(rel => [rel, localStateHash(BASE_DIR, rel, render(rel, docs[rel].body, docs[rel].title))]));
|
|
144
|
+
const legacy = buildTreeRenderer(BASE_DIR, allRel);
|
|
145
|
+
const locallyClean = (rel) => {
|
|
146
|
+
const entry = mapping[rel];
|
|
147
|
+
return entry?.localHash ? entry.localHash === localHashes[rel] : !!entry?.hash && (entry.hash === hashes[rel]
|
|
148
|
+
|| entry.hash === docHash(legacy.docs[rel].title, legacy.render(rel, legacy.docs[rel].body, legacy.docs[rel].title))
|
|
149
|
+
|| entry.hash === docHash(docs[rel].title, render(rel, docs[rel].body, docs[rel].title, 'panels'))
|
|
150
|
+
|| entry.hash === docHash(docs[rel].title, render(rel, docs[rel].body, docs[rel].title, true))
|
|
151
|
+
|| entry.hash === docHash(legacy.docs[rel].title, legacy.render(rel, legacy.docs[rel].body, legacy.docs[rel].title, 'panels'))
|
|
152
|
+
|| entry.hash === docHash(legacy.docs[rel].title, legacy.render(rel, legacy.docs[rel].body, legacy.docs[rel].title, true)));
|
|
153
|
+
};
|
|
154
|
+
const publicationHash = (rel) => !FORCE && locallyClean(rel) ? mapping[rel].hash : hashes[rel];
|
|
155
|
+
const unchanged = (rel) => !FORCE && !VERIFY && locallyClean(rel) && !mapping[rel]?.pendingMove;
|
|
156
|
+
const needsRemote = picked.some(rel => !unchanged(rel));
|
|
157
|
+
let client;
|
|
158
|
+
let spaceId = '';
|
|
159
|
+
if (needsRemote && (!DRY_RUN || VERIFY)) {
|
|
160
|
+
client = createClient({ baseUrl: env.baseUrl, email: env.email, token: env.token }, { force: FORCE, verify: VERIFY, scope: { id: root.id, spaceId: workspace.connection.spaceId } });
|
|
161
|
+
progressStep('원격 연결과 문서 버전 검증');
|
|
162
|
+
spaceId = await verifyScope(client, workspace);
|
|
163
|
+
for (const rel of files) {
|
|
164
|
+
if (!isCarriedParent(rel) && unchanged(rel))
|
|
165
|
+
continue;
|
|
166
|
+
if (isCarriedParent(rel) && mapping[rel]?.pageId) {
|
|
167
|
+
await client.assertInScope(mapping[rel].pageId);
|
|
168
|
+
continue;
|
|
125
169
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
const { title, body, fm } = readDoc(BASE_DIR, rel);
|
|
133
|
-
const r = render(rel, body, title);
|
|
134
|
-
for (const link of r.referenceLinks)
|
|
135
|
-
console.log(dim(` 참조 링크: ${link}`));
|
|
136
|
-
for (const warning of r.linkWarnings)
|
|
137
|
-
console.error(yellow(` ⚠ ${rel}: ${warning}`));
|
|
138
|
-
const hash = docHash(title, r);
|
|
139
|
-
const ex = mapping[rel];
|
|
140
|
-
// 매핑엔 없지만 frontmatter 에 pageId 가 있으면 신규 생성이 아니라 기존 페이지에 연결된다
|
|
141
|
-
const status = !ex?.pageId
|
|
142
|
-
? (fm.pageId ? cyan('연결') : green('신규'))
|
|
143
|
-
: ex.pendingMove ? cyan(ex.hash === hash ? '위치 확인/이동' : '위치 확인/이동 + 변경')
|
|
144
|
-
: ex.hash === hash ? gray('동일') : yellow('변경');
|
|
145
|
-
const pk = parentKeyOf(rel, folderIndex);
|
|
146
|
-
const anchorNote = r.anchorLinks || r.anchorsPlaced
|
|
147
|
-
? `, 섹션링크: ${r.anchorLinks}, 앵커: ${r.anchorsPlaced}` : '';
|
|
148
|
-
console.log(` [${status}] ${rel} ${dim('→')} ${cyan(`"${title}"`)} ${dim(`(부모: ${pk ?? 'ROOT'}, 내부링크: ${r.internalLinks}${anchorNote}, 이미지: ${r.images.length})`)}`);
|
|
149
|
-
if (r.deadAnchors.length) {
|
|
150
|
-
console.error(yellow(` ⚠ 대응 헤딩 없는 앵커 ${r.deadAnchors.length}개: `) + dim(r.deadAnchors.slice(0, 3).join(' ')));
|
|
170
|
+
const { title, body, fm } = docs[rel];
|
|
171
|
+
const hash = publicationHash(rel);
|
|
172
|
+
const entry = mapping[rel] ?? (fm.pageId ? { pageId: fm.pageId, title } : undefined);
|
|
173
|
+
if (entry)
|
|
174
|
+
await client.checkPage({ [rel]: entry }, spaceId, rel, hash);
|
|
151
175
|
}
|
|
152
176
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const touched = new Set(); // 이번에 발행(생성/갱신/재생성)된 문서
|
|
168
|
-
const handledFolders = new Map(); // 이번 실행에서 처리한 폴더 dir
|
|
169
|
-
// README 없는 폴더를 Confluence 폴더로 생성(없으면)하고 work 에 등록. 성공 여부 반환.
|
|
170
|
-
const ensureFolder = async (dir) => {
|
|
171
|
-
const key = `${dir}/`;
|
|
172
|
-
const pcKey = containerKeyOf(parentDirOf(dir), folderIndex);
|
|
173
|
-
const parentId = pcKey ? work[pcKey]?.pageId : env.parentId;
|
|
174
|
-
if (pcKey && !parentId) {
|
|
175
|
-
console.error(yellow(` ✗ 폴더 건너뜀 ${dir}/ (부모 '${pcKey}' 가 아직 없음)`));
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
const ex = work[key];
|
|
179
|
-
try {
|
|
180
|
-
const title = dir.split('/').pop();
|
|
181
|
-
const result = await client.upsertFolder(spaceId, env.spaceKey, title, parentId, ex?.type === 'folder' ? ex.pageId : undefined);
|
|
182
|
-
const fid = result.id;
|
|
183
|
-
work[key] = { pageId: fid, title, type: 'folder' };
|
|
184
|
-
saveMapping(MAPPING_PATH, work);
|
|
185
|
-
console.log(` ${cyan(!result.created ? '📁 폴더 연결' : '📁 폴더')} ${dir}/ ${dim(`(부모: ${pcKey ?? 'ROOT'})`)}`);
|
|
186
|
-
if (result.created)
|
|
187
|
-
foldersMade++;
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
catch (e) {
|
|
191
|
-
console.error(red(` ✗ 폴더 준비 실패 ${dir}/`) + `\n${e.message}`);
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
for (const rel of files) {
|
|
196
|
-
// 상위 README-less 폴더들 보장(shallow→deep)
|
|
197
|
-
let folderOk = true;
|
|
198
|
-
for (const d of ancestorFolderDirs(rel)) {
|
|
199
|
-
if (!handledFolders.has(d))
|
|
200
|
-
handledFolders.set(d, await ensureFolder(d));
|
|
201
|
-
if (!handledFolders.get(d))
|
|
202
|
-
folderOk = false;
|
|
203
|
-
if (!folderOk)
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
if (!folderOk) {
|
|
207
|
-
console.error(yellow(` ✗ 건너뜀 ${rel} (상위 폴더 미생성)`));
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
// 딸려온 상위 README 는 자식의 부모 pageId 를 얻으려고 들어온 것이다.
|
|
211
|
-
// 이미 페이지가 있으면 내용은 건드리지 않는다 — `csync <파일>` 이 고르지 않은 문서를 발행하면 안 된다.
|
|
212
|
-
// (페이지가 아직 없으면 자식을 붙일 곳이 없으므로 아래에서 생성한다)
|
|
213
|
-
if (isCarriedParent(rel) && work[rel]?.pageId) {
|
|
214
|
-
console.log(` ${gray('· 상위')} ${rel} ${dim(`(pageId #${work[rel].pageId} 만 사용)`)}`);
|
|
215
|
-
carried++;
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
const { title, body, fm } = readDoc(BASE_DIR, rel);
|
|
219
|
-
const r = render(rel, body, title);
|
|
220
|
-
for (const link of r.referenceLinks)
|
|
221
|
-
console.log(dim(` 참조 링크: ${link}`));
|
|
222
|
-
for (const warning of r.linkWarnings)
|
|
223
|
-
console.error(yellow(` ⚠ ${rel}: ${warning}`));
|
|
224
|
-
const hash = docHash(title, r);
|
|
225
|
-
const pk = parentKeyOf(rel, folderIndex);
|
|
226
|
-
if (r.deadAnchors.length) {
|
|
227
|
-
console.error(yellow(` ⚠ 대응 헤딩 없는 앵커 ${rel}`) + dim(` ${r.deadAnchors.slice(0, 3).join(' ')}${r.deadAnchors.length > 3 ? ` 외 ${r.deadAnchors.length - 3}` : ''}`));
|
|
228
|
-
}
|
|
229
|
-
const parentId = pk ? work[pk]?.pageId : env.parentId;
|
|
230
|
-
rendered.set(rel, { ...r, title, hash, parentId });
|
|
231
|
-
if (pk && !parentId) {
|
|
232
|
-
console.error(yellow(` ✗ 건너뜀 ${rel} (부모 '${pk}' 가 아직 없음)`));
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
// pull 로 받은 문서(frontmatter 에 pageId)는 매핑이 없어도 원본 페이지에 다시 연결한다.
|
|
236
|
-
// 매핑 파일을 잃었거나 vault 를 다른 곳에 복제한 경우 중복 생성을 막아준다.
|
|
237
|
-
if (!work[rel]?.pageId && fm.pageId) {
|
|
238
|
-
try {
|
|
239
|
-
if (await client.getContentOrNull(fm.pageId)) {
|
|
240
|
-
work[rel] = { pageId: fm.pageId, title };
|
|
241
|
-
saveMapping(MAPPING_PATH, work);
|
|
242
|
-
console.log(` ${cyan('🔗 연결')} ${rel} ${dim(`→ 기존 페이지 #${fm.pageId}`)}`);
|
|
243
|
-
linked++;
|
|
177
|
+
if (DRY_RUN) {
|
|
178
|
+
const seen = new Set();
|
|
179
|
+
for (const rel of files) {
|
|
180
|
+
for (const d of ancestorFolderDirs(rel))
|
|
181
|
+
if (!seen.has(d)) {
|
|
182
|
+
seen.add(d);
|
|
183
|
+
const fex = mapping[`${d}/`];
|
|
184
|
+
console.log(` [${fex?.pageId ? gray('폴더') : green('폴더+')}] 📁 ${d}/`);
|
|
185
|
+
}
|
|
186
|
+
const ex0 = mapping[rel];
|
|
187
|
+
// 딸려온 상위 README 는 pageId 만 쓰고 지나간다 — 고르지 않은 문서를 발행하지 않는다
|
|
188
|
+
if (isCarriedParent(rel) && ex0?.pageId) {
|
|
189
|
+
console.log(` [${gray('상위')}] ${rel} ${dim(`(pageId #${ex0.pageId} 만 사용)`)}`);
|
|
190
|
+
continue;
|
|
244
191
|
}
|
|
245
|
-
|
|
246
|
-
|
|
192
|
+
const { title, body, fm } = docs[rel];
|
|
193
|
+
const r = render(rel, body, title);
|
|
194
|
+
for (const link of r.referenceLinks)
|
|
195
|
+
console.log(dim(` 참조 링크: ${link}`));
|
|
196
|
+
for (const warning of r.linkWarnings)
|
|
197
|
+
console.error(yellow(` ⚠ ${rel}: ${warning}`));
|
|
198
|
+
const hash = publicationHash(rel);
|
|
199
|
+
const ex = mapping[rel];
|
|
200
|
+
// 매핑엔 없지만 frontmatter 에 pageId 가 있으면 신규 생성이 아니라 기존 페이지에 연결된다
|
|
201
|
+
const status = !ex?.pageId
|
|
202
|
+
? (fm.pageId ? cyan('연결') : green('신규'))
|
|
203
|
+
: ex.pendingMove ? cyan(!FORCE && ex.hash === hash ? '위치 확인/이동' : '위치 확인/이동 + 변경')
|
|
204
|
+
: !FORCE && locallyClean(rel) ? gray(relinked.has(rel) ? '로컬 경로 연결' : '동일') : yellow('변경');
|
|
205
|
+
const pk = parentKeyOf(rel, folderIndex);
|
|
206
|
+
const anchorNote = r.anchorLinks || r.anchorsPlaced
|
|
207
|
+
? `, 섹션링크: ${r.anchorLinks}, 앵커: ${r.anchorsPlaced}` : '';
|
|
208
|
+
console.log(` [${status}] ${rel} ${dim('→')} ${cyan(`"${title}"`)} ${dim(`(부모: ${pk ?? 'ROOT'}, 내부링크: ${r.internalLinks}${anchorNote}, 이미지: ${r.images.length}, 첨부: ${r.attachments.length})`)}`);
|
|
209
|
+
if (r.deadAnchors.length) {
|
|
210
|
+
console.error(yellow(` ⚠ 대응 헤딩 없는 앵커 ${r.deadAnchors.length}개: `) + dim(r.deadAnchors.slice(0, 3).join(' ')));
|
|
247
211
|
}
|
|
248
212
|
}
|
|
213
|
+
console.log('\n' + dim(VERIFY ? '--dry-run --verify: 원격 조회만 수행, 변경 없음.' : '--dry-run: 실제 호출 없음.'));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const apiClient = client;
|
|
217
|
+
const work = mapping;
|
|
218
|
+
let failed = 0;
|
|
219
|
+
let moved = 0;
|
|
220
|
+
let created = 0, updated = 0, skipped = 0, foldersMade = 0, carried = 0;
|
|
221
|
+
const handledFolders = new Map(); // 이번 실행에서 처리한 폴더 dir
|
|
222
|
+
// README 없는 폴더를 Confluence 폴더로 생성(없으면)하고 work 에 등록. 성공 여부 반환.
|
|
223
|
+
const ensureFolder = async (dir) => {
|
|
224
|
+
const key = `${dir}/`;
|
|
225
|
+
const pcKey = containerKeyOf(parentDirOf(dir), folderIndex);
|
|
226
|
+
const parentId = pcKey ? work[pcKey]?.pageId : rootParent;
|
|
227
|
+
if (pcKey && !parentId) {
|
|
228
|
+
console.error(yellow(` ✗ 폴더 건너뜀 ${dir}/ (부모 '${pcKey}' 가 아직 없음)`));
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
const ex = work[key];
|
|
232
|
+
try {
|
|
233
|
+
const title = dir.split('/').pop();
|
|
234
|
+
const result = await apiClient.upsertFolder(spaceId, env.spaceKey, title, parentId, ex?.type === 'folder' ? ex.pageId : undefined);
|
|
235
|
+
const fid = result.id;
|
|
236
|
+
work[key] = ex?.pageId === fid ? ex : { pageId: fid, title, type: 'folder' };
|
|
237
|
+
saveMapping(MAPPING_PATH, work);
|
|
238
|
+
console.log(` ${cyan(!result.created ? '📁 폴더 연결' : '📁 폴더')} ${dir}/ ${dim(`(부모: ${pcKey ?? 'ROOT'})`)}`);
|
|
239
|
+
if (result.created)
|
|
240
|
+
foldersMade++;
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
249
243
|
catch (e) {
|
|
250
|
-
console.error(
|
|
244
|
+
console.error(red(` ✗ 폴더 준비 실패 ${dir}/`) + `\n${e.message}`);
|
|
245
|
+
return false;
|
|
251
246
|
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
247
|
+
};
|
|
248
|
+
for (const [index, rel] of files.entries()) {
|
|
249
|
+
progressStep(`문서 처리 ${index + 1}/${files.length} · ${rel}`);
|
|
250
|
+
if (!isCarriedParent(rel) && unchanged(rel)) {
|
|
251
|
+
if (relinked.has(rel)) {
|
|
252
|
+
saveMapping(MAPPING_PATH, work);
|
|
253
|
+
console.log(` ${gray('로컬 경로 연결')} ${rel} ${dim('(원격 본문·제목·위치 유지)')}`);
|
|
254
|
+
}
|
|
255
|
+
console.log(` = 변경없음 ${rel}`);
|
|
258
256
|
skipped++;
|
|
257
|
+
completeStaged(BASE_DIR, rel, staged?.[rel]);
|
|
259
258
|
continue;
|
|
260
259
|
}
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
moved++;
|
|
260
|
+
if (isCarriedParent(rel) && !needsRemote) {
|
|
261
|
+
carried++;
|
|
264
262
|
continue;
|
|
265
263
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
recreated++;
|
|
276
|
-
recreatedTitles.add(title);
|
|
264
|
+
// 상위 README-less 폴더들 보장(shallow→deep)
|
|
265
|
+
let folderOk = true;
|
|
266
|
+
for (const d of ancestorFolderDirs(rel)) {
|
|
267
|
+
if (!handledFolders.has(d))
|
|
268
|
+
handledFolders.set(d, await ensureFolder(d));
|
|
269
|
+
if (!handledFolders.get(d))
|
|
270
|
+
folderOk = false;
|
|
271
|
+
if (!folderOk)
|
|
272
|
+
break;
|
|
277
273
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
catch (e) {
|
|
283
|
-
console.error(red(` ✗ 실패 ${rel}`) + `\n${e.message}`);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
// 링크 정합성: 재생성된 문서를 가리키던, 이번에 발행 안 된(스킵된) 문서를 강제 재발행해 링크를 새 페이지로 재연결
|
|
287
|
-
if (recreatedTitles.size) {
|
|
288
|
-
for (const rel of files) {
|
|
289
|
-
if (touched.has(rel))
|
|
274
|
+
if (!folderOk) {
|
|
275
|
+
failed++;
|
|
276
|
+
console.error(yellow(` ✗ 건너뜀 ${rel} (상위 폴더 미생성)`));
|
|
290
277
|
continue;
|
|
291
|
-
|
|
292
|
-
|
|
278
|
+
}
|
|
279
|
+
// 딸려온 상위 README 는 자식의 부모 pageId 를 얻으려고 들어온 것이다.
|
|
280
|
+
// 이미 페이지가 있으면 내용은 건드리지 않는다 — `csync <파일>` 이 고르지 않은 문서를 발행하면 안 된다.
|
|
281
|
+
// (페이지가 아직 없으면 자식을 붙일 곳이 없으므로 아래에서 생성한다)
|
|
282
|
+
if (isCarriedParent(rel) && work[rel]?.pageId) {
|
|
283
|
+
console.log(` ${gray('· 상위')} ${rel} ${dim(`(pageId #${work[rel].pageId} 만 사용)`)}`);
|
|
284
|
+
carried++;
|
|
293
285
|
continue;
|
|
294
|
-
|
|
286
|
+
}
|
|
287
|
+
const { title, body, fm } = docs[rel];
|
|
288
|
+
const r = render(rel, body, title);
|
|
289
|
+
for (const link of r.referenceLinks)
|
|
290
|
+
console.log(dim(` 참조 링크: ${link}`));
|
|
291
|
+
for (const warning of r.linkWarnings)
|
|
292
|
+
console.error(yellow(` ⚠ ${rel}: ${warning}`));
|
|
293
|
+
const hash = publicationHash(rel);
|
|
294
|
+
const pk = parentKeyOf(rel, folderIndex);
|
|
295
|
+
if (r.deadAnchors.length) {
|
|
296
|
+
console.error(yellow(` ⚠ 대응 헤딩 없는 앵커 ${rel}`) + dim(` ${r.deadAnchors.slice(0, 3).join(' ')}${r.deadAnchors.length > 3 ? ` 외 ${r.deadAnchors.length - 3}` : ''}`));
|
|
297
|
+
}
|
|
298
|
+
// Pull keeps existing local paths; editing content must preserve the observed remote parent.
|
|
299
|
+
const recordedParent = work[rel]?.pendingMove ? undefined : work[rel]?.remoteParentId;
|
|
300
|
+
const parentId = recordedParent ?? (pk ? work[pk]?.pageId : rootParent);
|
|
301
|
+
if (pk && !parentId) {
|
|
302
|
+
failed++;
|
|
303
|
+
console.error(yellow(` ✗ 건너뜀 ${rel} (부모 '${pk}' 가 아직 없음)`));
|
|
295
304
|
continue;
|
|
305
|
+
}
|
|
306
|
+
// pull 로 받은 문서(frontmatter 에 pageId)는 매핑이 없어도 원본 페이지에 다시 연결한다.
|
|
307
|
+
// 매핑 파일을 잃었거나 vault 를 다른 곳에 복제한 경우 중복 생성을 막아준다.
|
|
308
|
+
if (!work[rel]?.pageId && fm.pageId)
|
|
309
|
+
work[rel] = { pageId: fm.pageId, title };
|
|
296
310
|
try {
|
|
297
|
-
|
|
311
|
+
if (staged)
|
|
312
|
+
assertStaged(BASE_DIR, rel, hashes[rel], staged[rel]);
|
|
313
|
+
const result = await apiClient.upsertPage(work, spaceId, rel, title, r.storage, hash, parentId);
|
|
298
314
|
saveMapping(MAPPING_PATH, work);
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
315
|
+
if (result === 'skipped') {
|
|
316
|
+
work[rel].localHash = localHashes[rel];
|
|
317
|
+
work[rel].sourceObject = storeBaseline(BASE_DIR, sourceTexts[rel]);
|
|
318
|
+
saveMapping(MAPPING_PATH, work);
|
|
319
|
+
console.log(` ${gray('= 변경없음')} ${rel}`);
|
|
320
|
+
skipped++;
|
|
321
|
+
completeStaged(BASE_DIR, rel, staged?.[rel]);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (result === 'moved') {
|
|
325
|
+
work[rel].localHash = localHashes[rel];
|
|
326
|
+
work[rel].sourceObject = storeBaseline(BASE_DIR, sourceTexts[rel]);
|
|
327
|
+
saveMapping(MAPPING_PATH, work);
|
|
328
|
+
console.log(` ${cyan('→ 이동')} ${rel} (부모: ${pk ?? 'ROOT'})`);
|
|
329
|
+
moved++;
|
|
330
|
+
completeStaged(BASE_DIR, rel, staged?.[rel]);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const imgOk = await apiClient.uploadAttachments(work[rel].pageId, r.attachments, BASE_DIR);
|
|
334
|
+
const imgNote = r.attachments.length ? `, 첨부 ${imgOk}/${r.attachments.length}` : '';
|
|
335
|
+
if (imgOk !== r.attachments.length) {
|
|
336
|
+
failed++;
|
|
337
|
+
delete work[rel].hash; // 부분 실패는 다음 동기화에서 재시도한다.
|
|
338
|
+
saveMapping(MAPPING_PATH, work);
|
|
339
|
+
}
|
|
340
|
+
if (imgOk === r.attachments.length) {
|
|
341
|
+
work[rel].localHash = localHashes[rel];
|
|
342
|
+
work[rel].sourceObject = storeBaseline(BASE_DIR, sourceTexts[rel]);
|
|
343
|
+
saveMapping(MAPPING_PATH, work);
|
|
344
|
+
}
|
|
345
|
+
if (imgOk === r.attachments.length)
|
|
346
|
+
completeStaged(BASE_DIR, rel, staged?.[rel]);
|
|
347
|
+
const label = result === 'created' ? green('+ 생성')
|
|
348
|
+
: yellow('↻ 갱신');
|
|
349
|
+
console.log(` ${label} ${rel} ${dim('→')} ${cyan(`"${title}"`)} ${dim(`(부모: ${pk ?? 'ROOT'}${imgNote})`)}`);
|
|
350
|
+
if (result === 'created')
|
|
351
|
+
created++;
|
|
352
|
+
else
|
|
353
|
+
updated++;
|
|
302
354
|
}
|
|
303
355
|
catch (e) {
|
|
304
|
-
|
|
356
|
+
failed++;
|
|
357
|
+
console.error(red(` ✗ 실패 ${rel}`) + `\n${e.message}`);
|
|
305
358
|
}
|
|
306
359
|
}
|
|
360
|
+
if (failed)
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
console.log('\n' + bold(failed ? '일부 실패' : '완료') +
|
|
363
|
+
` ${green(`생성 ${created}`)}` +
|
|
364
|
+
` ${yellow(`갱신 ${updated}`)}` +
|
|
365
|
+
` ${cyan(`이동 ${moved}`)}` +
|
|
366
|
+
` ${gray(`변경없음 ${skipped}`)}` +
|
|
367
|
+
(foldersMade ? ` ${cyan(`폴더 ${foldersMade}`)}` : '') +
|
|
368
|
+
(carried ? ` ${gray(`상위 ${carried}`)}` : '') +
|
|
369
|
+
` ${dim(`대상 ${files.length - carried}`)}`);
|
|
370
|
+
}
|
|
371
|
+
finally {
|
|
372
|
+
prepared.dispose();
|
|
307
373
|
}
|
|
308
|
-
console.log('\n' + bold('완료') +
|
|
309
|
-
` ${green(`생성 ${created}`)}` +
|
|
310
|
-
` ${yellow(`갱신 ${updated}`)}` +
|
|
311
|
-
` ${cyan(`이동 ${moved}`)}` +
|
|
312
|
-
` ${magenta(`재생성 ${recreated}`)}` +
|
|
313
|
-
` ${cyan(`링크재연결 ${relinked}`)}` +
|
|
314
|
-
` ${gray(`변경없음 ${skipped}`)}` +
|
|
315
|
-
(linked ? ` ${cyan(`연결 ${linked}`)}` : '') +
|
|
316
|
-
(foldersMade ? ` ${cyan(`폴더 ${foldersMade}`)}` : '') +
|
|
317
|
-
(carried ? ` ${gray(`상위 ${carried}`)}` : '') +
|
|
318
|
-
` ${dim(`대상 ${files.length - carried}`)}`);
|
|
319
374
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Infer local page moves without writing metadata or contacting Confluence. */
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { buildFolderIndex, parentKeyOf, readDoc } from '../documents/catalog.js';
|
|
5
|
+
export function reconcilePages(base, mapping, allFiles, selected, scope) {
|
|
6
|
+
const next = structuredClone(mapping);
|
|
7
|
+
const byId = new Map(Object.entries(mapping).map(([key, entry]) => [entry.pageId, { key, entry }]));
|
|
8
|
+
const oldFolders = buildFolderIndex(Object.keys(mapping).filter(key => key.endsWith('.md')));
|
|
9
|
+
const folders = buildFolderIndex(allFiles);
|
|
10
|
+
const docs = new Map(allFiles.map(key => [key, readDoc(base, key)]));
|
|
11
|
+
const seen = new Map();
|
|
12
|
+
for (const [key, doc] of docs) {
|
|
13
|
+
const id = doc.fm.pageId ?? mapping[key]?.pageId;
|
|
14
|
+
if (!id)
|
|
15
|
+
continue;
|
|
16
|
+
if (mapping[key] && mapping[key].pageId !== id)
|
|
17
|
+
throw new Error(`pageId 충돌: ${key}`);
|
|
18
|
+
if (seen.has(id))
|
|
19
|
+
throw new Error(`문서 pageId 중복: ${seen.get(id)}, ${key} (#${id})`);
|
|
20
|
+
seen.set(id, key);
|
|
21
|
+
if (id === scope.id && (scope.type !== 'page' || key !== 'README.md'))
|
|
22
|
+
throw new Error('스코프 루트의 매핑 경로는 README.md로 유지해야 합니다.');
|
|
23
|
+
}
|
|
24
|
+
for (const key of selected) {
|
|
25
|
+
const doc = docs.get(key);
|
|
26
|
+
const id = doc.fm.pageId ?? mapping[key]?.pageId;
|
|
27
|
+
if (!id)
|
|
28
|
+
continue;
|
|
29
|
+
const prior = byId.get(id);
|
|
30
|
+
if (prior?.entry.type === 'folder')
|
|
31
|
+
throw new Error(`폴더 ID를 문서에 사용할 수 없습니다: ${key}`);
|
|
32
|
+
if (prior && prior.key !== key && existsSync(resolve(base, prior.key)))
|
|
33
|
+
throw new Error(`기존 pageId 경로가 남아 있습니다: ${prior.key}, ${key}`);
|
|
34
|
+
const entry = { ...(prior?.entry ?? { pageId: id, title: doc.title }) };
|
|
35
|
+
const parentKey = parentKeyOf(key, folders);
|
|
36
|
+
const oldParentKey = prior ? parentKeyOf(prior.key, oldFolders) : undefined;
|
|
37
|
+
const parentId = parentKey ? mapping[parentKey]?.pageId ?? docs.get(parentKey)?.fm.pageId : scope.id;
|
|
38
|
+
const sameParent = !!prior && (oldParentKey === parentKey || !!parentId && prior.entry.remoteParentId === parentId);
|
|
39
|
+
if (id === scope.id) {
|
|
40
|
+
if (entry.pendingMove)
|
|
41
|
+
throw new Error('스코프 루트는 이동할 수 없습니다.');
|
|
42
|
+
}
|
|
43
|
+
else if (!prior || !sameParent || entry.pendingMove) {
|
|
44
|
+
entry.pendingMove = { parentKey };
|
|
45
|
+
}
|
|
46
|
+
if (prior && prior.key !== key)
|
|
47
|
+
delete next[prior.key];
|
|
48
|
+
next[key] = entry;
|
|
49
|
+
}
|
|
50
|
+
return next;
|
|
51
|
+
}
|
package/dist/sync/references.js
CHANGED
|
@@ -4,7 +4,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:pat
|
|
|
4
4
|
import { parse } from 'dotenv';
|
|
5
5
|
import { collectMarkdown } from '../documents/catalog.js';
|
|
6
6
|
import { buildIgnorer } from './ignore.js';
|
|
7
|
-
import {
|
|
7
|
+
import { mappingPath } from './metadata.js';
|
|
8
8
|
const key = (s) => s.normalize('NFC').toLowerCase();
|
|
9
9
|
const slash = (s) => s.split('\\').join('/');
|
|
10
10
|
const decode = (s) => { try {
|
|
@@ -34,7 +34,7 @@ export function buildReferenceLookup(base, rels, roots, baseUrl) {
|
|
|
34
34
|
if (configured && configured !== server)
|
|
35
35
|
throw new Error('참조 폴더의 Confluence 서버가 현재 설정과 다릅니다: ' + root);
|
|
36
36
|
let mapping = {};
|
|
37
|
-
const path =
|
|
37
|
+
const path = mappingPath(root);
|
|
38
38
|
if (existsSync(path)) {
|
|
39
39
|
mapping = JSON.parse(readFileSync(path, 'utf8'));
|
|
40
40
|
if (!mapping || typeof mapping !== 'object' || Array.isArray(mapping)
|