diff --git a/apps/server/src/services/import/markdown.spec.ts b/apps/server/src/services/import/markdown.spec.ts
index 3aa67bd9d..3bb56580c 100644
--- a/apps/server/src/services/import/markdown.spec.ts
+++ b/apps/server/src/services/import/markdown.spec.ts
@@ -283,7 +283,7 @@ $$`;
it("supports wikilink with root-relative path", () => {
const input = `oh no my banana I bought on [[journal/monday]] has gone off! I’m taking it back to the [[other/shop]] for a refund`;
- const expected = `
oh no my banana I bought on journal/monday has gone off! I’m taking it back to the other/shop for a refund
`;
+ const expected = `oh no my banana I bought on journal/monday has gone off! I’m taking it back to the other/shop for a refund
`;
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
});
diff --git a/apps/server/src/services/import/markdown.ts b/apps/server/src/services/import/markdown.ts
index c945143fa..77b35eeba 100644
--- a/apps/server/src/services/import/markdown.ts
+++ b/apps/server/src/services/import/markdown.ts
@@ -215,7 +215,7 @@ function restoreFromMap(text: string, map: Map): string {
}
function processWikiLinks(paragraph: string) {
- paragraph = paragraph.replaceAll(/\[\[([^\[\]]+)\]\]/g, `$1`);
+ paragraph = paragraph.replaceAll(/\[\[([^\[\]]+)\]\]/g, `$1`);
return paragraph;
}
diff --git a/apps/server/src/services/import/zip.ts b/apps/server/src/services/import/zip.ts
index 5e795ae54..1f3ed96cc 100644
--- a/apps/server/src/services/import/zip.ts
+++ b/apps/server/src/services/import/zip.ts
@@ -41,6 +41,7 @@ async function importZip(taskContext: TaskContext, fileBuffer: Buffer, importRoo
const createdPaths: Record = { "/": importRootNote.noteId, "\\": importRootNote.noteId };
let metaFile: MetaFile | null = null;
let firstNote: BNote | null = null;
+ let topLevelPath = "";
const createdNoteIds = new Set();
function getNewNoteId(origNoteId: string) {
@@ -257,29 +258,33 @@ async function importZip(taskContext: TaskContext, fileBuffer: Buffer, importRoo
saveAttributes(note, noteMeta);
firstNote = firstNote || note;
-
return noteId;
}
function getEntityIdFromRelativeUrl(url: string, filePath: string) {
- while (url.startsWith("./")) {
- url = url.substr(2);
+ let absUrl;
+ if (!url.startsWith("/")) {
+ while (url.startsWith("./")) {
+ url = url.substr(2);
+ }
+
+ let absUrl = path.dirname(filePath);
+
+ while (url.startsWith("../")) {
+ absUrl = path.dirname(absUrl);
+
+ url = url.substr(3);
+ }
+
+ if (absUrl === ".") {
+ absUrl = "";
+ }
+
+ absUrl += `${absUrl.length > 0 ? "/" : ""}${url}`;
+ } else {
+ absUrl = topLevelPath + url;
}
- let absUrl = path.dirname(filePath);
-
- while (url.startsWith("../")) {
- absUrl = path.dirname(absUrl);
-
- url = url.substr(3);
- }
-
- if (absUrl === ".") {
- absUrl = "";
- }
-
- absUrl += `${absUrl.length > 0 ? "/" : ""}${url}`;
-
const { noteMeta, attachmentMeta } = getMeta(absUrl);
if (attachmentMeta && attachmentMeta.attachmentId && noteMeta.noteId) {
@@ -527,20 +532,28 @@ async function importZip(taskContext: TaskContext, fileBuffer: Buffer, importRoo
}
}
- // we're running two passes to make sure that the meta file is loaded before the rest of the files is processed.
-
+ // we're running two passes in order to obtain critical information first (meta file and root)
+ const topLevelItems = new Set();
await readZipFile(fileBuffer, async (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => {
const filePath = normalizeFilePath(entry.fileName);
+ // make sure that the meta file is loaded before the rest of the files is processed.
if (filePath === "!!!meta.json") {
const content = await readContent(zipfile, entry);
metaFile = JSON.parse(content.toString("utf-8"));
}
+ // determine the root of the .zip (i.e. if it has only one top-level folder then the root is that folder, or the root of the archive if there are multiple top-level folders).
+ const firstSlash = filePath.indexOf("/");
+ const topLevelPath = (firstSlash !== -1 ? filePath.substring(0, firstSlash) : filePath);
+ topLevelItems.add(topLevelPath);
+
zipfile.readEntry();
});
+ topLevelPath = (topLevelItems.size > 1 ? "" : topLevelItems.values().next().value ?? "");
+
await readZipFile(fileBuffer, async (zipfile: yauzl.ZipFile, entry: yauzl.Entry) => {
const filePath = normalizeFilePath(entry.fileName);