diff --git a/src/services/import/mime.js b/src/services/import/mime.js new file mode 100644 index 000000000..485c0cbee --- /dev/null +++ b/src/services/import/mime.js @@ -0,0 +1,113 @@ +"use strict"; + +const mimeTypes = require('mime-types'); +const path = require('path'); + +const CODE_MIME_TYPES = { + 'text/plain': true, + 'text/x-csrc': true, + 'text/x-c++src': true, + 'text/x-csharp': true, + 'text/x-clojure': true, + 'text/css': true, + 'text/x-dockerfile': true, + 'text/x-erlang': true, + 'text/x-feature': true, + 'text/x-go': true, + 'text/x-groovy': true, + 'text/x-haskell': true, + 'text/html': true, + 'message/http': true, + 'text/x-java': true, + 'application/javascript': 'application/javascript;env=frontend', + 'application/x-javascript': 'application/javascript;env=frontend', + 'application/json': true, + 'text/x-kotlin': true, + 'text/x-stex': true, + 'text/x-lua': true, + // possibly later migrate to text/markdown as primary MIME + 'text/markdown': 'text/x-markdown', + 'text/x-markdown': true, + 'text/x-objectivec': true, + 'text/x-pascal': true, + 'text/x-perl': true, + 'text/x-php': true, + 'text/x-python': true, + 'text/x-ruby': true, + 'text/x-rustsrc': true, + 'text/x-scala': true, + 'text/x-sh': true, + 'text/x-sql': true, + 'text/x-swift': true, + 'text/xml': true, + 'text/x-yaml': true +}; + +// extensions missing in mime-db +const EXTENSION_TO_MIME = { + ".c": "text/x-csrc", + ".cs": "text/x-csharp", + ".clj": "text/x-clojure", + ".erl": "text/x-erlang", + ".hrl": "text/x-erlang", + ".feature": "text/x-feature", + ".go": "text/x-go", + ".groovy": "text/x-groovy", + ".hs": "text/x-haskell", + ".lhs": "text/x-haskell", + ".http": "message/http", + ".kt": "text/x-kotlin", + ".m": "text/x-objectivec", + ".py": "text/x-python", + ".rb": "text/x-ruby", + ".scala": "text/x-scala", + ".swift": "text/x-swift" +}; + +function getMime(fileName) { + if (fileName.toLowerCase() === 'dockerfile') { + return "text/x-dockerfile"; + } + + const ext = path.extname(fileName).toLowerCase(); + + if (ext in EXTENSION_TO_MIME) { + return EXTENSION_TO_MIME[ext]; + } + + return mimeTypes.lookup(fileName); +} + +function getType(importContext, mime) { + mime = mime.toLowerCase(); + + if (importContext.textImportedAsText && (mime === 'text/html' || ['text/markdown', 'text/x-markdown'].includes(mime))) { + return 'text'; + } + else if (importContext.codeImportedAsCode && mime in CODE_MIME_TYPES) { + return 'code'; + } + else if (mime.startsWith("image/")) { + return 'image'; + } + else { + return 'file'; + } +} + +function normalizeMimeType(mime) { + mime = mime.toLowerCase(); + + if (!(mime in CODE_MIME_TYPES) || CODE_MIME_TYPES[mime] === true) { + return mime; + } + else { + return CODE_MIME_TYPES[mime]; + } +} + +module.exports = { + getMime, + getType, + normalizeMimeType +}; \ No newline at end of file diff --git a/src/services/import/single.js b/src/services/import/single.js index 582cf9361..c46bb691a 100644 --- a/src/services/import/single.js +++ b/src/services/import/single.js @@ -5,84 +5,10 @@ const imageService = require('../../services/image'); const protectedSessionService = require('../protected_session'); const commonmark = require('commonmark'); const path = require('path'); -const mimeTypes = require('mime-types'); - -const CODE_MIME_TYPES = { - 'text/plain': true, - 'text/x-csrc': true, - 'text/x-c++src': true, - 'text/x-csharp': true, - 'text/x-clojure': true, - 'text/css': true, - 'text/x-dockerfile': true, - 'text/x-erlang': true, - 'text/x-feature': true, - 'text/x-go': true, - 'text/x-groovy': true, - 'text/x-haskell': true, - 'text/html': true, - 'message/http': true, - 'text/x-java': true, - 'application/javascript': 'application/javascript;env=frontend', - 'application/x-javascript': 'application/javascript;env=frontend', - 'application/json': true, - 'text/x-kotlin': true, - 'text/x-stex': true, - 'text/x-lua': true, - // possibly later migrate to text/markdown as primary MIME - 'text/markdown': 'text/x-markdown', - 'text/x-markdown': true, - 'text/x-objectivec': true, - 'text/x-pascal': true, - 'text/x-perl': true, - 'text/x-php': true, - 'text/x-python': true, - 'text/x-ruby': true, - 'text/x-rustsrc': true, - 'text/x-scala': true, - 'text/x-sh': true, - 'text/x-sql': true, - 'text/x-swift': true, - 'text/xml': true, - 'text/x-yaml': true -}; - -// extensions missing in mime-db -const EXTENSION_TO_MIME = { - ".cs": "text/x-csharp", - ".clj": "text/x-clojure", - ".erl": "text/x-erlang", - ".hrl": "text/x-erlang", - ".feature": "text/x-feature", - ".go": "text/x-go", - ".groovy": "text/x-groovy", - ".hs": "text/x-haskell", - ".lhs": "text/x-haskell", - ".http": "message/http", - ".kt": "text/x-kotlin", - ".m": "text/x-objectivec", - ".py": "text/x-python", - ".rb": "text/x-ruby", - ".scala": "text/x-scala", - ".swift": "text/x-swift" -}; - -function getMime(fileName) { - if (fileName.toLowerCase() === 'dockerfile') { - return "text/x-dockerfile"; - } - - const ext = path.extname(fileName).toLowerCase(); - - if (ext in EXTENSION_TO_MIME) { - return EXTENSION_TO_MIME[ext]; - } - - return mimeTypes.lookup(fileName); -} +const mimeService = require('./mime'); async function importSingleFile(importContext, file, parentNote) { - const mime = getMime(file.originalname); + const mime = mimeService.getMime(file.originalname); if (importContext.textImportedAsText) { if (mime === 'text/html') { @@ -94,7 +20,7 @@ async function importSingleFile(importContext, file, parentNote) { } } - if (importContext.codeImportedAsCode && mime in CODE_MIME_TYPES) { + if (importContext.codeImportedAsCode && mimeService.getType(importContext, mime) === 'code') { return await importCodeNote(importContext, file, parentNote); } @@ -121,7 +47,7 @@ async function importFile(importContext, file, parentNote) { target: 'into', isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), type: 'file', - mime: getMime(originalName), + mime: mimeService.getMime(originalName), attributes: [ { type: "label", name: "originalFileName", value: originalName }, { type: "label", name: "fileSize", value: size } @@ -136,8 +62,8 @@ async function importFile(importContext, file, parentNote) { async function importCodeNote(importContext, file, parentNote) { const title = getFileNameWithoutExtension(file.originalname); const content = file.buffer.toString("UTF-8"); - const detectedMime = getMime(file.originalname); - const mime = CODE_MIME_TYPES[detectedMime] === true ? detectedMime : CODE_MIME_TYPES[detectedMime]; + const detectedMime = mimeService.getMime(file.originalname); + const mime = mimeService.normalizeMimeType(detectedMime); const {note} = await noteService.createNote(parentNote.noteId, title, content, { type: 'code', diff --git a/src/services/import/tar.js b/src/services/import/tar.js index 899fc5065..7da144dfc 100644 --- a/src/services/import/tar.js +++ b/src/services/import/tar.js @@ -1,5 +1,6 @@ "use strict"; + const Attribute = require('../../entities/attribute'); const utils = require('../../services/utils'); const log = require('../../services/log'); @@ -11,9 +12,9 @@ const tar = require('tar-stream'); const stream = require('stream'); const path = require('path'); const commonmark = require('commonmark'); -const mimeTypes = require('mime-types'); const ImportContext = require('../import_context'); const protectedSessionService = require('../protected_session'); +const mimeService = require("./mime"); /** * @param {ImportContext} importContext @@ -140,20 +141,11 @@ async function importTar(importContext, fileBuffer, importRootNote) { return noteId; } - function detectFileTypeAndMime(filePath) { - const mime = mimeTypes.lookup(filePath); - let type = 'file'; + function detectFileTypeAndMime(importContext, filePath) { + const mime = mimeService.getMime(filePath); + const type = mimeService.getType(importContext, mime); - if (mime) { - if (mime === 'text/html' || ['text/markdown', 'text/x-markdown'].includes(mime)) { - type = 'text'; - } - else if (mime.startsWith('image/')) { - type = 'image'; - } - } - - return { type, mime }; + return { mime, type }; } async function saveAttributes(note, noteMeta) { @@ -264,7 +256,7 @@ async function importTar(importContext, fileBuffer, importRootNote) { return; } - const {type, mime} = noteMeta ? noteMeta : detectFileTypeAndMime(filePath); + const {type, mime} = noteMeta ? noteMeta : detectFileTypeAndMime(importContext, filePath); if (type !== 'file' && type !== 'image') { content = content.toString("UTF-8");