@wonseok-han/confluence-sync 2.0.1 → 2.0.2
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/dist/conversion/convert.js +1 -1
- package/dist/documents/anchors.js +1 -1
- package/dist/documents/catalog.js +24 -9
- package/dist/documents/obsidian.js +1 -1
- package/dist/site/assets/app.js +4 -4
- package/dist/site/assets/workspace.worker.js +128 -128
- package/dist/site/index.html +2 -2
- package/dist/sync/diff-links.js +37 -0
- package/dist/sync/diff.js +6 -2
- package/dist/sync/local-state.js +38 -2
- package/dist/sync/prepare.js +2 -2
- package/dist/sync/pull.js +3 -3
- package/dist/sync/push.js +2 -2
- package/dist/sync/render.js +1 -1
- package/dist/sync/staging.js +2 -2
- package/dist/web/assets/app.js +4 -4
- package/dist/web/assets/workspace.worker.js +128 -128
- package/docs/user/CLI.md +2 -0
- package/docs/user/WEB.md +2 -0
- package/package.json +1 -1
|
@@ -167,7 +167,7 @@ export async function runConvert(argv) {
|
|
|
167
167
|
}
|
|
168
168
|
const allMd = collectMarkdown(baseDir); // 링크 해석용(전체)
|
|
169
169
|
const mdRels = allMd.map((f) => posix(relative(baseDir, f)));
|
|
170
|
-
const vault = buildVault(mdRels, collectAssets(baseDir).map((f) => posix(relative(baseDir, f))));
|
|
170
|
+
const vault = buildVault(mdRels, collectAssets(baseDir).map((f) => posix(relative(baseDir, f))), baseDir);
|
|
171
171
|
// obsidian 방향의 이름 중복 검사도 트리 전체 기준이어야 한다
|
|
172
172
|
const nameCount = new Map();
|
|
173
173
|
for (const f of allMd) {
|
|
@@ -17,7 +17,7 @@ const FENCE = /^\s*(?:```|~~~)/;
|
|
|
17
17
|
* 대상이 **비어 있을 수 있다** — `[[#헤딩]]` 은 "이 문서의 이 섹션"이라는 Obsidian 표기다.
|
|
18
18
|
* 표 안에서는 별칭 앞 파이프가 `\|` 로 이스케이프되므로 그 백슬래시도 함께 받아 준다.
|
|
19
19
|
*/
|
|
20
|
-
export const WIKILINK_RE = /(!?)\[\[([
|
|
20
|
+
export const WIKILINK_RE = /(!?)\[\[((?:(?!\[\[|\]\])[^|#\n])*)(#(?:(?!\[\[|\]\])[^|\n])+)?(?:\\?\|([^[\]]*))?\]\]/g;
|
|
21
21
|
/**
|
|
22
22
|
* WIKILINK_RE 의 캡처 그룹을 해석한다. 대상도 섹션도 없으면(`[[]]`) 링크가 아니므로 null.
|
|
23
23
|
* 표의 `\|` 때문에 앞 그룹 끝에 딸려온 백슬래시는 여기서 떼어낸다.
|
|
@@ -98,7 +98,7 @@ export function resolveAnchorTargets(docs, vault, localTarget) {
|
|
|
98
98
|
let slug;
|
|
99
99
|
if (la.wiki) {
|
|
100
100
|
// dest 가 비면 `[[#헤딩]]` — 같은 문서의 섹션이다
|
|
101
|
-
target = la.dest === '' ? rel : (vault
|
|
101
|
+
target = la.dest === '' ? rel : vaultPath(vault, la.dest, false, rel);
|
|
102
102
|
slug = wikilinkAnchorToSlug(la.fragment);
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
@@ -124,30 +124,45 @@ export function resolveAnchorTargets(docs, vault, localTarget) {
|
|
|
124
124
|
* Obsidian 은 `[[파일명]]`(짧은 이름)과 `[[폴더/파일명]]`(경로) 을 모두 허용하므로 둘 다 등록한다.
|
|
125
125
|
* 짧은 이름이 겹치면 경로가 사전순으로 앞서는 쪽이 이긴다(Obsidian 의 "가장 가까운 것" 규칙과는 다르지만 결정적이다).
|
|
126
126
|
*/
|
|
127
|
-
export function buildVault(mdRels, assetRels) {
|
|
127
|
+
export function buildVault(mdRels, assetRels, base) {
|
|
128
128
|
const index = (rels, stripExt) => {
|
|
129
129
|
const idx = {};
|
|
130
130
|
for (const rel of [...rels].sort()) {
|
|
131
131
|
const withoutExt = stripExt ? rel.replace(/\.md$/i, '') : rel;
|
|
132
132
|
for (const key of [withoutExt, basename(withoutExt)]) {
|
|
133
|
-
const k = key.toLowerCase();
|
|
133
|
+
const k = key.normalize('NFC').toLowerCase();
|
|
134
134
|
if (!(k in idx))
|
|
135
135
|
idx[k] = rel; // 먼저 등록된(사전순 앞선) 것이 이긴다
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
return idx;
|
|
139
139
|
};
|
|
140
|
-
return { notes: index(mdRels, true), assets: index(assetRels, false) };
|
|
140
|
+
return { notes: index(mdRels, true), assets: index(assetRels, false), rootName: base ? basename(base).normalize('NFC').toLowerCase() : undefined };
|
|
141
|
+
}
|
|
142
|
+
/** Resolve a vault-root path without reading outside the selected workspace. */
|
|
143
|
+
export function vaultPath(vault, target, embed = false, from = '') {
|
|
144
|
+
let key = target.normalize('NFC').toLowerCase();
|
|
145
|
+
if (key.startsWith('/') || key.includes('\\') || key.split('/').some(part => part === '..' || part === '.'))
|
|
146
|
+
return null;
|
|
147
|
+
const noteKey = key.replace(/\.md$/i, '');
|
|
148
|
+
const dir = dirname(from).normalize('NFC').toLowerCase();
|
|
149
|
+
const nearby = !key.includes('/') && dir !== '.' ? vault.notes[dir + '/' + noteKey] : undefined;
|
|
150
|
+
const direct = embed ? (vault.assets[key] ?? vault.notes[noteKey]) : (nearby ?? vault.notes[noteKey] ?? vault.assets[key]);
|
|
151
|
+
if (direct)
|
|
152
|
+
return direct;
|
|
153
|
+
if (!vault.rootName)
|
|
154
|
+
return null;
|
|
155
|
+
const parts = key.split('/'), at = parts.lastIndexOf(vault.rootName);
|
|
156
|
+
if (at < 0)
|
|
157
|
+
return null;
|
|
158
|
+
key = parts.slice(at + 1).join('/');
|
|
159
|
+
return embed ? (vault.assets[key] ?? vault.notes[key.replace(/\.md$/i, '')] ?? null) : (vault.notes[key.replace(/\.md$/i, '')] ?? vault.assets[key] ?? null);
|
|
141
160
|
}
|
|
142
161
|
/** 파일(rel) 기준으로 wikilink 대상을 상대경로로 풀어주는 resolver. */
|
|
143
162
|
export function vaultResolver(rel, vault) {
|
|
144
163
|
const dir = dirname(rel) === '.' ? '' : dirname(rel);
|
|
145
164
|
return (target, embed) => {
|
|
146
|
-
const
|
|
147
|
-
// 임베드(![[...]])는 대개 이미지, 링크([[...]])는 대개 노트 → 각자 먼저 찾아본다
|
|
148
|
-
const hit = embed
|
|
149
|
-
? (vault.assets[target.toLowerCase()] ?? vault.notes[key])
|
|
150
|
-
: (vault.notes[key] ?? vault.assets[target.toLowerCase()]);
|
|
165
|
+
const hit = vaultPath(vault, target, embed, rel);
|
|
151
166
|
if (!hit)
|
|
152
167
|
return null;
|
|
153
168
|
const r = relative(dir || '.', hit).split('\\').join('/');
|
|
@@ -46,7 +46,7 @@ const markdownDisplayText = (text) => text.replace(/[\\_]/g, '\\$&');
|
|
|
46
46
|
* 코드블록(``` / ~~~)과 인라인 코드(`...`) 안은 그대로 둔다 — 링크처럼 생긴 예제 코드를
|
|
47
47
|
* 망가뜨리지 않기 위해서다.
|
|
48
48
|
*/
|
|
49
|
-
function mapProse(md, fn) {
|
|
49
|
+
export function mapProse(md, fn) {
|
|
50
50
|
let inFence = false;
|
|
51
51
|
return md
|
|
52
52
|
.split('\n')
|