Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link parser #1

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
20 changes: 8 additions & 12 deletions src/gitbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');


/**
Expand All @@ -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) {
Expand All @@ -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
}

Expand Down
19 changes: 19 additions & 0 deletions src/gitbook/copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
192 changes: 192 additions & 0 deletions src/obsidian-md/parse-links.js
Original file line number Diff line number Diff line change
@@ -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;
19 changes: 19 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
@@ -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;