diff --git a/src/services/export/zip.js b/src/services/export/zip.js index c21546672..e6e9476e6 100644 --- a/src/services/export/zip.js +++ b/src/services/export/zip.js @@ -16,7 +16,6 @@ const archiver = require('archiver'); const log = require("../log"); const TaskContext = require("../task_context"); const ValidationError = require("../../errors/validation_error"); -const MetaFile = require("../meta/meta_file"); const NoteMeta = require("../meta/note_meta"); const AttachmentMeta = require("../meta/attachment_meta"); const AttributeMeta = require("../meta/attribute_meta"); @@ -40,24 +39,6 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) /** @type {Object.} */ const noteIdToMeta = {}; - /** @type {Object.} */ - const childNoteIdToParentMeta = {}; - - /** @type {Object.} */ - const parentNoteIdToChildrenMeta = {}; - - function getNotePath(noteId) { - const notePath = [noteId]; - - let cur = noteIdToMeta[noteId]; - while (cur = childNoteIdToParentMeta[cur.noteId]) { - notePath.push(cur.noteId); - } - - notePath.reverse(); - return notePath; - } - /** * @param {Object.} existingFileNames * @param {string} fileName @@ -135,49 +116,13 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) return getUniqueFilename(existingFileNames, fileName); } - /** - * @param {BBranch[]} branches - * @param {Object.} existingFileNames - * @returns {MetaFile} - */ - function createMetaFileForDirectory(branches, existingFileNames = {}) { - // namespace is shared by children in the same note - const metas = []; - - for (const branch of branches) { - const noteMeta = createNoteMeta(branch, existingFileNames); - - // can be undefined if export is disabled for this note - if (noteMeta) { - metas.push(noteMeta); - - const parentMeta = noteIdToMeta[branch.parentNoteId]; - - if (parentMeta) { - childNoteIdToParentMeta[noteMeta.noteId] = parentMeta; - parentNoteIdToChildrenMeta[parentMeta.noteId] = parentNoteIdToChildrenMeta[parentMeta.noteId] || []; - parentNoteIdToChildrenMeta[parentMeta.noteId].push(noteMeta); - } - } - } - - if (!metas.length) { - return null; - } - - const metaFile = new MetaFile(); - metaFile.formatVersion = 3; - metaFile.appVersion = packageInfo.version; - metaFile.files = metas; - return metaFile; - } - /** * @param {BBranch} branch + * @param {NoteMeta} parentMeta * @param {Object.} existingFileNames * @returns {NoteMeta|null} */ - function createNoteMeta(branch, existingFileNames) { + function createNoteMeta(branch, parentMeta, existingFileNames) { const note = branch.getNote(); if (note.hasOwnedLabel('excludeFromExport')) { @@ -192,13 +137,15 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) baseFileName = baseFileName.substr(0, 200); } + const notePath = parentMeta.notePath.concat([note.noteId]); + if (note.noteId in noteIdToMeta) { - const fileName = getUniqueFilename(existingFileNames, - `${baseFileName}.clone.${format === 'html' ? 'html' : 'md'}`); + const fileName = getUniqueFilename(existingFileNames, `${baseFileName}.clone.${format === 'html' ? 'html' : 'md'}`); const meta = new NoteMeta(); meta.isClone = true; meta.noteId = note.noteId; + meta.notePath = notePath; meta.title = note.getTitleOrProtected(); meta.prefix = branch.prefix; meta.dataFileName = fileName; @@ -210,6 +157,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) const meta = new NoteMeta(); meta.isClone = false; meta.noteId = note.noteId; + meta.notePath = notePath; meta.title = note.getTitleOrProtected(); meta.notePosition = branch.notePosition; meta.prefix = branch.prefix; @@ -260,10 +208,23 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) existingFileNames ); return attMeta; - }); + }); if (childBranches.length > 0) { meta.dirFileName = getUniqueFilename(existingFileNames, baseFileName); + meta.children = []; + + // namespace is shared by children in the same note + const childExistingNames = {}; + + for (const childBranch of childBranches) { + const note = createNoteMeta(childBranch, meta, childExistingNames); + + // can be undefined if export is disabled for this note + if (note) { + meta.children.push(note); + } + } } return meta; @@ -281,8 +242,8 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) return null; } - const targetPath = getNotePath(targetMeta.noteId); - const sourcePath = getNotePath(sourceMeta.noteId); + const targetPath = targetMeta.notePath.slice(); + const sourcePath = sourceMeta.notePath.slice(); // > 1 for the edge case that targetPath and sourcePath are exact same (a link to itself) while (targetPath.length > 1 && sourcePath.length > 1 && targetPath[0] === sourcePath[0]) { @@ -367,7 +328,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) if (noteMeta.format === 'html') { if (!content.substr(0, 100).toLowerCase().includes(" element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809 @@ -448,17 +409,14 @@ ${markdownContent}`; }); } - const metaFile = createMetaFileForDirectory(note.getChildBranches()); - if (metaFile) { - const childFilePathPrefix = `${filePathPrefix}${noteMeta.dirFileName}/`; + if (noteMeta.children?.length > 0) { + const directoryPath = filePathPrefix + noteMeta.dirFileName; // create directory - archive.append('', { name: childFilePathPrefix, date: dateUtils.parseDateTime(note.utcDateModified) }); + archive.append('', { name: `${directoryPath}/`, date: dateUtils.parseDateTime(note.utcDateModified) }); - metaFile.save(archive, childFilePathPrefix); - - for (const childMeta of metaFile.files) { - saveNote(childMeta, childFilePathPrefix); + for (const childMeta of noteMeta.children) { + saveNote(childMeta, `${directoryPath}/`); } } } @@ -482,13 +440,11 @@ ${markdownContent}`; html += escapedTitle; } - const childrenMeta = parentNoteIdToChildrenMeta[meta.noteId]; - - if (childrenMeta?.length > 0) { + if (meta.children && meta.children.length > 0) { html += '
    '; - for (const childMeta of childrenMeta) { - html += saveNavigationInner(childMeta); + for (const child of meta.children) { + html += saveNavigationInner(child); } html += '
' @@ -526,10 +482,8 @@ ${markdownContent}`; firstNonEmptyNote = getNoteTargetUrl(curMeta.noteId, rootMeta); } - const childrenMeta = parentNoteIdToChildrenMeta[curMeta.noteId]; - - if (childrenMeta?.length > 0) { - curMeta = childrenMeta[0]; + if (curMeta.children && curMeta.children.length > 0) { + curMeta = curMeta.children[0]; } else { break; @@ -561,13 +515,14 @@ ${markdownContent}`; archive.append(cssContent, { name: cssMeta.dataFileName }); } - const existingFileNames = format === 'html' ? { 'navigation': 1, 'index': 1 } : {}; - const metaFile = createMetaFileForDirectory([branch], existingFileNames); + const existingFileNames = format === 'html' ? ['navigation', 'index'] : []; + const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames); - if (!metaFile) { // corner case of disabled export for exported note - res.sendStatus(400); - return; - } + const metaFile = { + formatVersion: 2, + appVersion: packageInfo.version, + files: [ rootMeta ] + }; let navigationMeta, indexMeta, cssMeta; @@ -610,9 +565,15 @@ ${markdownContent}`; }); } - metaFile.save(archive); + if (!rootMeta) { // corner case of disabled export for exported note + res.sendStatus(400); + return; + } + + const metaFileJson = JSON.stringify(metaFile, null, '\t'); + + archive.append(metaFileJson, { name: "!!!meta.json" }); - const rootMeta = metaFile.files[0]; saveNote(rootMeta, ''); if (format === 'html') { diff --git a/src/services/meta/meta_file.js b/src/services/meta/meta_file.js deleted file mode 100644 index 9fcdff480..000000000 --- a/src/services/meta/meta_file.js +++ /dev/null @@ -1,16 +0,0 @@ -class MetaFile { - /** @type {int} */ - formatVersion; - /** @type {string} */ - appVersion; - /** @type {NoteMeta[]} */ - files; - - save(archive, filePathPrefix = '') { - const metaFileJson = JSON.stringify(this, null, '\t'); - - archive.append(metaFileJson, { name: filePathPrefix + "!!!meta.json" }); - } -} - -module.exports = MetaFile; diff --git a/src/services/meta/note_meta.js b/src/services/meta/note_meta.js index 3c280d978..fd24381d6 100644 --- a/src/services/meta/note_meta.js +++ b/src/services/meta/note_meta.js @@ -1,10 +1,7 @@ class NoteMeta { /** @type {string} */ noteId; - /** - * @type {string[]} - * @deprecated unused as of v3 - */ + /** @type {string} */ notePath; /** @type {boolean} */ isClone; @@ -32,10 +29,7 @@ class NoteMeta { attributes; /** @type {AttachmentMeta[]} */ attachments; - /** - * @type {NoteMeta[]|undefined} - * @deprecated unused as of v3, there's meta file for each directory, avoiding the need to use this - */ + /** @type {NoteMeta[]|undefined} */ children; }