"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs-extra");
const test_utils_js_1 = require("../../testing/test-utils.js");
const InteropService_Exporter_Md_1 = require("../../services/interop/InteropService_Exporter_Md");
const BaseModel_1 = require("../../BaseModel");
const Folder_1 = require("../../models/Folder");
const Resource_1 = require("../../models/Resource");
const Note_1 = require("../../models/Note");
const shim_1 = require("../../shim");
const renderer_1 = require("@joplin/renderer");
const InteropService_js_1 = require("./InteropService.js");
const path_utils_js_1 = require("../../path-utils.js");
const promises_1 = require("fs/promises");
const types_js_1 = require("./types.js");
describe('interop/InteropService_Exporter_Md', () => {
    beforeEach(async () => {
        await (0, test_utils_js_1.setupDatabaseAndSynchronizer)(1);
        await (0, test_utils_js_1.switchClient)(1);
        await fs.remove((0, test_utils_js_1.exportDir)());
        await fs.mkdirp((0, test_utils_js_1.exportDir)());
    });
    const createExportItems = () => {
        const items = [];
        const queue = (itemType, itemOrId) => {
            items.push({ type: itemType, itemOrId });
        };
        return { items, queue };
    };
    it('should create resources directory', (async () => {
        const service = new InteropService_Exporter_Md_1.default();
        await service.init((0, test_utils_js_1.exportDir)());
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/_resources/`)).toBe(true);
    }));
    it('should create note paths and add them to context', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        let note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder1.id });
        await shim_1.default.attachFileToNote(note1, `${test_utils_js_1.supportDir}/photo.jpg`);
        note1 = await Note_1.default.load(note1.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note1.body))[0]);
        const folder2 = await Folder_1.default.save({ title: 'folder2' });
        let note3 = await Note_1.default.save({ title: 'note3', parent_id: folder2.id, markup_language: renderer_1.MarkupToHtml.MARKUP_LANGUAGE_HTML });
        await shim_1.default.attachFileToNote(note3, `${test_utils_js_1.supportDir}/photo.jpg`);
        note3 = await Note_1.default.load(note3.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note3);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note3.body))[0]);
        expect(!exporter.context() && !(exporter.context().notePaths || Object.keys(exporter.context().notePaths).length)).toBe(false);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        expect(Object.keys(exporter.context().notePaths).length).toBe(3);
        expect(exporter.context().notePaths[note1.id]).toBe('folder1/note1.md');
        expect(exporter.context().notePaths[note2.id]).toBe('folder1/note2.md');
        expect(exporter.context().notePaths[note3.id]).toBe('folder2/note3.html');
    }));
    it('should create resource paths and add them to context', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        let note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder1.id });
        await shim_1.default.attachFileToNote(note1, `${test_utils_js_1.supportDir}/photo.jpg`);
        note1 = await Note_1.default.load(note1.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note1.body))[0]);
        const resource1 = await Resource_1.default.load(itemsToExport[3].itemOrId);
        const folder2 = await Folder_1.default.save({ title: 'folder2' });
        let note3 = await Note_1.default.save({ title: 'note3', parent_id: folder2.id });
        await shim_1.default.attachFileToNote(note3, `${test_utils_js_1.supportDir}/photo.jpg`);
        note3 = await Note_1.default.load(note3.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note3);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note3.body))[0]);
        const resource2 = await Resource_1.default.load(itemsToExport[6].itemOrId);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processResource(resource1, Resource_1.default.fullPath(resource1));
        await exporter.processResource(resource2, Resource_1.default.fullPath(resource2));
        expect(!exporter.context() && !(exporter.context().destResourcePaths || Object.keys(exporter.context().destResourcePaths).length)).toBe(false);
        expect(Object.keys(exporter.context().destResourcePaths).length).toBe(2);
        expect(exporter.context().destResourcePaths[resource1.id]).toBe(`${(0, test_utils_js_1.exportDir)()}/_resources/photo.jpg`);
        expect(exporter.context().destResourcePaths[resource2.id]).toBe(`${(0, test_utils_js_1.exportDir)()}/_resources/photo-1.jpg`);
    }));
    it('should handle duplicate note names', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const note1_2 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1_2);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        expect(Object.keys(exporter.context().notePaths).length).toBe(2);
        expect(exporter.context().notePaths[note1.id]).toBe('folder1/note1.md');
        expect(exporter.context().notePaths[note1_2.id]).toBe('folder1/note1-1.md');
    }));
    it('should not override existing files', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        // Create a file with the path of note1 before processing note1
        await shim_1.default.fsDriver().writeFile(`${(0, test_utils_js_1.exportDir)()}/folder1/note1.md`, 'Note content', 'utf-8');
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        expect(Object.keys(exporter.context().notePaths).length).toBe(1);
        expect(exporter.context().notePaths[note1.id]).toBe('folder1/note1-1.md');
    }));
    it('should save resource files in _resource directory', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        let note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        await shim_1.default.attachFileToNote(note1, `${test_utils_js_1.supportDir}/photo.jpg`);
        note1 = await Note_1.default.load(note1.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note1.body))[0]);
        const resource1 = await Resource_1.default.load(itemsToExport[2].itemOrId);
        const folder2 = await Folder_1.default.save({ title: 'folder2', parent_id: folder1.id });
        let note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        await shim_1.default.attachFileToNote(note2, `${test_utils_js_1.supportDir}/photo.jpg`);
        note2 = await Note_1.default.load(note2.id);
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        queueExportItem(BaseModel_1.default.TYPE_RESOURCE, (await Note_1.default.linkedResourceIds(note2.body))[0]);
        const resource2 = await Resource_1.default.load(itemsToExport[5].itemOrId);
        await exporter.processResource(resource1, Resource_1.default.fullPath(resource1));
        await exporter.processResource(resource2, Resource_1.default.fullPath(resource2));
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/_resources/photo.jpg`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/_resources/photo-1.jpg`)).toBe(true);
    }));
    it('should create folders in fs', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const folder2 = await Folder_1.default.save({ title: 'folder2', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        const folder3 = await Folder_1.default.save({ title: 'folder3', parent_id: folder1.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder3.id);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.processItem(Folder_1.default.modelType(), folder3);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processItem(Note_1.default.modelType(), note2);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/folder1`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/folder1/folder2`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/folder1/folder3`)).toBe(true);
    }));
    it('should save notes in fs', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        const note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        const folder2 = await Folder_1.default.save({ title: 'folder2', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        const folder3 = await Folder_1.default.save({ title: 'folder3' });
        const note3 = await Note_1.default.save({ title: 'note3', parent_id: folder3.id });
        queueExportItem(BaseModel_1.default.TYPE_FOLDER, folder3.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note3);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        await exporter.processItem(Note_1.default.modelType(), note3);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note1.id]}`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note2.id]}`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note3.id]}`)).toBe(true);
    }));
    it('should replace resource ids with relative paths', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        let note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        await shim_1.default.attachFileToNote(note1, `${test_utils_js_1.supportDir}/photo.jpg`);
        note1 = await Note_1.default.load(note1.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        const resource1 = await Resource_1.default.load((await Note_1.default.linkedResourceIds(note1.body))[0]);
        const folder2 = await Folder_1.default.save({ title: 'folder2', parent_id: folder1.id });
        let note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        await shim_1.default.attachFileToNote(note2, `${test_utils_js_1.supportDir}/photo.jpg`);
        note2 = await Note_1.default.load(note2.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        const resource2 = await Resource_1.default.load((await Note_1.default.linkedResourceIds(note2.body))[0]);
        let note3 = await Note_1.default.save({ title: 'note3', parent_id: folder2.id });
        await shim_1.default.attachFileToNote(note3, `${test_utils_js_1.supportDir}/photo.jpg`);
        note3 = await Note_1.default.load(note3.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note3);
        const resource3 = await Resource_1.default.load((await Note_1.default.linkedResourceIds(note3.body))[0]);
        note3 = await Note_1.default.save(Object.assign(Object.assign({}, note3), { body: `<img src=":/${resource3.id}" alt="alt">` }));
        note3 = await Note_1.default.load(note3.id);
        let note4 = await Note_1.default.save({ title: 'note4', parent_id: folder2.id });
        await shim_1.default.attachFileToNote(note4, `${test_utils_js_1.supportDir}/photo.jpg`);
        note4 = await Note_1.default.load(note4.id);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note4);
        const resource4 = await Resource_1.default.load((await Note_1.default.linkedResourceIds(note4.body))[0]);
        note4 = await Note_1.default.save(Object.assign(Object.assign({}, note4), { body: `![](:/${resource4.id} "title")` }));
        note4 = await Note_1.default.load(note4.id);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processResource(resource1, Resource_1.default.fullPath(resource1));
        await exporter.processResource(resource2, Resource_1.default.fullPath(resource2));
        await exporter.processResource(resource3, Resource_1.default.fullPath(resource3));
        await exporter.processResource(resource4, Resource_1.default.fullPath(resource3));
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const context = {
            resourcePaths: {},
        };
        context.resourcePaths[resource1.id] = 'resource1.jpg';
        context.resourcePaths[resource2.id] = 'resource2.jpg';
        context.resourcePaths[resource3.id] = 'resource3.jpg';
        context.resourcePaths[resource4.id] = 'resource3.jpg';
        exporter.updateContext(context);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        await exporter.processItem(Note_1.default.modelType(), note3);
        await exporter.processItem(Note_1.default.modelType(), note4);
        const note1_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note1.id]}`);
        const note2_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note2.id]}`);
        const note3_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note3.id]}`);
        const note4_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note4.id]}`);
        expect(note1_body).toContain('](../_resources/photo.jpg)');
        expect(note2_body).toContain('](../../_resources/photo-1.jpg)');
        expect(note3_body).toContain('<img src="../../_resources/photo-2.jpg" alt="alt">');
        expect(note4_body).toContain('](../../_resources/photo-3.jpg "title")');
    }));
    it('should replace note ids with relative paths', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const changeNoteBodyAndReload = async (note, newBody) => {
            note.body = newBody;
            await Note_1.default.save(note);
            return await Note_1.default.load(note.id);
        };
        const folder1 = await Folder_1.default.save({ title: 'folder1' });
        let note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const folder2 = await Folder_1.default.save({ title: 'folder2', parent_id: folder1.id });
        let note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        const folder3 = await Folder_1.default.save({ title: 'folder3' });
        let note3 = await Note_1.default.save({ title: 'note3', parent_id: folder3.id });
        note1 = await changeNoteBodyAndReload(note1, `# Some text \n\n [A link to note3](:/${note3.id})`);
        note2 = await changeNoteBodyAndReload(note2, `# Some text \n\n [A link to note3](:/${note3.id}) some more text \n ## And some headers \n and [A link to note1](:/${note1.id}) more links`);
        note3 = await changeNoteBodyAndReload(note3, `[A link to note3](:/${note2.id})`);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note3);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.processItem(Folder_1.default.modelType(), folder3);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        await exporter.processItem(Note_1.default.modelType(), note3);
        const note1_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note1.id]}`);
        const note2_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note2.id]}`);
        const note3_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note3.id]}`);
        expect(note1_body).toContain('](../folder3/note3.md)');
        expect(note2_body).toContain('](../../folder3/note3.md)');
        expect(note2_body).toContain('](../../folder1/note1.md)');
        expect(note3_body).toContain('](../folder1/folder2/note2.md)');
    }));
    it('should url encode relative note links', (async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const itemsToExport = [];
        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
        const queueExportItem = (itemType, itemOrId) => {
            itemsToExport.push({
                type: itemType,
                itemOrId: itemOrId,
            });
        };
        const folder1 = await Folder_1.default.save({ title: 'folder with space1' });
        const note1 = await Note_1.default.save({ title: 'note1 name with space', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder1.id, body: `[link](:/${note1.id})` });
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note1);
        queueExportItem(BaseModel_1.default.TYPE_NOTE, note2);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, itemsToExport);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        const note2_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/${exporter.context().notePaths[note2.id]}`);
        expect(note2_body).toContain('[link](../folder%20with%20space1/note1%20name%20with%20space.md)');
    }));
    it('should preserve resource file extension', (async () => {
        const folder = await Folder_1.default.save({ title: 'testing' });
        const note = await Note_1.default.save({ title: 'mynote', parent_id: folder.id });
        await shim_1.default.attachFileToNote(note, `${test_utils_js_1.supportDir}/photo.jpg`);
        const resource = (await Resource_1.default.all())[0];
        await Resource_1.default.save({ id: resource.id, title: 'veryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitle.jpg' });
        const service = InteropService_js_1.default.instance();
        await service.export({
            path: (0, test_utils_js_1.exportDir)(),
            format: types_js_1.ExportModuleOutputFormat.Markdown,
        });
        const resourceFilename = (await fs.readdir(`${(0, test_utils_js_1.exportDir)()}/_resources`))[0];
        expect((0, path_utils_js_1.fileExtension)(resourceFilename)).toBe('jpg');
    }));
    it('should url encode resource links', (async () => {
        const folder = await Folder_1.default.save({ title: 'testing' });
        const note = await Note_1.default.save({ title: 'mynote', parent_id: folder.id });
        await shim_1.default.attachFileToNote(note, `${test_utils_js_1.supportDir}/photo.jpg`);
        const resource = (await Resource_1.default.all())[0];
        await Resource_1.default.save({ id: resource.id, title: 'name with spaces.jpg' });
        const service = InteropService_js_1.default.instance();
        await service.export({
            path: (0, test_utils_js_1.exportDir)(),
            format: types_js_1.ExportModuleOutputFormat.Markdown,
        });
        const note_body = await shim_1.default.fsDriver().readFile(`${(0, test_utils_js_1.exportDir)()}/testing/mynote.md`);
        expect(note_body).toContain('[photo.jpg](../_resources/name%20with%20spaces.jpg)');
    }));
    it.each([
        { titles: ['folder:', 'folder?'], expectedPaths: ['folder_/note1.md', 'folder_-1/note2.md'], description: 'special characters' },
        { titles: ['CON', 'NUL'], expectedPaths: ['___/note1.md', '___-1/note2.md'], description: 'Windows-banned names' },
    ])('should handle folders that collide after sanitization ($description)', async ({ titles, expectedPaths }) => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init((0, test_utils_js_1.exportDir)());
        const { items, queue } = createExportItems();
        const folder1 = await Folder_1.default.save({ title: titles[0] });
        const folder2 = await Folder_1.default.save({ title: titles[1] });
        const note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        queue(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queue(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queue(BaseModel_1.default.TYPE_NOTE, note1);
        queue(BaseModel_1.default.TYPE_NOTE, note2);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_FOLDER, items);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, items);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        expect(Object.keys(exporter.context().notePaths).length).toBe(2);
        expect(exporter.context().notePaths[note1.id]).toBe(expectedPaths[0]);
        expect(exporter.context().notePaths[note2.id]).toBe(expectedPaths[1]);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/${expectedPaths[0]}`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/${expectedPaths[1]}`)).toBe(true);
    });
    it('should handle folders that collide after sanitization when the export path contains a dot', async () => {
        const exporter = new InteropService_Exporter_Md_1.default();
        await exporter.init(`${(0, test_utils_js_1.exportDir)()}/parent.with.dot/export`);
        const { items, queue } = createExportItems();
        const folder1 = await Folder_1.default.save({ title: 'folder:' });
        const folder2 = await Folder_1.default.save({ title: 'folder?' });
        const note1 = await Note_1.default.save({ title: 'note1', parent_id: folder1.id });
        const note2 = await Note_1.default.save({ title: 'note2', parent_id: folder2.id });
        queue(BaseModel_1.default.TYPE_FOLDER, folder1.id);
        queue(BaseModel_1.default.TYPE_FOLDER, folder2.id);
        queue(BaseModel_1.default.TYPE_NOTE, note1);
        queue(BaseModel_1.default.TYPE_NOTE, note2);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_FOLDER, items);
        await exporter.prepareForProcessingItemType(BaseModel_1.default.TYPE_NOTE, items);
        await exporter.processItem(Folder_1.default.modelType(), folder1);
        await exporter.processItem(Folder_1.default.modelType(), folder2);
        await exporter.processItem(Note_1.default.modelType(), note1);
        await exporter.processItem(Note_1.default.modelType(), note2);
        expect(exporter.context().notePaths[note1.id]).toBe('folder_/note1.md');
        expect(exporter.context().notePaths[note2.id]).toBe('folder_-1/note2.md');
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/parent.with.dot/export/folder_/note1.md`)).toBe(true);
        expect(await shim_1.default.fsDriver().exists(`${(0, test_utils_js_1.exportDir)()}/parent.with.dot/export/folder_-1/note2.md`)).toBe(true);
    });
    it('should handle filenames that contain slashes', (async () => {
        const folder = await Folder_1.default.save({ title: 'testing' });
        const note = await Note_1.default.save({ title: 'mynote', parent_id: folder.id });
        await shim_1.default.attachFileToNote(note, `${test_utils_js_1.supportDir}/photo.jpg`);
        const resource = (await Resource_1.default.all())[0];
        await Resource_1.default.save({ id: resource.id, filename: 'a/b/c/test.jpg', title: 'name with spaces.jpg' });
        const service = InteropService_js_1.default.instance();
        await service.export({
            path: (0, test_utils_js_1.exportDir)(),
            format: types_js_1.ExportModuleOutputFormat.Markdown,
        });
        const files = await (0, promises_1.readdir)(`${(0, test_utils_js_1.exportDir)()}/_resources`);
        expect(files).toEqual(['a_b_c_test.jpg']);
    }));
});
//# sourceMappingURL=InteropService_Exporter_Md.test.js.map