From 4c99400485bfefe185f211518000c2a31dc97417 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 17 Aug 2021 06:57:00 +0100 Subject: [PATCH] Desktop, Cli: Fixes #5325: Fixed file paths when exporting as HTML --- packages/lib/path-utils.ts | 3 ++- packages/lib/pathUtils.test.js | 1 + .../InteropService_Exporter_Html.test.ts | 26 ++++++++++++++++++- .../interop/InteropService_Exporter_Html.ts | 7 +++-- .../InteropService_Exporter_Md.test.js | 2 +- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/lib/path-utils.ts b/packages/lib/path-utils.ts index f0af7b4d2..49f877451 100644 --- a/packages/lib/path-utils.ts +++ b/packages/lib/path-utils.ts @@ -75,7 +75,8 @@ export function friendlySafeFilename(e: string, maxLength: number = null, preser let fileExt = ''; if (preserveExtension) { - fileExt = `.${safeFileExtension(fileExtension(e))}`; + const baseExt = fileExtension(e); + fileExt = baseExt ? `.${safeFileExtension(baseExt)}` : ''; e = filename(e); } diff --git a/packages/lib/pathUtils.test.js b/packages/lib/pathUtils.test.js index 9f0eb80d0..a5ff91824 100644 --- a/packages/lib/pathUtils.test.js +++ b/packages/lib/pathUtils.test.js @@ -28,6 +28,7 @@ describe('pathUtils', function() { expect(!!friendlySafeFilename('...')).toBe(true); // Check that it optionally handles filenames with extension + expect(friendlySafeFilename('file', null, true)).toBe('file'); expect(friendlySafeFilename(' testing.md', null, true)).toBe('testing.md'); expect(friendlySafeFilename('testing.safe??ext##', null, true)).toBe('testing.safeext'); expect(friendlySafeFilename('thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong.md', null, true)).toBe('thatsreallylongthatsreallylongthatsreallylongthats.md'); diff --git a/packages/lib/services/interop/InteropService_Exporter_Html.test.ts b/packages/lib/services/interop/InteropService_Exporter_Html.test.ts index a6654caa2..5d8b92110 100644 --- a/packages/lib/services/interop/InteropService_Exporter_Html.test.ts +++ b/packages/lib/services/interop/InteropService_Exporter_Html.test.ts @@ -6,6 +6,7 @@ import Note from '../../models/Note'; import * as fs from 'fs-extra'; import { tempFilePath } from '../../testing/test-utils'; import { ContentScriptType } from '../../services/plugins/api/types'; +import { FileSystemItem } from './types'; async function recreateExportDir() { const dir = exportDir(); @@ -13,7 +14,7 @@ async function recreateExportDir() { await fs.mkdirp(dir); } -describe('services_InteropService_Exporter_Html', function() { +describe('interop/InteropService_Exporter_Html', function() { beforeEach(async (done) => { await setupDatabaseAndSynchronizer(1); @@ -37,6 +38,29 @@ describe('services_InteropService_Exporter_Html', function() { expect(content).toContain('ma note'); })); + test('should export HTML directory', (async () => { + const service = InteropService.instance(); + const folder1 = await Folder.save({ title: 'folder1' }); + await Folder.save({ title: 'folder2' }); + await Note.save({ title: 'note1', parent_id: folder1.id }); + await Note.save({ title: 'note2', parent_id: folder1.id }); + + const dir = exportDir(); + await service.export({ + path: dir, + format: 'html', + target: FileSystemItem.Directory, + }); + + const rootDirs = await fs.readdir(dir); + rootDirs.sort(); + expect(rootDirs).toEqual(['folder1', 'folder2']); + + const files = await fs.readdir(`${dir}/${rootDirs[0]}`); + expect(files).toContain('note1.html'); + expect(files).toContain('note2.html'); + })); + test('should export plugin assets', (async () => { const service = InteropService.instance(); const folder1 = await Folder.save({ title: 'folder1' }); diff --git a/packages/lib/services/interop/InteropService_Exporter_Html.ts b/packages/lib/services/interop/InteropService_Exporter_Html.ts index 62a011725..e4d65838d 100644 --- a/packages/lib/services/interop/InteropService_Exporter_Html.ts +++ b/packages/lib/services/interop/InteropService_Exporter_Html.ts @@ -8,9 +8,8 @@ import Setting from '../../models/Setting'; import { MarkupToHtml } from '@joplin/renderer'; import { ResourceEntity } from '../database/types'; import { contentScriptsToRendererRules } from '../plugins/utils/loadContentScripts'; -const { basename, friendlySafeFilename, rtrimSlashes } = require('../../path-utils'); +import { basename, friendlySafeFilename, rtrimSlashes, dirname } from '../../path-utils'; const { themeStyle } = require('../../theme'); -const { dirname } = require('../../path-utils'); const { escapeHtml } = require('../../string-utils.js'); const { assetsToHeaders } = require('@joplin/renderer'); @@ -53,7 +52,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte if (pathPart) { output = `${pathPart}/${output}`; } else { - output = `${friendlySafeFilename(item.title, null, true)}/${output}`; + output = `${friendlySafeFilename(item.title)}/${output}`; output = await shim.fsDriver().findUniqueFilename(output); } } @@ -98,7 +97,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte if (this.filePath_) { noteFilePath = this.filePath_; } else { - noteFilePath = `${dirPath}/${friendlySafeFilename(item.title, null, true)}.html`; + noteFilePath = `${dirPath}/${friendlySafeFilename(item.title)}.html`; noteFilePath = await shim.fsDriver().findUniqueFilename(noteFilePath); } diff --git a/packages/lib/services/interop/InteropService_Exporter_Md.test.js b/packages/lib/services/interop/InteropService_Exporter_Md.test.js index 41a5de82f..c98b0216c 100644 --- a/packages/lib/services/interop/InteropService_Exporter_Md.test.js +++ b/packages/lib/services/interop/InteropService_Exporter_Md.test.js @@ -10,7 +10,7 @@ const Resource = require('../../models/Resource').default; const Note = require('../../models/Note').default; const shim = require('../../shim').default; -describe('services_InteropService_Exporter_Md', function() { +describe('interop/InteropService_Exporter_Md', function() { beforeEach(async (done) => { await setupDatabaseAndSynchronizer(1);