/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/crypt/crypt.js var require_crypt = __commonJS({ "node_modules/crypt/crypt.js"(exports, module2) { (function() { var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", crypt = { rotl: function(n, b) { return n << b | n >>> 32 - b; }, rotr: function(n, b) { return n << 32 - b | n >>> b; }, endian: function(n) { if (n.constructor == Number) { return crypt.rotl(n, 8) & 16711935 | crypt.rotl(n, 24) & 4278255360; } for (var i = 0; i < n.length; i++) n[i] = crypt.endian(n[i]); return n; }, randomBytes: function(n) { for (var bytes = []; n > 0; n--) bytes.push(Math.floor(Math.random() * 256)); return bytes; }, bytesToWords: function(bytes) { for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8) words[b >>> 5] |= bytes[i] << 24 - b % 32; return words; }, wordsToBytes: function(words) { for (var bytes = [], b = 0; b < words.length * 32; b += 8) bytes.push(words[b >>> 5] >>> 24 - b % 32 & 255); return bytes; }, bytesToHex: function(bytes) { for (var hex = [], i = 0; i < bytes.length; i++) { hex.push((bytes[i] >>> 4).toString(16)); hex.push((bytes[i] & 15).toString(16)); } return hex.join(""); }, hexToBytes: function(hex) { for (var bytes = [], c = 0; c < hex.length; c += 2) bytes.push(parseInt(hex.substr(c, 2), 16)); return bytes; }, bytesToBase64: function(bytes) { for (var base64 = [], i = 0; i < bytes.length; i += 3) { var triplet = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2]; for (var j = 0; j < 4; j++) if (i * 8 + j * 6 <= bytes.length * 8) base64.push(base64map.charAt(triplet >>> 6 * (3 - j) & 63)); else base64.push("="); } return base64.join(""); }, base64ToBytes: function(base64) { base64 = base64.replace(/[^A-Z0-9+\/]/ig, ""); for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) { if (imod4 == 0) continue; bytes.push((base64map.indexOf(base64.charAt(i - 1)) & Math.pow(2, -2 * imod4 + 8) - 1) << imod4 * 2 | base64map.indexOf(base64.charAt(i)) >>> 6 - imod4 * 2); } return bytes; } }; module2.exports = crypt; })(); } }); // node_modules/charenc/charenc.js var require_charenc = __commonJS({ "node_modules/charenc/charenc.js"(exports, module2) { var charenc = { utf8: { stringToBytes: function(str) { return charenc.bin.stringToBytes(unescape(encodeURIComponent(str))); }, bytesToString: function(bytes) { return decodeURIComponent(escape(charenc.bin.bytesToString(bytes))); } }, bin: { stringToBytes: function(str) { for (var bytes = [], i = 0; i < str.length; i++) bytes.push(str.charCodeAt(i) & 255); return bytes; }, bytesToString: function(bytes) { for (var str = [], i = 0; i < bytes.length; i++) str.push(String.fromCharCode(bytes[i])); return str.join(""); } } }; module2.exports = charenc; } }); // node_modules/is-buffer/index.js var require_is_buffer = __commonJS({ "node_modules/is-buffer/index.js"(exports, module2) { module2.exports = function(obj) { return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer); }; function isBuffer(obj) { return !!obj.constructor && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj); } function isSlowBuffer(obj) { return typeof obj.readFloatLE === "function" && typeof obj.slice === "function" && isBuffer(obj.slice(0, 0)); } } }); // node_modules/md5/md5.js var require_md5 = __commonJS({ "node_modules/md5/md5.js"(exports, module2) { (function() { var crypt = require_crypt(), utf8 = require_charenc().utf8, isBuffer = require_is_buffer(), bin = require_charenc().bin, md52 = function(message, options) { if (message.constructor == String) if (options && options.encoding === "binary") message = bin.stringToBytes(message); else message = utf8.stringToBytes(message); else if (isBuffer(message)) message = Array.prototype.slice.call(message, 0); else if (!Array.isArray(message) && message.constructor !== Uint8Array) message = message.toString(); var m = crypt.bytesToWords(message), l = message.length * 8, a = 1732584193, b = -271733879, c = -1732584194, d = 271733878; for (var i = 0; i < m.length; i++) { m[i] = (m[i] << 8 | m[i] >>> 24) & 16711935 | (m[i] << 24 | m[i] >>> 8) & 4278255360; } m[l >>> 5] |= 128 << l % 32; m[(l + 64 >>> 9 << 4) + 14] = l; var FF = md52._ff, GG = md52._gg, HH = md52._hh, II = md52._ii; for (var i = 0; i < m.length; i += 16) { var aa = a, bb = b, cc = c, dd = d; a = FF(a, b, c, d, m[i + 0], 7, -680876936); d = FF(d, a, b, c, m[i + 1], 12, -389564586); c = FF(c, d, a, b, m[i + 2], 17, 606105819); b = FF(b, c, d, a, m[i + 3], 22, -1044525330); a = FF(a, b, c, d, m[i + 4], 7, -176418897); d = FF(d, a, b, c, m[i + 5], 12, 1200080426); c = FF(c, d, a, b, m[i + 6], 17, -1473231341); b = FF(b, c, d, a, m[i + 7], 22, -45705983); a = FF(a, b, c, d, m[i + 8], 7, 1770035416); d = FF(d, a, b, c, m[i + 9], 12, -1958414417); c = FF(c, d, a, b, m[i + 10], 17, -42063); b = FF(b, c, d, a, m[i + 11], 22, -1990404162); a = FF(a, b, c, d, m[i + 12], 7, 1804603682); d = FF(d, a, b, c, m[i + 13], 12, -40341101); c = FF(c, d, a, b, m[i + 14], 17, -1502002290); b = FF(b, c, d, a, m[i + 15], 22, 1236535329); a = GG(a, b, c, d, m[i + 1], 5, -165796510); d = GG(d, a, b, c, m[i + 6], 9, -1069501632); c = GG(c, d, a, b, m[i + 11], 14, 643717713); b = GG(b, c, d, a, m[i + 0], 20, -373897302); a = GG(a, b, c, d, m[i + 5], 5, -701558691); d = GG(d, a, b, c, m[i + 10], 9, 38016083); c = GG(c, d, a, b, m[i + 15], 14, -660478335); b = GG(b, c, d, a, m[i + 4], 20, -405537848); a = GG(a, b, c, d, m[i + 9], 5, 568446438); d = GG(d, a, b, c, m[i + 14], 9, -1019803690); c = GG(c, d, a, b, m[i + 3], 14, -187363961); b = GG(b, c, d, a, m[i + 8], 20, 1163531501); a = GG(a, b, c, d, m[i + 13], 5, -1444681467); d = GG(d, a, b, c, m[i + 2], 9, -51403784); c = GG(c, d, a, b, m[i + 7], 14, 1735328473); b = GG(b, c, d, a, m[i + 12], 20, -1926607734); a = HH(a, b, c, d, m[i + 5], 4, -378558); d = HH(d, a, b, c, m[i + 8], 11, -2022574463); c = HH(c, d, a, b, m[i + 11], 16, 1839030562); b = HH(b, c, d, a, m[i + 14], 23, -35309556); a = HH(a, b, c, d, m[i + 1], 4, -1530992060); d = HH(d, a, b, c, m[i + 4], 11, 1272893353); c = HH(c, d, a, b, m[i + 7], 16, -155497632); b = HH(b, c, d, a, m[i + 10], 23, -1094730640); a = HH(a, b, c, d, m[i + 13], 4, 681279174); d = HH(d, a, b, c, m[i + 0], 11, -358537222); c = HH(c, d, a, b, m[i + 3], 16, -722521979); b = HH(b, c, d, a, m[i + 6], 23, 76029189); a = HH(a, b, c, d, m[i + 9], 4, -640364487); d = HH(d, a, b, c, m[i + 12], 11, -421815835); c = HH(c, d, a, b, m[i + 15], 16, 530742520); b = HH(b, c, d, a, m[i + 2], 23, -995338651); a = II(a, b, c, d, m[i + 0], 6, -198630844); d = II(d, a, b, c, m[i + 7], 10, 1126891415); c = II(c, d, a, b, m[i + 14], 15, -1416354905); b = II(b, c, d, a, m[i + 5], 21, -57434055); a = II(a, b, c, d, m[i + 12], 6, 1700485571); d = II(d, a, b, c, m[i + 3], 10, -1894986606); c = II(c, d, a, b, m[i + 10], 15, -1051523); b = II(b, c, d, a, m[i + 1], 21, -2054922799); a = II(a, b, c, d, m[i + 8], 6, 1873313359); d = II(d, a, b, c, m[i + 15], 10, -30611744); c = II(c, d, a, b, m[i + 6], 15, -1560198380); b = II(b, c, d, a, m[i + 13], 21, 1309151649); a = II(a, b, c, d, m[i + 4], 6, -145523070); d = II(d, a, b, c, m[i + 11], 10, -1120210379); c = II(c, d, a, b, m[i + 2], 15, 718787259); b = II(b, c, d, a, m[i + 9], 21, -343485551); a = a + aa >>> 0; b = b + bb >>> 0; c = c + cc >>> 0; d = d + dd >>> 0; } return crypt.endian([a, b, c, d]); }; md52._ff = function(a, b, c, d, x, s, t) { var n = a + (b & c | ~b & d) + (x >>> 0) + t; return (n << s | n >>> 32 - s) + b; }; md52._gg = function(a, b, c, d, x, s, t) { var n = a + (b & d | c & ~d) + (x >>> 0) + t; return (n << s | n >>> 32 - s) + b; }; md52._hh = function(a, b, c, d, x, s, t) { var n = a + (b ^ c ^ d) + (x >>> 0) + t; return (n << s | n >>> 32 - s) + b; }; md52._ii = function(a, b, c, d, x, s, t) { var n = a + (c ^ (b | ~d)) + (x >>> 0) + t; return (n << s | n >>> 32 - s) + b; }; md52._blocksize = 16; md52._digestsize = 16; module2.exports = function(message, options) { if (message === void 0 || message === null) throw new Error("Illegal argument " + message); var digestbytes = crypt.wordsToBytes(md52(message, options)); return options && options.asBytes ? digestbytes : options && options.asString ? bin.bytesToString(digestbytes) : crypt.bytesToHex(digestbytes); }; })(); } }); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => MarkdownExportPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian3 = require("obsidian"); var path3 = __toESM(require("path")); // src/config.ts var ATTACHMENT_URL_REGEXP = /!\[\[((.*?)\.(\w+))(?:\s*\|\s*(?\d+%?)\s*(?:[*|x]\s*(?\d+%?))?)?\]\]/g; var MARKDOWN_ATTACHMENT_URL_REGEXP = /!\[(.*?)\]\(((.*?)\.(\w+))\)/g; var EMBED_URL_REGEXP = /!\[\[([\s\S]*?)\]\]/g; var EMBED_METADATA_REGEXP = /^---(?:\n|\r\n)[\s\S]*?(?:\n|\r\n)---(?:\n|\r\n)?/; var GFM_IMAGE_FORMAT = "![]({0})"; var OUTGOING_LINK_REGEXP = /(? String(num).padStart(len, "0"); const variables = { fileName: fileName.replace(/\.[^/.]+$/, "").replace(/[/\\]/g, ""), date: `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`, time: `${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`, datetime: `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}-${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`, timestamp: String(now.getTime()), year: String(now.getFullYear()), month: pad(now.getMonth() + 1), day: pad(now.getDate()), hour: pad(now.getHours()), minute: pad(now.getMinutes()), second: pad(now.getSeconds()), vaultName }; let result = pathTemplate; for (const [key, value] of Object.entries(variables)) { result = result.replace(new RegExp(`{{${key}}}`, "g"), value); } return result; } // src/utils.ts var path2 = __toESM(require("path")); var fs = __toESM(require("fs")); var import_md5 = __toESM(require_md5()); var import_obsidian2 = require("obsidian"); // src/renderer.ts var path = __toESM(require("path")); var import_obsidian = require("obsidian"); async function markdownToHTML(plugin, inputFile, inputContent) { let activeView = app.workspace.getActiveViewOfType(import_obsidian.MarkdownView); const leaf = app.workspace.getLeaf(true); if (!activeView) { activeView = new import_obsidian.MarkdownView(leaf); } const wrapper = document.createElement("div"); wrapper.style.display = "hidden"; document.body.appendChild(wrapper); await import_obsidian.MarkdownRenderer.renderMarkdown(inputContent, wrapper, path.dirname(inputFile), activeView); const html = wrapper.innerHTML; document.body.removeChild(wrapper); leaf.detach(); return { html }; } // src/utils.ts async function getImageLinks(markdown) { const imageLinks = markdown.matchAll(ATTACHMENT_URL_REGEXP); const markdownImageLinks = markdown.matchAll(MARKDOWN_ATTACHMENT_URL_REGEXP); return Array.from(imageLinks).concat(Array.from(markdownImageLinks)); } async function getEmbeds(markdown) { const embeds = markdown.matchAll(EMBED_URL_REGEXP); return Array.from(embeds); } function getFilesWithTag(plugin, tag) { const normalizedTag = tag.startsWith("#") ? tag : `#${tag}`; const filesWithTag = []; const markdownFiles = plugin.app.vault.getMarkdownFiles(); for (const file of markdownFiles) { const cache = plugin.app.metadataCache.getFileCache(file); if (cache) { if (hasTag(cache, normalizedTag)) { filesWithTag.push(file); } } } return filesWithTag; } function hasTag(cache, tag) { if (cache.frontmatter && cache.frontmatter.tags) { const frontmatterTags = cache.frontmatter.tags; if (Array.isArray(frontmatterTags)) { for (const t of frontmatterTags) { if (typeof t === "string" && tagsMatch(t, tag)) { return true; } } } else if (typeof frontmatterTags === "string") { const tags = frontmatterTags.split(",").map((t) => t.trim()); for (const t of tags) { if (tagsMatch(t, tag)) { return true; } } } } if (cache.tags) { for (const tagObj of cache.tags) { if (tagObj.tag && tagsMatch(tagObj.tag, tag)) { return true; } } } return false; } function tagsMatch(fileTag, searchTag) { const normalizedFileTag = fileTag.startsWith("#") ? fileTag : `#${fileTag}`; if (normalizedFileTag === searchTag) { return true; } if (normalizedFileTag.startsWith(searchTag + "/")) { return true; } return false; } function allMarkdownParams(file, out, outputFormat = "Markdown" /* MD */, outputSubPath = ".", parentPath = "") { try { if (!file.extension) { for (const absFile of file.children) { if (!absFile.extension) { const extname2 = absFile.path.replace(file.path, "").slice(1); const outputSubPath2 = path2.join(parentPath, extname2); allMarkdownParams(absFile, out, outputFormat, outputSubPath2, outputSubPath2); } else { out.push({ file: absFile, outputFormat, outputSubPath }); } } } else { out.push({ file, outputFormat, outputSubPath }); } } catch (e) { console.warn("Path Error:" + parentPath); } return out; } async function tryRun(plugin, file, outputFormat = "Markdown" /* MD */) { try { const params = allMarkdownParams(file, [], outputFormat); for (const param of params) { await tryCopyMarkdownByRead(plugin, param); } } catch (error) { if (!error.message.contains("file already exists")) { throw error; } } } async function tryRunBatch(plugin, files, outputFormat = "Markdown" /* MD */) { const result = { success: 0, failed: 0, errors: [] }; for (const file of files) { try { const params = allMarkdownParams(file, [], outputFormat, "."); for (const param of params) { await tryCopyMarkdownByRead(plugin, param); } result.success++; } catch (error) { result.failed++; const errorMsg = `Failed to export ${file.path}: ${error.message}`; result.errors.push(errorMsg); console.error(errorMsg); } } return result; } function getResourceOsPath(plugin, resouorce) { if (resouorce === null) { return "."; } const appPath = plugin.app.vault.getResourcePath(resouorce); const match = appPath.match(/app:\/\/(.*?)\//); if (match) { const hash = match[1]; const result = appPath.replace(`app://${hash}/`, process.platform === "win32" ? "" : "/").split("?")[0]; return decodeURIComponent(result); } return "."; } function getClickSubRoute(p, sep = "/") { if (p === ".") { return ""; } const parentLevels = p.split(sep).length; const parentRoute = ".." + sep; return parentRoute.repeat(parentLevels); } function fileExists(path4) { try { return fs.statSync(path4).isFile(); } catch (error) { if (error.code === "ENOENT") { return false; } else { throw error; } } } async function tryCreateFolder(plugin, p) { try { if (p.startsWith("/") || path2.win32.isAbsolute(p)) { fs.mkdirSync(p, { recursive: true }); } else { await plugin.app.vault.createFolder(p); } } catch (error) { if (!error.message.contains("Folder already exists")) { throw error; } } } async function tryCreate(plugin, p, data) { try { if (p.startsWith("/") || path2.win32.isAbsolute(p)) { fs.writeFileSync(p, data); } else { await plugin.app.vault.create(p, data); } } catch (error) { if (!error.message.contains("file already exists")) { throw error; } } } async function tryCopyImage(plugin, filename, contentPath) { try { await plugin.app.vault.adapter.read(contentPath).then(async (content) => { const imageLinks = await getImageLinks(content); const vaultName = plugin.app.vault.getName(); const fileNameWithoutExt = filename.replace(/\.[^/.]+$/, ""); for (const index in imageLinks) { const urlEncodedImageLink = imageLinks[index][7 - imageLinks[index].length]; let imageLink = decodeURI(urlEncodedImageLink).replace(/\.\.\//g, ""); if (imageLink.contains("|")) { imageLink = imageLink.split("|")[0]; } const fileName = path2.parse(path2.basename(imageLink)).name; const imageLinkMd5 = plugin.settings.fileNameEncode ? (0, import_md5.default)(imageLink) : encodeURI(fileName); const imageExt = path2.extname(imageLink); const ifile = plugin.app.metadataCache.getFirstLinkpathDest(imageLink, contentPath); const filePath = ifile !== null ? ifile.path : path2.join(path2.dirname(contentPath), imageLink); if (urlEncodedImageLink.startsWith("http")) { continue; } const resolvedAttachPath = resolvePathVariables(plugin.settings.attachment, fileNameWithoutExt, vaultName); const targetPath = path2.join(plugin.settings.relAttachPath ? plugin.settings.output : resolvedAttachPath, plugin.settings.includeFileName ? fileNameWithoutExt : "", plugin.settings.relAttachPath ? resolvedAttachPath : "", imageLinkMd5.concat(imageExt)).replace(/\\/g, "/"); if (filePath === targetPath) { continue; } try { if (!fileExists(targetPath)) { if (plugin.settings.output.startsWith("/") || path2.win32.isAbsolute(plugin.settings.output)) { const resourceOsPath = getResourceOsPath(plugin, ifile); fs.copyFileSync(resourceOsPath, targetPath); } else { await plugin.app.vault.adapter.copy(filePath, targetPath); } } } catch (error) { console.error(`Failed to copy file from ${filePath} to ${targetPath}: ${error.message}`); } } }); } catch (error) { if (!error.message.contains("file already exists")) { throw error; } } } async function getHeadingContent(plugin, filePath, heading) { try { const file = plugin.app.vault.getAbstractFileByPath(filePath); if (!(file instanceof import_obsidian2.TFile)) { return null; } const content = await plugin.app.vault.cachedRead(file); const lines = content.split("\n"); const normalizedTarget = heading.toLowerCase().trim(); let startIndex = -1; let headingLevel = 0; for (let i = 0; i < lines.length; i++) { const headingMatch = lines[i].match(/^(#{1,6})\s+(.+)$/); if (headingMatch) { const level = headingMatch[1].length; const text = headingMatch[2].toLowerCase().trim(); if (text === normalizedTarget) { startIndex = i; headingLevel = level; break; } } } if (startIndex === -1) { return null; } let endIndex = lines.length; for (let i = startIndex + 1; i < lines.length; i++) { const nextHeadingMatch = lines[i].match(/^(#{1,6})\s/); if (nextHeadingMatch) { const nextLevel = nextHeadingMatch[1].length; if (nextLevel <= headingLevel) { endIndex = i; break; } } } const headingLines = lines.slice(startIndex, endIndex); return headingLines.join("\n"); } catch (error) { console.error("Error getting heading content:", error); return null; } } async function getEmbedContentFromSource(plugin, embedLink, currentPath) { const parsed = parseEmbedLink(embedLink, currentPath); if (!parsed.filePath) { return null; } try { const file = plugin.app.vault.getAbstractFileByPath(parsed.filePath); if (!(file instanceof import_obsidian2.TFile)) { return null; } let content = await plugin.app.vault.cachedRead(file); if (parsed.blockId) { const blockContent = await getBlockContent(plugin, parsed.filePath, parsed.blockId); if (plugin.settings.removeYamlHeader && blockContent) { return blockContent.replace(EMBED_METADATA_REGEXP, ""); } return blockContent; } if (parsed.heading) { const headingContent = await getHeadingContent(plugin, parsed.filePath, parsed.heading); if (plugin.settings.removeYamlHeader && headingContent) { return headingContent.replace(EMBED_METADATA_REGEXP, ""); } return headingContent; } if (plugin.settings.removeYamlHeader) { content = content.replace(EMBED_METADATA_REGEXP, ""); } return content; } catch (error) { console.error("Error getting embed content from source:", error); return null; } } async function getEmbedMap(plugin, content, path4) { const embedMap = /* @__PURE__ */ new Map(); const embeds = await getEmbeds(content); for (const embedMatch of embeds) { const embedLink = embedMatch[1]; const rawContent = await getEmbedContentFromSource(plugin, embedLink, path4); if (rawContent !== null) { const embedValue = "> " + rawContent.replaceAll("# \n\n", "# ").replaceAll("\n", "\n> "); embedMap.set(embedLink, embedValue); } } return embedMap; } async function getBlockContent(plugin, filePath, blockId) { try { const file = plugin.app.vault.getAbstractFileByPath(filePath); if (!(file instanceof import_obsidian2.TFile)) { return null; } const content = await plugin.app.vault.cachedRead(file); const metadata = plugin.app.metadataCache.getFileCache(file); if (!metadata || !metadata.blocks) { return null; } const block = metadata.blocks[blockId]; if (!block) { return null; } const lines = content.split("\n"); const startLine = block.position.start.line; const endLine = block.position.end.line; if (startLine >= lines.length) { return null; } const blockLines = lines.slice(startLine, endLine + 1); let blockContent = blockLines.join("\n"); blockContent = blockContent.replace(/\s*\^([a-zA-Z0-9]+)\s*$/, ""); return blockContent; } catch (error) { console.error("Error getting block content:", error); return null; } } function parseEmbedLink(embedLink, currentPath) { const blockMatch = embedLink.match(/^(.*?)#?\^([a-zA-Z0-9]+)$/); if (blockMatch) { const [, filePart, blockId] = blockMatch; let filePath = filePart; if (filePart && filePart.trim()) { const currentDir = currentPath.substring(0, currentPath.lastIndexOf("/")); filePath = currentDir ? `${currentDir}/${filePart}` : filePart; if (!filePath.endsWith(".md")) { filePath += ".md"; } } else { filePath = currentPath; } return { filePath, blockId, heading: null }; } const headingMatch = embedLink.match(/^(.*?)#([^#]+)$/); if (headingMatch) { const [, filePart, heading] = headingMatch; let filePath = filePart || currentPath; if (filePart && filePart.trim()) { const currentDir = currentPath.substring(0, currentPath.lastIndexOf("/")); filePath = currentDir ? `${currentDir}/${filePart}` : filePart; if (!filePath.endsWith(".md")) { filePath += ".md"; } } return { filePath, blockId: null, heading }; } if (embedLink.trim()) { const currentDir = currentPath.substring(0, currentPath.lastIndexOf("/")); let filePath = currentDir ? `${currentDir}/${embedLink}` : embedLink; if (!filePath.endsWith(".md")) { filePath += ".md"; } return { filePath, blockId: null, heading: null }; } return { filePath: null, blockId: null, heading: null }; } function convertMarkdownToText(plugin, markdown) { let text = markdown; text = text.replace(/- \[ \]/g, plugin.settings.textExportCheckboxUnchecked); text = text.replace(/- \[x\]/g, plugin.settings.textExportCheckboxChecked); const lines = text.split("\n"); const processedLines = lines.map((line) => { var _a; const leadingWhitespace = ((_a = line.match(/^(\s*)/)) == null ? void 0 : _a[0]) || ""; if (line.trim().startsWith("- ")) { const trimmedLine = line.trim(); const normalizedIndent = leadingWhitespace.replace(/\t/g, " "); const indentationLevel = Math.floor(normalizedIndent.length / 4); let bulletPointSymbol = plugin.settings.textExportBulletPointMap[indentationLevel * 4]; if (!bulletPointSymbol) { switch (indentationLevel) { case 0: bulletPointSymbol = plugin.settings.textExportBulletPointMap[0] || "\u25CF"; break; case 1: bulletPointSymbol = plugin.settings.textExportBulletPointMap[4] || "\uFFEE"; break; case 2: bulletPointSymbol = plugin.settings.textExportBulletPointMap[8] || "\uFFED"; break; case 3: bulletPointSymbol = plugin.settings.textExportBulletPointMap[12] || "\u25BA"; break; case 4: bulletPointSymbol = plugin.settings.textExportBulletPointMap[16] || "\u2022"; break; default: { const levels = Object.keys(plugin.settings.textExportBulletPointMap).map(Number).sort((a, b) => a - b); if (levels.length > 0) { const deepestLevel = levels[levels.length - 1]; bulletPointSymbol = plugin.settings.textExportBulletPointMap[deepestLevel] || "\u2022"; } else { bulletPointSymbol = "\u2022"; } } } } return leadingWhitespace + bulletPointSymbol + " " + trimmedLine.slice(2); } return line; }); return processedLines.join("\n"); } async function tryCopyMarkdownByRead(plugin, { file, outputFormat, outputSubPath = "." }) { try { await plugin.app.vault.adapter.read(file.path).then(async (content) => { var _a; const imageLinks = await getImageLinks(content); const vaultName = plugin.app.vault.getName(); const fileNameWithoutExt = file.name.replace(/\.[^/.]+$/, ""); const resolvedAttachPath = resolvePathVariables(plugin.settings.attachment, fileNameWithoutExt, vaultName); const resolvedCustomAttachPath = plugin.settings.customAttachPath ? resolvePathVariables(plugin.settings.customAttachPath, fileNameWithoutExt, vaultName) : plugin.settings.customAttachPath; if (imageLinks.length > 0) { await tryCreateFolder(plugin, path2.join(plugin.settings.relAttachPath ? plugin.settings.output : resolvedAttachPath, plugin.settings.includeFileName ? file.name.replace(".md", "") : "", plugin.settings.relAttachPath ? resolvedAttachPath : "")); } for (const index in imageLinks) { const rawImageLink = imageLinks[index][0]; const urlEncodedImageLink = imageLinks[index][7 - imageLinks[index].length]; let imageLink = decodeURI(urlEncodedImageLink).replace(/\.\.\//g, ""); if (imageLink.contains("|")) { imageLink = imageLink.split("|")[0]; } const fileName = path2.parse(path2.basename(imageLink)).name; const imageLinkMd5 = plugin.settings.fileNameEncode ? (0, import_md5.default)(imageLink) : encodeURI(fileName); const imageExt = path2.extname(imageLink); const clickSubRoute = getClickSubRoute(outputSubPath); const baseAttachPath = plugin.settings.relAttachPath ? resolvedAttachPath : path2.join(resolvedCustomAttachPath ? resolvedCustomAttachPath : resolvedAttachPath, plugin.settings.includeFileName ? file.name.replace(".md", "") : ""); const hashLink = path2.join(clickSubRoute, baseAttachPath, imageLinkMd5.concat(imageExt)).replace(/\\/g, "/"); if (urlEncodedImageLink.startsWith("http")) { continue; } if (plugin.settings.displayImageAsHtml) { const { width = null, height = null } = ((_a = imageLinks[index]) == null ? void 0 : _a.groups) || {}; const formatSize = (value) => { if (!value) return ""; return value.includes("%") ? value : `${value}px`; }; const style = width && height ? ` style='width: ${formatSize(width)}; height: ${formatSize(height)};'` : width ? ` style='width: ${formatSize(width)};'` : height ? ` style='height: ${formatSize(height)};'` : ""; content = content.replace(rawImageLink, ``); } else if (plugin.settings.GFM) { content = content.replace(rawImageLink, GFM_IMAGE_FORMAT.format(hashLink)); } else { content = content.replace(urlEncodedImageLink, hashLink); } } if (plugin.settings.removeOutgoingLinkBrackets) { content = content.replaceAll(OUTGOING_LINK_REGEXP, "$1"); } const embedMap = await getEmbedMap(plugin, content, file.path); const embeds = await getEmbeds(content); for (const index in embeds) { const embedMatch = embeds[index]; const fullMatch = embedMatch[0]; const embedLink = embedMatch[1]; let replacement = embedMap.get(embedLink); if (replacement === void 0 && plugin.settings.inlineBlockEmbeds) { const parsed = parseEmbedLink(embedLink, file.path); if (parsed.blockId && parsed.filePath) { const blockContent = await getBlockContent(plugin, parsed.filePath, parsed.blockId); if (blockContent !== null) { replacement = "> " + blockContent.replace(/\n/g, "\n> "); } } } if (replacement !== void 0) { content = content.replace(fullMatch, replacement); } } if (plugin.settings.convertWikiLinksToMarkdown) { content = content.replace(/\[\[(.*?)\]\]/g, (match, linkText) => { const encodedLink = encodeURIComponent(linkText); return `[${linkText}](${encodedLink})`; }); } await tryCopyImage(plugin, file.name, file.path); const outDir = path2.join(plugin.settings.output, plugin.settings.customFileName != "" || plugin.settings.includeFileName && plugin.settings.relAttachPath ? file.name.replace(".md", "") : "", outputSubPath); await tryCreateFolder(plugin, outDir); switch (outputFormat) { case "HTML" /* HTML */: { let filename; if (plugin.settings.customFileName) { filename = plugin.settings.customFileName + ".md"; } else { filename = file.name; } const targetFile = path2.join(outDir, filename.replace(".md", ".html")); const { html } = await markdownToHTML(plugin, file.path, content); await tryCreate(plugin, targetFile, html); break; } case "Markdown" /* MD */: { let filename; if (plugin.settings.customFileName) { filename = plugin.settings.customFileName + ".md"; } else { filename = file.name; } const targetFile = path2.join(outDir, filename); await tryCreate(plugin, targetFile, content); break; } case "Text" /* TEXT */: { let filename; if (plugin.settings.customFileName) { filename = plugin.settings.customFileName + ".md"; } else { filename = file.name; } const targetFile = path2.join(outDir, filename.replace(".md", ".txt")); const textContent = convertMarkdownToText(plugin, content); await tryCreate(plugin, targetFile, textContent); break; } } }); } catch (error) { if (!error.message.contains("file already exists")) { throw error; } } } // src/main.ts var TagInputModal = class extends import_obsidian3.Modal { constructor(app2, onSubmit) { super(app2); this.onSubmit = onSubmit; } onOpen() { const { contentEl } = this; contentEl.createEl("h2", { text: "Export notes by tag" }); contentEl.createEl("p", { text: "Enter the tag to export (e.g. 'blog' or '#blog')" }); const inputContainer = contentEl.createDiv(); this.inputEl = inputContainer.createEl("input", { type: "text", placeholder: "blog" }); this.inputEl.style.width = "100%"; this.inputEl.style.padding = "8px"; this.inputEl.style.marginTop = "10px"; this.errorEl = contentEl.createEl("p", { text: "Please enter a tag", cls: "mod-warning" }); this.errorEl.style.marginTop = "10px"; this.errorEl.style.display = "none"; const buttonContainer = contentEl.createDiv({ cls: "modal-button-container" }); buttonContainer.style.marginTop = "20px"; buttonContainer.style.display = "flex"; buttonContainer.style.justifyContent = "flex-end"; buttonContainer.style.gap = "10px"; const cancelButton = buttonContainer.createEl("button", { text: "Cancel", cls: "mod-cancel" }); cancelButton.addEventListener("click", () => this.close()); const submitButton = buttonContainer.createEl("button", { text: "Export", cls: "mod-cta" }); submitButton.addEventListener("click", () => { const tag = this.inputEl.value.trim(); if (tag) { this.errorEl.style.display = "none"; this.onSubmit(tag); this.close(); } else { this.errorEl.style.display = "block"; } }); this.inputEl.addEventListener("keypress", (e) => { if (e.key === "Enter") { const tag = this.inputEl.value.trim(); if (tag) { this.errorEl.style.display = "none"; this.onSubmit(tag); this.close(); } else { this.errorEl.style.display = "block"; } } }); this.inputEl.addEventListener("input", () => { if (this.inputEl.value.trim()) { this.errorEl.style.display = "none"; } }); setTimeout(() => this.inputEl.focus(), 10); } onClose() { const { contentEl } = this; contentEl.empty(); } }; var MarkdownExportPlugin = class extends import_obsidian3.Plugin { async onload() { await this.loadSettings(); this.addSettingTab(new MarkdownExportSettingTab(this.app, this)); this.registerEvent(this.app.workspace.on("file-menu", (menu, file) => { this.registerDirMenu(menu, file); })); for (const outputFormat of [ "Markdown" /* MD */, "HTML" /* HTML */, "Text" /* TEXT */ ]) { this.addCommand({ id: "export-to-" + outputFormat, name: `Export to ${outputFormat}`, callback: async () => { const file = this.app.workspace.getActiveFile(); if (!file) { new import_obsidian3.Notice(`No active file`); return; } this.createFolderAndRun(file, outputFormat); } }); } for (const outputFormat of [ "Markdown" /* MD */, "HTML" /* HTML */, "Text" /* TEXT */ ]) { this.addCommand({ id: "export-by-tag-to-" + outputFormat, name: `Export notes by tag to ${outputFormat}`, callback: async () => { this.exportByTag(outputFormat); } }); } } async exportByTag(outputFormat) { new TagInputModal(this.app, async (tag) => { const trimmedTag = tag.trim(); const files = getFilesWithTag(this, trimmedTag); if (files.length === 0) { new import_obsidian3.Notice(`No files found with tag '${trimmedTag}'`); return; } new import_obsidian3.Notice(`Exporting ${files.length} file(s) with tag '${trimmedTag}' to ${outputFormat}...`); const result = await tryRunBatch(this, files, outputFormat); if (result.failed === 0) { new import_obsidian3.Notice(`Successfully exported ${result.success} file(s) with tag '${trimmedTag}' to ${outputFormat}`); } else { new import_obsidian3.Notice(`Exported ${result.success} file(s), ${result.failed} failed. Check console for details.`); for (const error of result.errors) { console.error(error); } } }).open(); } registerDirMenu(menu, file) { for (const outputFormat of [ "Markdown" /* MD */, "HTML" /* HTML */, "Text" /* TEXT */ ]) { const addMenuItem = (item) => { item.setTitle(`Export to ${outputFormat}`); item.onClick(async () => { await this.createFolderAndRun(file, outputFormat); }); }; menu.addItem(addMenuItem); } } async createFolderAndRun(file, outputFormat) { await tryRun(this, file, outputFormat); if (file instanceof import_obsidian3.TFolder) { new import_obsidian3.Notice(`Exporting folder ${file.path} to ${path3.join(this.settings.output)}`); } else { new import_obsidian3.Notice(`Exporting ${file.path} to ${path3.join(this.settings.output, this.settings.includeFileName ? file.name.replace(".md", "") : "", file.name)}`); } } onunload() { } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); } }; var MarkdownExportSettingTab = class extends import_obsidian3.PluginSettingTab { constructor(app2, plugin) { super(app2, plugin); this.plugin = plugin; } display() { const { containerEl } = this; containerEl.empty(); containerEl.createEl("h1", { text: "Obsidian Markdown Export" }); containerEl.createEl("p", { text: "Created by " }).createEl("a", { text: "bingryan \u{1F913}", href: "https://github.com/bingryan" }); containerEl.createEl("h3", { text: "Baisc Setting" }); new import_obsidian3.Setting(containerEl).setName("Output Path").setDesc("default directory for one-click export").addText((text) => text.setPlaceholder("Enter default output path").setValue(this.plugin.settings.output).onChange(async (value) => { this.plugin.settings.output = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Attachment Path (optional)").setDesc("attachment path, relative to the output path. Supports variables: {{fileName}}, {{date}}, {{time}}, {{datetime}}, {{timestamp}}, {{year}}, {{month}}, {{day}}, {{hour}}, {{minute}}, {{second}}, {{vaultName}}. Example: 'images/{{date}}' becomes 'images/2024-12-06'").addText((text) => text.setPlaceholder("Enter attachment path").setValue(this.plugin.settings.attachment).onChange(async (value) => { this.plugin.settings.attachment = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Custom Attachment Path").setDesc("Changes an images path in an exported file, rather than use the attachment path. Only applies to unrelative attachments. Useful if your using a static site generator.").addText((text) => text.setPlaceholder("Enter attachment path").setValue(this.plugin.settings.customAttachPath).onChange(async (value) => { this.plugin.settings.customAttachPath = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Use GitHub Flavored Markdown Format").setDesc("The format of markdown is more inclined to choose Github Flavored Markdown").addToggle((toggle) => toggle.setValue(this.plugin.settings.GFM).onChange(async (value) => { this.plugin.settings.GFM = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Use Html tag to display image").setDesc("false default, tag will use the size specified in obsidian.").addToggle((toggle) => toggle.setValue(this.plugin.settings.displayImageAsHtml).onChange(async (value) => { this.plugin.settings.displayImageAsHtml = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Encode file name").setDesc("true default, if you want to keep the original file name, set this to false").addToggle((toggle) => toggle.setValue(this.plugin.settings.fileNameEncode).onChange(async (value) => { this.plugin.settings.fileNameEncode = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Remove brackets for outgoing links").setDesc("false default, if you want to remove the brackets in links, set this to true").addToggle((toggle) => toggle.setValue(this.plugin.settings.removeOutgoingLinkBrackets).onChange(async (value) => { this.plugin.settings.removeOutgoingLinkBrackets = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Create Subdirectory").setDesc("Determines when a subdirectory with the exported file's name gets created").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeFileName).onChange(async (value) => { this.plugin.settings.includeFileName = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Custom Filename").setDesc("update if you want a custom filename, leave off extension").addText((text) => text.setPlaceholder("index").setValue(this.plugin.settings.customFileName).onChange(async (value) => { this.plugin.settings.customFileName = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Set Attachment Path as Relative").setDesc("If enabled, the attachment path will be relative to the output.").addToggle((toggle) => toggle.setValue(this.plugin.settings.relAttachPath).onChange(async (value) => { this.plugin.settings.relAttachPath = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Convert WikiLinks to Markdown").setDesc("Automatically convert WikiLink style links to Markdown links").addToggle((toggle) => toggle.setValue(this.plugin.settings.convertWikiLinksToMarkdown).onChange(async (value) => { this.plugin.settings.convertWikiLinksToMarkdown = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Inline Block Embeds").setDesc("If enabled, block embeds like ![[#^blockid]] will be replaced with the actual block content. If disabled, block embeds will be preserved as-is (may not work in exported markdown).").addToggle((toggle) => toggle.setValue(this.plugin.settings.inlineBlockEmbeds).onChange(async (value) => { this.plugin.settings.inlineBlockEmbeds = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Remove YAML Metadata Header").setDesc("If enabled, the YAML metadata header will be removed from embedded files when exporting.").addToggle((toggle) => toggle.setValue(this.plugin.settings.removeYamlHeader).onChange(async (value) => { this.plugin.settings.removeYamlHeader = value; await this.plugin.saveSettings(); })); containerEl.createEl("h3", { text: "Export Text Setting" }); containerEl.createEl("h6", { text: "Bullet Point Symbols" }); containerEl.createEl("p", { text: "Configure symbols for different indentation levels of bullet points." }); new import_obsidian3.Setting(containerEl).setName("Level 0 Bullet Point").setDesc("Symbol for top-level bullet points").addText((text) => text.setPlaceholder("\u25CF").setValue(this.plugin.settings.textExportBulletPointMap[0] || "\u25CF").onChange(async (value) => { this.plugin.settings.textExportBulletPointMap[0] = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Level 1 Bullet Point").setDesc("Symbol for first-level indented bullet points (4 spaces)").addText((text) => text.setPlaceholder("\uFFEE").setValue(this.plugin.settings.textExportBulletPointMap[4] || "\uFFEE").onChange(async (value) => { this.plugin.settings.textExportBulletPointMap[4] = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Level 2 Bullet Point").setDesc("Symbol for second-level indented bullet points (8 spaces)").addText((text) => text.setPlaceholder("\uFFED").setValue(this.plugin.settings.textExportBulletPointMap[8] || "\uFFED").onChange(async (value) => { this.plugin.settings.textExportBulletPointMap[8] = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Level 3 Bullet Point").setDesc("Symbol for third-level indented bullet points (12 spaces)").addText((text) => text.setPlaceholder("\u25BA").setValue(this.plugin.settings.textExportBulletPointMap[12] || "\u25BA").onChange(async (value) => { this.plugin.settings.textExportBulletPointMap[12] = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Level 4 Bullet Point").setDesc("Symbol for fourth-level indented bullet points (16 spaces)").addText((text) => text.setPlaceholder("\u2022").setValue(this.plugin.settings.textExportBulletPointMap[16] || "\u2022").onChange(async (value) => { this.plugin.settings.textExportBulletPointMap[16] = value; await this.plugin.saveSettings(); })); containerEl.createEl("h6", { text: "Checkbox Symbols" }); containerEl.createEl("p", { text: "Configure symbols for checkboxes." }); new import_obsidian3.Setting(containerEl).setName("Unchecked Checkbox").setDesc("Symbol for unchecked checkboxes").addText((text) => text.setPlaceholder("\u2610").setValue(this.plugin.settings.textExportCheckboxUnchecked || "\u2610").onChange(async (value) => { this.plugin.settings.textExportCheckboxUnchecked = value; await this.plugin.saveSettings(); })); new import_obsidian3.Setting(containerEl).setName("Checked Checkbox").setDesc("Symbol for checked checkboxes").addText((text) => text.setPlaceholder("\u2611").setValue(this.plugin.settings.textExportCheckboxChecked || "\u2611").onChange(async (value) => { this.plugin.settings.textExportCheckboxChecked = value; await this.plugin.saveSettings(); })); } }; /*! * Determine if an object is a Buffer * * @author Feross Aboukhadijeh * @license MIT */ /* nosourcemap */