1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
| #!/usr/bin/env node
const path = require('path'); const fs = require('fs').promises;
async function readNotable(notableDir, results = new Map()) { let files = await fs.readdir(notableDir, { withFileTypes : true } ); for (let f of files) { let fullPath = path.join(notableDir, f.name); if (f.isDirectory()) { await readNotable(fullPath, results); } else { console.info(`* Caching ${fullPath}...`);
const data = await fs.readFile(fullPath, 'utf-8' );
const metaRe = /---((?:.|[\r\n])*)---/g;
let title; let tags = []; let match = metaRe.exec(data); if (match) { const metadata = match[1];
const titleRe = /title: ([^\n]+)/; match = metadata.match(titleRe); title = match && match[1];
const tagsRe = /tags: \[([^\]]+)\]\n/; match = metadata.match(tagsRe); if (match) { tags = match[1].split(',').map(s => s.trim()); } }
const entry = { fullPath, data, title, tags, };
results.set(title, entry); } } return results; }
async function migrateTo(entriesCache, notableDir, obsidianVaultDir) { for (const [title, entry] of entriesCache) { const vaultRelPath = entry.fullPath.replace(notableDir, ''); let vaultFullPath = path.dirname(path.join(obsidianVaultDir, vaultRelPath)); vaultFullPath = path.join(vaultFullPath, `${path.basename(entry.fullPath)}`);
console.info(`* Processing "${title}" @ ${entry.fullPath} -> ${vaultFullPath}...`);
const noteRe = /\[([\w\s]+)\]\(@note\/([\w\s\/\-_\+\.\:]+)\.md\)/g; let newData = entry.data; let match; while ((match = noteRe.exec(entry.data))) { const base = path.dirname(vaultRelPath).substr(1); let newLink = path.join(base, path.basename(match[2], '.md')); const linkTitle = match[1] === newLink ? '' : `\\|${match[1]}`; newLink = `[[${newLink}${linkTitle}]]`; console.log(` > Internal link: -> ${newLink}`); newData = newData.replace(match[0], newLink); console.log(match[0]) }
await fs.mkdir(path.dirname(vaultFullPath), { recursive: true } ); await fs.writeFile(vaultFullPath, newData, { encoding : 'utf-8'} ); } }
async function validDirectories(paths) { for (const path of paths) { if (!path) { return false; }
const stats = await fs.stat(path); if (!stats.isDirectory()) { return false; } }
return true; }
async function main() { const notableDir = process.argv[2]; const obsidianVaultDir = process.argv[3];
const validDirs = await validDirectories([notableDir, obsidianVaultDir]); if (!validDirs) { return console.error('Usage: notable_to_obsidian.js <notableDir> <vaultDir>'); }
const entriesCache = await readNotable(process.argv[2]) await migrateTo(entriesCache, notableDir, obsidianVaultDir);
return 0; }
main().then().catch(console.error);
|