diff --git a/README.md b/README.md index 428d60ac..6f9d2db1 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,9 @@ As soon as you push code to your Obsidian repository, it will trigget an action ## Status and known issues: - [x] Transform Obsidian project in Gitbook project (naming and structure) - [x] Generate a valid SUMMARY.md +- [x] Remove git related files and folders - [ ] Transform page links to plain markdown links (next-up) +- [ ] Replace tildes and ñ instead of removing them (next-up) - [ ] Show all the pages linking to the current one (on the roadmap) - [ ] Link to blocks (on the roadmap) diff --git a/src/gitbook.js b/src/gitbook.js index 70ae0528..8dc0f0b8 100644 --- a/src/gitbook.js +++ b/src/gitbook.js @@ -2,20 +2,11 @@ const copyProject = require('./gitbook/copy'); const indexProject = require('./gitbook/index-project'); const renameProject = require('./gitbook/rename'); const summarize = require('./gitbook/summary'); -// const obsidianToMD = require('./gitbook/obsidian'); + +const parseLinks = require('./obsidian-md/parse-links'); /* Load settings (if exist) */ -let settings = { - obsidianProject: '../obsidian', - gitbookProject: '../gitbook', -}; - -try { - settings = require('../settings.json'); - console.log('Settings loaded from settings.json'); -} catch { - console.log('Settings not found. Using default settings'); -} +const settings = require('./settings.js'); /** @@ -35,6 +26,8 @@ async function main() { const index = await indexProject(settings.gitbookProject); // console.log(index) + /* ToDo: Remove unneccessary files and folders (.gitignore, .gitatributes, .git...) */ + /* Rename the files and folders */ const renamed = await renameProject(settings.gitbookProject, index); if (!renamed) { @@ -56,6 +49,9 @@ async function main() { /* Convert the Obsidian syntax to markdown */ // obsidianToMd(index); + /* Parse page links */ + const pageIndex = parseLinks(settings.gitbookProject, index); + return true } diff --git a/src/gitbook/copy.js b/src/gitbook/copy.js index 81390cb5..4e097b0e 100644 --- a/src/gitbook/copy.js +++ b/src/gitbook/copy.js @@ -16,6 +16,25 @@ async function copyProject(obsidian, gitbook) { await fse.remove(`${gitbook}/.obsidian`); console.log('> Removed Obsidian files'); + // Remove Git files + const gitPaths = [ + '.git', + '.gitignore', + '.gitattributes', + '.github', + ]; + + for (var i = 0; i < gitPaths.length; i++) { + const path = gitPaths[i]; + + const fullPath = `${gitbook}/${path}`; + const exists = await fse.pathExists(fullPath); + if (exists) { + await fse.remove(fullPath); + } + } + console.log('> Removed Git-related files'); + return true; } catch (e) { console.error('> Error copying Obsidian project to GitBook folder'); diff --git a/src/obsidian-md/parse-links.js b/src/obsidian-md/parse-links.js new file mode 100644 index 00000000..8898c0e1 --- /dev/null +++ b/src/obsidian-md/parse-links.js @@ -0,0 +1,192 @@ +const fs = require('fs'); +const fse = require('fs-extra'); + +const indexProject = require('../gitbook/index-project'); + +// Page links map +const pageLinks = {}; + +/** + * Get page name from original filename + * + * @param filename {String} Filename to turn into page name + * @return {String} Page name (without stuff like extensions) + */ +function pageName(filename) { + return filename.replace('.md', ''); +} + +/** + * Search for page link in node index + * + * @param page {String} Page name to find link + * @param index {Object} Project index to find into + * @return {String} Path to the page + */ +function findPageLink(page, index) { + const nodes = Object.keys(index); + + // ToDo: Is there a / in page name? + + for (let i = 0; i < nodes.length; i += 1) { + const node = index[nodes[i]]; + + // Deep search in folders + if (typeof node.content !== 'undefined') { + const found = findPageLink(page, node.content); + + if (found) { + return `${nodes[i]}/${found}`; + } + } + + // Check page name + if (pageName(node.name) === page) { + return nodes[i]; + } + } + + return false; +} + +/** + * Get a page link + * + * @param page {String} Page name to find link + * @param index {Object} Project index to find into + * @return {String} Path to the page + */ +function pageLink(page, index) { + if (pageLinks[page]) { + return pageLinks[page]; + } + + const link = findPageLink(page, index); + pageLinks[page] = link; + + return link; +} + +/** + * Parse page links in a file + */ +async function parsePageLinks(filename, index) { + try { + // If is not a markdown file, jump to the next file + if (filename.indexOf('.md') === -1) { + // console.log('File is not markdown. Skipping.'); + return false; + } + + // If file dont exist, jump to the next file + const exists = await fse.pathExists(filename); + if (!exists) { + return false; + } + + // Get page content + let pageText = fs.readFileSync(filename, 'utf8'); + + // If not content, jump. It might be an empty page. + + // Regex: Find "[[ SOMETHING ]]" (without quotes) + const pageLinkRegex = /(\[\[)(\s*\b)([^\[\]]*)(\b\s*)(\]\])/g; + const links = pageText.match(pageLinkRegex); + const uniqueLinks = [...new Set(links)]; + + // If links, replace them... + for (let i = 0; i < uniqueLinks.length; i += 1) { + const pageName = uniqueLinks[i].replace('[[', '').replace(']]', ''); + const pageLinkPath = pageLink(pageName, index); + + // ToDo: If not link found, act in consequence + if (!pageLinkPath) { + console.warn(`[warn] Unable to find link for ${pageName}`); + break; + } + + // In GitBook, relative links to the book are preceded by ../ + /* + ToDo: + In nested folders, internal links are not working. + It might be related to the ../ at the begining. + Maybe trying to use as may ../ as levels are in the path? + -> (check src/gitbook/summary.md). + */ + + // ToDo: Make this dynamic based on the orifinal fonder parsed + const originDepth = '../gitbook/'.split('/').length; + const depth = filename.split('/').length - originDepth; + + // Initial depth of '0' + let pageDepth = './'; + + if (depth > 0) { + // Reset page depth + pageDepth = ''; + + // And add the nested levels required + for (let j = 0; j < depth; j += 1) { + pageDepth += '../'; + } + } + + const gitbookLink = `[${pageName}](${pageDepth}${pageLinkPath})` + // console.log(filename, pageDepth, pageLinkPath); + console.log(filename, depth, pageDepth); + + // Unable to use .replace() with RegEx because of [] chars + pageText = pageText.split(uniqueLinks[i]).join(gitbookLink); + } + + // ...And store the new file + fs.writeFileSync(filename, pageText); + + } catch (err) { + console.error(err) + } +} + +/** + * Parse links in all pages for a given index + * + * @param index {Object} Project index to find into + */ +async function parseLinks(folder, index, rootIndex) { + let newIndex = { ...index }; + let originalIndex = { ...rootIndex } + + if (!index) { + newIndex = indexProject(folder); + } + if (!rootIndex) { + originalIndex = newIndex; + } + + try { + const nodes = Object.keys(newIndex); + + for (let i = 0; i < nodes.length; i += 1) { + const node = newIndex[nodes[i]]; + + // If is folder, go recursive + if (typeof node.content !== 'undefined') { + await parseLinks(`${folder}/${nodes[i]}`, node.content, originalIndex); + } + + // Parse page links + // console.log(`~~> ${folder}/${nodes[i]}`) + await parsePageLinks(`${folder}/${nodes[i]}`, originalIndex); + } + + // console.log('> First level page links created!'); + + return pageLinks; + } catch (e) { + console.error('Error: Unable to rewrite Obsidian page links'); + console.error(e); + return null; + } +} + +module.exports = parseLinks; diff --git a/src/settings.js b/src/settings.js new file mode 100644 index 00000000..fe298eda --- /dev/null +++ b/src/settings.js @@ -0,0 +1,19 @@ +let settings = { + obsidianProject: '../obsidian', + gitbookProject: '../gitbook', +}; + +try { + const settingsFile = require('./settings.json'); + + settings = { + ...settings, + ...settingsFile, + }; + console.log('Custom settings loaded from settings.json'); +} catch { + console.log('Settings not found. Using default settings'); +} + +// export default settings; +module.exports = settings;