diff --git a/packages/htmlpack/src/index.ts b/packages/htmlpack/src/index.ts
index aa760b202..dfa45b706 100644
--- a/packages/htmlpack/src/index.ts
+++ b/packages/htmlpack/src/index.ts
@@ -33,8 +33,15 @@ const htmlentities = (s: string): string => {
};
const dataUriEncode = (filePath: string): string => {
- const result = Datauri(filePath);
- return result.content;
+ try {
+ const result = Datauri(filePath);
+ return result.content;
+ } catch (error) {
+ // If the file path is invalid, the Datauri will throw an exception.
+ // Instead, since we can just ignore that particular file.
+ // Fixes https://github.com/laurent22/joplin/issues/8305
+ return '';
+ }
};
const attributesHtml = (attr: any) => {
diff --git a/packages/lib/services/interop/InteropService_Exporter_Html.test.ts b/packages/lib/services/interop/InteropService_Exporter_Html.test.ts
index edfdecd31..0a80706ad 100644
--- a/packages/lib/services/interop/InteropService_Exporter_Html.test.ts
+++ b/packages/lib/services/interop/InteropService_Exporter_Html.test.ts
@@ -7,6 +7,7 @@ import * as fs from 'fs-extra';
import { tempFilePath } from '../../testing/test-utils';
import { ContentScriptType } from '../../services/plugins/api/types';
import { FileSystemItem } from './types';
+import { readFile } from 'fs/promises';
async function recreateExportDir() {
const dir = exportDir();
@@ -120,4 +121,22 @@ describe('interop/InteropService_Exporter_Html', () => {
expect(readFenceContent).toBe(fenceContent);
}));
+ test('should not throw an error on invalid resource paths', (async () => {
+ const service = InteropService.instance();
+ const folder1 = await Folder.save({ title: 'folder1' });
+ await Note.save({ title: 'note1', parent_id: folder1.id, body: '[a link starts with slash](/)' });
+
+ const filePath = `${exportDir()}/test.html`;
+
+ await service.export({
+ path: filePath,
+ format: 'html',
+ packIntoSingleFile: true,
+ target: FileSystemItem.File,
+ });
+
+ const content = await readFile(filePath, 'utf-8');
+ expect(content).toContain('a link starts with slash');
+ }));
+
});
diff --git a/packages/lib/services/interop/InteropService_Exporter_Html.ts b/packages/lib/services/interop/InteropService_Exporter_Html.ts
index 75f13af52..45a96694c 100644
--- a/packages/lib/services/interop/InteropService_Exporter_Html.ts
+++ b/packages/lib/services/interop/InteropService_Exporter_Html.ts
@@ -6,7 +6,7 @@ import Folder from '../../models/Folder';
import Note from '../../models/Note';
import Setting from '../../models/Setting';
import { MarkupToHtml } from '@joplin/renderer';
-import { ResourceEntity } from '../database/types';
+import { NoteEntity, ResourceEntity } from '../database/types';
import { contentScriptsToRendererRules } from '../plugins/utils/loadContentScripts';
import { basename, friendlySafeFilename, rtrimSlashes, dirname } from '../../path-utils';
import htmlpack from '@joplin/htmlpack';
@@ -48,7 +48,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte
this.style_ = themeStyle(Setting.THEME_LIGHT);
}
- private async makeDirPath_(item: any, pathPart: string = null) {
+ private async makeDirPath_(item: NoteEntity, pathPart: string = null) {
let output = '';
while (true) {
if (item.type_ === BaseModel.TYPE_FOLDER) {
@@ -64,7 +64,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte
}
}
- private async processNoteResources_(item: any) {
+ private async processNoteResources_(item: NoteEntity) {
const target = this.metadata().target;
const linkedResourceIds = await Note.linkedResourceIds(item.body);
const relativePath = target === 'directory' ? rtrimSlashes(await this.makeDirPath_(item, '..')) : '';