/* 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 __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( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // main.ts var main_exports = {}; __export(main_exports, { C2DSettingTab: () => C2DSettingTab, default: () => Canvas2DocumentPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian = require("obsidian"); var path = __toESM(require("path")); var DEFAULT_SETTINGS = { usefrontmatter: true, useedgelabels: true }; var C2DSettingTab = class extends import_obsidian.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } display() { let { containerEl } = this; containerEl.empty(); new import_obsidian.Setting(containerEl).setName("Include YAML frontmatter from embedded documents").setDesc("Makes metadata from embedded documents usable in target document").addToggle( (toggle) => toggle.setValue(this.plugin.settings.usefrontmatter).onChange(async (value) => { this.plugin.settings.usefrontmatter = value; await this.plugin.saveSettings(); }) ); new import_obsidian.Setting(containerEl).setName("Include labels of canvas elements").setDesc("Makes connections descriptions usable in target document").addToggle( (toggle) => toggle.setValue(this.plugin.settings.useedgelabels).onChange(async (value) => { this.plugin.settings.useedgelabels = value; await this.plugin.saveSettings(); }) ); } }; var Canvas2DocumentPlugin = class extends import_obsidian.Plugin { async onload() { await this.loadSettings(); this.addSettingTab(new C2DSettingTab(this.app, this)); if (this.app.vault.adapter instanceof import_obsidian.FileSystemAdapter) { this.fsadapter = this.app.vault.adapter; } else { return; } this.addCommand({ id: "run-conversion", name: "Step 1 - Convert canvas to a longform document", callback: async () => { const canvStruct = await this.readCanvasStruct(); if (canvStruct == false) { new import_obsidian.Notice(`this is not a canvas file`); return; } let [contents, myparsed_data] = await this.readCanvasData(canvStruct); const result = await this.writeCanvDocFile(contents, canvStruct, myparsed_data); } }); this.addCommand({ id: "run-redoc", name: "Step 2 - Clear canvas2document target document", callback: async () => { const canvStruct = await this.readC2Dtarget(); if (canvStruct == false) { new import_obsidian.Notice(`this is not a canvas2document target file`); return; } this.writeC2Doc(canvStruct); } }); this.addRibbonIcon("image-down", "C2D Step 1 - Convert Canvas to draft doc", () => { this.app.commands.executeCommandById("canvas2document:run-conversion"); }); this.addRibbonIcon("file-input", "C2D Step 2 - Make cleared document", () => { this.app.commands.executeCommandById("canvas2document:run-redoc"); }); } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); } onunload() { } async readC2Dtarget() { let activeFile = this.app.workspace.getActiveFile(); if (!activeFile || !activeFile.name.includes("_fromCanvas.md")) { return false; } else { let mdFolderPath = path.dirname(activeFile.path); } let content = this.app.vault.cachedRead(activeFile); return content; } async writeC2Doc(canvStruct) { let activeFile = this.app.workspace.getActiveFile(); let mdFolderPath = path.dirname(activeFile.path); const regex = /\!\[\[([^[\]]+)\]\]|]*src="(.*?)"/g; const matches = []; let match; while ((match = regex.exec(canvStruct)) !== null) { if (match[1]) { matches.push(match[1]); } else if (match[2]) { matches.push(match[2]); } } const edgelabelpattern = /(.*?)<\/edgelabel>/g; const matchesedgelabel = []; let matchel; while ((matchel = edgelabelpattern.exec(canvStruct)) !== null) { matchesedgelabel.push({ data: matchel[1], // Captured `data` attribute (optional) content: matchel[2] // Captured inner content }); } let doccontentstring = "> [!success] This is your converted and cleared document from Canvas2Document\n> (you can delete this infobox)\n\n"; if (!matches) { return; } let textfilenames = []; let filenames = []; matches.forEach((match2) => { let embeddedfilename = match2.replace(/\!\[\[(.*)\]\]/, "$1"); if (embeddedfilename.endsWith(".md")) { if (embeddedfilename.startsWith("./")) { embeddedfilename = embeddedfilename.replace("./", ""); } textfilenames.push(embeddedfilename); } filenames.push(embeddedfilename); }); const fileContents = await Promise.all( textfilenames.map( async (file) => [file, await this.app.vault.cachedRead(this.app.vault.getAbstractFileByPath(file))] ) ); for (const xfile of filenames) { if (this.settings.useedgelabels) { matchesedgelabel.forEach((label) => { if (xfile === label.data) { doccontentstring += '> [!info] (edge label in canvas for the following entry:) "' + label.content + '"\n\n'; } }); } if (xfile.endsWith(".md")) { const found = fileContents.find((element) => element[0] == xfile); const { dir, name, ext } = path.parse(xfile); if (!dir.endsWith("_canvas2doc-data")) { doccontentstring += "# " + name + "\n\n"; } const frontMatterInfo = (0, import_obsidian.getFrontMatterInfo)(found[1]); let textfilestring = ""; if (this.settings.usefrontmatter && frontMatterInfo.exists) { textfilestring = found[1].substring(frontMatterInfo.contentStart); } else { textfilestring = found[1]; } doccontentstring += textfilestring + "\n\n"; } else if (xfile.startsWith("http")) { doccontentstring += '\n\n'; } else { doccontentstring += "![[" + xfile + "]]\n\n"; } } let docFilename; if (mdFolderPath == ".") { docFilename = activeFile.basename + "_fromC2D.md"; } else { docFilename = mdFolderPath + "/" + activeFile.basename + "_fromC2D.md"; } try { const exists = await this.fsadapter.exists(docFilename); if (exists) { const confirmed = await new Promise((resolve) => { const notice = new import_obsidian.Notice("File " + docFilename + " already exists. Overwrite?", 0); notice.noticeEl.createEl("button", { text: "Yes" }).onclick = () => { notice.hide(); resolve(true); }; notice.noticeEl.createEl("button", { text: "No" }).onclick = () => { notice.hide(); resolve(false); }; }); if (!confirmed) { return false; } } await this.fsadapter.write(docFilename, doccontentstring); } catch (e) { console.log("error writing the new cleared doc file " + e); } const docftab = await this.app.vault.getAbstractFileByPath(docFilename); try { await this.app.workspace.getLeaf("split").openFile(docftab); } catch (e) { console.log(e); } return; } async readCanvasStruct() { let activeFile = this.app.workspace.getActiveFile(); if (!activeFile || activeFile.extension != "canvas") { return false; } else { let mdFolderPath = path.dirname(activeFile.path); } let content = this.app.vault.cachedRead(activeFile); return content; } async findAllXChildren(startGeneration, myparsed_data, fileContents, handledNodes, limitrecurseNodes, runcounterfunc, runcounterforeach) { runcounterfunc++; if (runcounterfunc > 30) { return false; } for (const child of startGeneration) { runcounterforeach++; if (runcounterforeach > myparsed_data.edges2.length) { return false; } const nodeentry = myparsed_data.nodes.find((entry) => entry.id === child); if (!handledNodes.has(child)) { const result = await this.formatNode(nodeentry, 6); fileContents.push(result); handledNodes.add(child); } else { limitrecurseNodes++; if (limitrecurseNodes > 30) { return false; } } let children = myparsed_data.edges2.filter((edge) => edge.fromNode === child).map((edge) => edge.toNode); if (children.length > 0) { const continueRecursion = await this.findAllXChildren(children, myparsed_data, fileContents, handledNodes, limitrecurseNodes, runcounterfunc, runcounterforeach); if (!continueRecursion) return false; } } ; limitrecurseNodes++; return limitrecurseNodes <= 30; } async traverseNodes(initialNodes, myparsed_data, fileContents, handledNodes) { for (const node of initialNodes) { const nodeentry = myparsed_data.nodes.find((entry) => entry.id === node); if (!handledNodes.has(node)) { const result = await this.formatNode(nodeentry, 1); fileContents.push(result); } handledNodes.add(node); const children1 = myparsed_data.edges2.filter((edge) => edge.fromNode === node).map((edge) => edge.toNode); for (const child1 of children1) { const nodeentry2 = myparsed_data.nodes.find((entry) => entry.id === child1); if (!handledNodes.has(child1)) { const result = await this.formatNode(nodeentry2, 2); fileContents.push(result); } handledNodes.add(child1); const children2 = myparsed_data.edges2.filter((edge) => edge.fromNode === child1).map((edge) => edge.toNode); for (const child2 of children2) { const nodeentry3 = myparsed_data.nodes.find((entry) => entry.id === child2); if (!handledNodes.has(child2)) { const result = await this.formatNode(nodeentry3, 3); fileContents.push(result); } handledNodes.add(child2); const children3 = myparsed_data.edges2.filter((edge) => edge.fromNode === child2).map((edge) => edge.toNode); for (const child3 of children3) { const nodeentry4 = myparsed_data.nodes.find((entry) => entry.id === child3); if (!handledNodes.has(child3)) { const result = await this.formatNode(nodeentry4, 4); fileContents.push(result); } handledNodes.add(child3); const children4 = myparsed_data.edges2.filter((edge) => edge.fromNode === child3).map((edge) => edge.toNode); for (const child4 of children4) { const nodeentry5 = myparsed_data.nodes.find((entry) => entry.id === child4); if (!handledNodes.has(child4)) { const result = await this.formatNode(nodeentry5, 5); fileContents.push(result); } handledNodes.add(child4); const children5 = myparsed_data.edges2.filter((edge) => edge.fromNode === child4).map((edge) => edge.toNode); for (const child5 of children5) { const nodeentry6 = myparsed_data.nodes.find((entry) => entry.id === child5); if (!handledNodes.has(child5)) { const result2 = await this.formatNode(nodeentry6, 6); fileContents.push(result2); } handledNodes.add(child5); const children6 = myparsed_data.edges2.filter((edge) => edge.fromNode === child5).map((edge) => edge.toNode); let runcounterfunc = 0; let runcounterforeach = 0; let limitrecurseNodes = 0; const result = await this.findAllXChildren(children6, myparsed_data, fileContents, handledNodes, limitrecurseNodes, runcounterfunc, runcounterforeach); } } } } } } } async readCanvasData(struct) { const fileContents = []; let myparsed_data = JSON.parse(struct); const singleNodeIDs = /* @__PURE__ */ new Set(); const groupNodes = /* @__PURE__ */ new Set(); myparsed_data.nodes.forEach((node) => { if (node.type === "group") { groupNodes.add(node.id); } else { singleNodeIDs.add(node.id); } }); const fromNodes = /* @__PURE__ */ new Set(); const toNodes = /* @__PURE__ */ new Set(); let groupClearedEdges = []; let resa = await myparsed_data.edges.forEach((edge) => { if (groupNodes.has(edge.fromNode) || groupNodes.has(edge.toNode)) { } else { fromNodes.add(edge.fromNode); toNodes.add(edge.toNode); groupClearedEdges.push(edge); } }); myparsed_data.edges2 = groupClearedEdges; let handledNodes = /* @__PURE__ */ new Set(); const skiphandledNodes = true; let nodesWithoutParents = [...singleNodeIDs].filter((node) => !toNodes.has(node)); if (nodesWithoutParents.length === 0) { nodesWithoutParents = [...singleNodeIDs]; } const traverseresult = await this.traverseNodes(nodesWithoutParents, myparsed_data, fileContents, handledNodes); const diff = new Set([...singleNodeIDs].filter((x) => !handledNodes.has(x))); if (diff.size > 0) { const traverseresult2 = await this.traverseNodes(diff, myparsed_data, fileContents, handledNodes); } return [fileContents, myparsed_data]; } async formatNode(node, level) { const id = node.id; const type = node.type; let nodefile = ""; if (type === "file") { nodefile = node.file; const { name, ext } = path.parse(nodefile); if (ext === ".md") { return [id, type, nodefile, level, "textfile", name]; } else if (ext === ".canvas") { return [id, type, nodefile, level, "embeddedcanvas", name]; } else if (ext === ".jpg" || ext == ".jpeg" || ext === ".png" || ext === ".gif") { return [id, type, nodefile, level, "contentimage", name + "." + ext]; } else if (ext === ".mp3" || ext === ".wav" || ext === ".ogg") { return [id, type, nodefile, level, "contentaudio", name + "." + ext]; } else if (ext === ".mp4" || ext === ".webm") { return [id, type, nodefile, level, "contentvideo", name + "." + ext]; } else if (ext === ".pdf") { return [id, type, nodefile, level, "contentpdf", name + "." + ext]; } else { return [id, type, nodefile, level, "xfile", name + "." + ext]; } } else if (type === "link") { if (node.url.includes("youtube")) { const url = node.url; return [id, type, url, level, "contentyoutube", node.url]; } else { return [id, type, node.url, level, "contentlink", node.url]; } } else if (type === "text") { const text = node.text; const textPreview = text.substring(0, 100); return [id, type, "node", level, text, textPreview]; } } async writeCanvDocFile(content, convStruct, myparsed_data) { let activeFile = this.app.workspace.getActiveFile(); let mdFolderPath = path.dirname(activeFile.path); let writeworkdir = mdFolderPath + "/" + activeFile.basename + "_canvas2doc-data"; this.fsadapter.mkdir(writeworkdir); let canvasFile; let canvasFilename; if (mdFolderPath == ".") { canvasFilename = activeFile.basename + "_fromCanvas.md"; } else { canvasFilename = mdFolderPath + "/" + activeFile.basename + "_fromCanvas.md"; } let contentString = "> [!info] This is an automatically generated document from Plugin [Canvas2Document](https://github.com/slnsys/obsidian-canvas2document)\n> arrange the document as you need with the outline, then call *Clear canvas2document target document*\n\n"; for (const element of content) { let cnfname = ""; let heading = ""; for (let i = 0; i < element[3]; i++) { heading += "#"; } if (element[1] == "text") { cnfname = writeworkdir + "/newdoc-node_" + element[0] + "_fromCanvas.md"; contentString += "\n\n" + heading + " _card " + element[5] + "\n"; contentString += element[2] + " ^" + element[0] + "\n\n"; contentString += "> [!tip] link navigation from the canvas\n"; for (const edge of myparsed_data.edges2) { if (edge.fromNode == element[0]) { const found = content.find((element2) => element2[0] == edge.toNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); contentString += "> linking to: [[#^" + edge.toNode + "|" + found5 + "]]\n"; } if (edge.toNode == element[0]) { const found = content.find((element2) => element2[0] == edge.fromNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); if (edge.label != void 0) { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + ']] ("' + edge.label + '")\n'; } else { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + "]]\n"; } } } contentString += "\n ![[" + cnfname + "]]\n\n"; let canvasnodeFile; try { let cnfabst2 = this.app.vault.getAbstractFileByPath(cnfname); await this.fsadapter.write(cnfname, element[4]); } catch (e) { console.log(e); return; } } else if (element[1] == "link") { contentString += "\n\n" + heading + " _link " + element[5] + "\n"; contentString += element[2] + " ^" + element[0] + "\n\n"; contentString += "> [!tip] link navigation from the canvas\n"; for (const edge of myparsed_data.edges2) { if (edge.fromNode == element[0]) { const found = content.find((element2) => element2[0] == edge.toNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); contentString += "> linking to: [[#^" + edge.toNode + "|" + found5 + "]]\n"; } if (edge.toNode == element[0]) { const found = content.find((element2) => element2[0] == edge.fromNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); if (edge.label != void 0) { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + ']] ("' + edge.label + '")\n'; } else { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + "]]\n"; } } } if (element[4] == "contentyoutube") { contentString += "\n ![](" + element[2] + ")\n\n"; } else if (element[4] == "contentlink") { contentString += '\n \n\n'; } } else if (element[1] == "file") { if (element[4] == "contentimage" || element[4] == "contentpdf") { contentString += "\n\n" + heading + " _Media " + element[5] + "\n"; contentString += element[2] + " ^" + element[0] + "\n\n"; contentString += "> [!tip] link navigation from the canvas\n"; for (const edge of myparsed_data.edges2) { if (edge.fromNode == element[0]) { const found = content.find((element2) => element2[0] == edge.toNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); contentString += "> linking to: [[#^" + edge.toNode + "|" + found5 + "]]\n"; } if (edge.toNode == element[0]) { const found = content.find((element2) => element2[0] == edge.fromNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); if (edge.label != void 0) { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + ']] ("' + edge.label + '")\n'; } else { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + "]]\n"; } } } if (element[4] == "contentpdf") { contentString += "\n ![[" + element[2] + "]]\n\n"; } else if (element[4] == "contentimage") { contentString += "\n ![[" + element[2] + "]]\n\n"; } } else { contentString += "\n\n" + heading + " _noteFile " + element[5] + "\n"; contentString += element[2] + " ^" + element[0] + "\n\n"; contentString += "> [!tip] link navigation from the canvas\n"; for (const edge of myparsed_data.edges2) { if (edge.fromNode == element[0]) { const found = content.find((element2) => element2[0] == edge.toNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); contentString += "> linking to: [[#^" + edge.toNode + "|" + found5 + "]]\n"; } if (edge.toNode == element[0]) { const found = content.find((element2) => element2[0] == edge.fromNode); const firstline = found[5].split("\n")[0]; const found5 = firstline.replace(/#/g, ""); if (edge.label != void 0) { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + ']] ("' + edge.label + '")\n'; } else { contentString += "> linked from: [[#^" + edge.fromNode + "|" + found5 + "]]\n"; } } } contentString += "\n ![[" + element[2] + "]]\n\n"; } } } try { const exists = await this.fsadapter.exists(canvasFilename); if (exists) { const confirmed = await new Promise((resolve) => { const notice = new import_obsidian.Notice("File " + canvasFilename + " already exists. Overwrite?", 0); notice.noticeEl.createEl("button", { text: "Yes" }).onclick = () => { notice.hide(); resolve(true); }; notice.noticeEl.createEl("button", { text: "No" }).onclick = () => { notice.hide(); resolve(false); }; }); if (!confirmed) { return false; } } await this.fsadapter.write(canvasFilename, contentString); } catch (e) { console.log("error writing the new doc file " + e); } const cnfabst = await this.app.vault.getAbstractFileByPath(canvasFilename); try { await this.app.workspace.getLeaf("split").openFile(cnfabst); } catch (e) { console.log(e); } return true; } }; /* nosourcemap */