From 3dae771e906daaad70ff3029ad64fca4b0e6afce Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 22 Mar 2025 15:41:56 +0200 Subject: [PATCH] feat(import/single): mermaid with .mermaid extension --- src/services/import/mime.spec.ts | 5 +++++ src/services/import/mime.ts | 9 ++++++-- src/services/import/samples/New note.mermaid | 5 +++++ src/services/import/single.spec.ts | 9 ++++++++ src/services/import/single.ts | 22 ++++++++++++++++++++ src/services/utils.ts | 1 + 6 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/services/import/samples/New note.mermaid diff --git a/src/services/import/mime.spec.ts b/src/services/import/mime.spec.ts index 1e32ba3eb..7281d31c2 100644 --- a/src/services/import/mime.spec.ts +++ b/src/services/import/mime.spec.ts @@ -26,6 +26,11 @@ describe("#getMime", () => { ["test.excalidraw"], "application/json" ], + [ + "File extension ('.mermaid') that is defined in EXTENSION_TO_MIME", + ["test.mermaid"], "text/vnd.mermaid" + ], + [ "File extension with inconsistent capitalization that is defined in EXTENSION_TO_MIME", ["test.gRoOvY"], "text/x-groovy" diff --git a/src/services/import/mime.ts b/src/services/import/mime.ts index bab661c63..cb400b8d8 100644 --- a/src/services/import/mime.ts +++ b/src/services/import/mime.ts @@ -3,6 +3,7 @@ import mimeTypes from "mime-types"; import path from "path"; import type { TaskData } from "../task_context_interface.js"; +import type { NoteType } from "../../becca/entities/rows.js"; const CODE_MIME_TYPES = new Set([ "application/json", @@ -68,7 +69,8 @@ const EXTENSION_TO_MIME = new Map([ [".scala", "text/x-scala"], [".swift", "text/x-swift"], [".ts", "text/x-typescript"], - [".excalidraw", "application/json"] + [".excalidraw", "application/json"], + [".mermaid", "text/vnd.mermaid"] ]); /** @returns false if MIME is not detected */ @@ -85,7 +87,7 @@ function getMime(fileName: string) { return mimeFromExt || mimeTypes.lookup(fileNameLc); } -function getType(options: TaskData, mime: string) { +function getType(options: TaskData, mime: string): NoteType { const mimeLc = mime?.toLowerCase(); switch (true) { @@ -98,6 +100,9 @@ function getType(options: TaskData, mime: string) { case mime.startsWith("image/"): return "image"; + case mime === "text/vnd.mermaid": + return "mermaid"; + default: return "file"; } diff --git a/src/services/import/samples/New note.mermaid b/src/services/import/samples/New note.mermaid new file mode 100644 index 000000000..577e63359 --- /dev/null +++ b/src/services/import/samples/New note.mermaid @@ -0,0 +1,5 @@ +graph TD; + A-->B; + A-->C; + B-->D; + C-->D; \ No newline at end of file diff --git a/src/services/import/single.spec.ts b/src/services/import/single.spec.ts index 1eacd261b..060801eb9 100644 --- a/src/services/import/single.spec.ts +++ b/src/services/import/single.spec.ts @@ -96,4 +96,13 @@ describe("processNoteContent", () => { expect(importedNote.type).toBe("canvas"); expect(importedNote.title).toBe("New note"); }); + + it("supports mermaid note", async () => { + const { importedNote } = await testImport("New note.mermaid", "application/json"); + expect(importedNote).toMatchObject({ + mime: "text/vnd.mermaid", + type: "mermaid", + title: "New note" + }); + }); }); diff --git a/src/services/import/single.ts b/src/services/import/single.ts index 4105e55e3..c1597a562 100644 --- a/src/services/import/single.ts +++ b/src/services/import/single.ts @@ -27,6 +27,10 @@ function importSingleFile(taskContext: TaskContext, file: File, parentNote: BNot } } + if (mime === "text/vnd.mermaid") { + return importCustomType(taskContext, file, parentNote, "mermaid", mime); + } + if (taskContext?.data?.codeImportedAsCode && mimeService.getType(taskContext.data, mime) === "code") { return importCodeNote(taskContext, file, parentNote); } @@ -93,6 +97,24 @@ function importCodeNote(taskContext: TaskContext, file: File, parentNote: BNote) return note; } +function importCustomType(taskContext: TaskContext, file: File, parentNote: BNote, type: NoteType, mime: string) { + const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces); + const content = processStringOrBuffer(file.buffer); + + const { note } = noteService.createNewNote({ + parentNoteId: parentNote.noteId, + title, + content, + type, + mime: mime, + isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable() + }); + + taskContext.increaseProgressCount(); + + return note; +} + function importPlainText(taskContext: TaskContext, file: File, parentNote: BNote) { const title = getNoteTitle(file.originalname, !!taskContext.data?.replaceUnderscoresWithSpaces); const plainTextContent = processStringOrBuffer(file.buffer); diff --git a/src/services/utils.ts b/src/services/utils.ts index 3cb84d3a1..87dcf2d67 100644 --- a/src/services/utils.ts +++ b/src/services/utils.ts @@ -181,6 +181,7 @@ export function removeTextFileExtension(filePath: string) { case ".html": case ".htm": case ".excalidraw": + case ".mermaid": return filePath.substring(0, filePath.length - extension.length); default: return filePath;