Finished constructing backlink from internal links

TODO: performance improvement, and code reability.
This commit is contained in:
Tuan Cao 2022-04-07 16:52:41 +07:00
parent b47d1053d8
commit 2bb96504c9
5 changed files with 170 additions and 175 deletions

View File

@ -12,7 +12,7 @@ function BackLinks({linkList}) {
? ?
linkList.map(aLink => linkList.map(aLink =>
<li> <li>
<Link href={aLink.link}> <Link href={aLink.slug}>
<a> <a>
{aLink.title} {aLink.title}
</a> </a>

View File

@ -7,8 +7,6 @@ import { Node } from "./node"
var remark = require('remark') var remark = require('remark')
const unified = require('unified') const unified = require('unified')
const markdown = require('remark-parse') const markdown = require('remark-parse')
const { wikiLinkPlugin } = require('remark-wiki-link');
var guide = require('remark-preset-lint-markdown-style-guide') var guide = require('remark-preset-lint-markdown-style-guide')
var html = require('remark-html') var html = require('remark-html')
var report = require('vfile-reporter') var report = require('vfile-reporter')
@ -43,10 +41,10 @@ export function getSortedPostsData() {
// let processor = unified() // let processor = unified()
// .use(markdown, { gfm: true }) // .use(markdown, { gfm: true })
// .use(wikiLinkPlugin) // .use(wikiLinkPlugin)
const htmlContent = Remark.getHtmlContent(fileContent, { // const htmlContent = Remark.getHtmlContent(fileContent, {
fileNames:fileNames, // fileNames:fileNames,
permalink: `/note/${permalink}` // permalink: `/note/${permalink}`
}) // })
//unified() //unified()
//.use(markdown) //.use(markdown)

View File

@ -8,6 +8,7 @@ import html from "remark-html";
import frontmatter from "remark-frontmatter"; import frontmatter from "remark-frontmatter";
import externalLinks from "remark-external-links"; import externalLinks from "remark-external-links";
import highlight from "remark-highlight.js"; import highlight from "remark-highlight.js";
import {Node} from "./node";
const postsDirectory = path.join(process.cwd(), 'posts') const postsDirectory = path.join(process.cwd(), 'posts')
const isFile = fileName => { const isFile = fileName => {
@ -18,7 +19,7 @@ export const Transformer = {
haveFrontMatter: function (content) { haveFrontMatter: function (content) {
//console.log("\t Front matter data content", content) //console.log("\t Front matter data content", content)
if (!content) return false if (!content) return false
var indexOfFirst = content.indexOf("---") const indexOfFirst = content.indexOf("---");
//console.log("\t Front matter data firstIndex ", indexOfFirst) //console.log("\t Front matter data firstIndex ", indexOfFirst)
//console.log("index first", indexOfFirst) //console.log("index first", indexOfFirst)
if (indexOfFirst === -1) { if (indexOfFirst === -1) {
@ -37,7 +38,6 @@ export const Transformer = {
getHtmlContent: function (content, {fileNames}) { getHtmlContent: function (content, {fileNames}) {
let htmlContent = [] let htmlContent = []
let internalLinks = []
const sanitizedContent = Transformer.preprocessThreeDashes(content) const sanitizedContent = Transformer.preprocessThreeDashes(content)
unified() unified()
@ -46,61 +46,36 @@ export const Transformer = {
.use(externalLinks, {target: "_blank", rel: ['noopener']}) .use(externalLinks, {target: "_blank", rel: ['noopener']})
.use(frontmatter, ['yaml', 'toml']) .use(frontmatter, ['yaml', 'toml'])
.use(wikiLinkPlugin, { .use(wikiLinkPlugin, {
permalinks:fileNames, permalinks: null,
pageResolver: function(pageName){ pageResolver: function (pageName) {
const name = [Transformer.parseFileNameFromPath(pageName)] return [Transformer.parseFileNameFromPath(pageName)]
//console.log("\n\nwiki internal links", Transformer.parseFileNameFromPath(name[0]));
const backLink = {
title: name,
link: Transformer.parseFileNameFromPath(name[0]),
shortSummary: name
}
internalLinks.push(backLink);
return name
}, },
hrefTemplate: function(permalink){ hrefTemplate: function (permalink) {
permalink = Transformer.normalizeFileName(permalink) permalink = Transformer.normalizeFileName(permalink)
permalink = permalink.replace("ç","c").replace("ı","i").replace("ş","s") permalink = permalink.replace("ç", "c").replace("ı", "i").replace("ş", "s")
//console.log("wiki pemalink", permalink);
return `/note/${permalink}` return `/note/${permalink}`
}, },
aliasDivider:"|" aliasDivider: "|"
}) })
.use(html) .use(html)
.process(sanitizedContent, .process(sanitizedContent,
function (err, file) { function (err, file) {
//console.log("asd", String(file).slice(0,50)) htmlContent.push(String(file).replace("\n", ""))
//console.error("remark: ", report(err || file)) }
htmlContent.push(String(file).replace("\n", ""))
}
) )
htmlContent = htmlContent.join("") htmlContent = htmlContent.join("")
htmlContent = htmlContent.split("---") htmlContent = htmlContent.split("---")
return [htmlContent, internalLinks] return [htmlContent]
}, },
// getReact : function (content, {fileNames}) {
// const sanitizedContent = Transformer.preprocessThreeDashes(content)
// let result = null
// Transformer.getProcessor(content, {fileNames})
// .use(rehypeReact, {createElement, Fragment})
// .process(sanitizedContent, file => {
// result = file.result
// })
//
// return result
// },
/* SANITIZE MARKDOWN FOR --- */ /* SANITIZE MARKDOWN FOR --- */
preprocessThreeDashes: function (content) { preprocessThreeDashes: function (content) {
var indexOfFirst = content.indexOf("---") const indexOfFirst = content.indexOf("---");
if (indexOfFirst === -1) { if (indexOfFirst === -1) {
return content return content
} }
var indexOfSecond = content.indexOf("---", (indexOfFirst + 1)) const indexOfSecond = content.indexOf("---", (indexOfFirst + 1));
const frontPart = content.slice(0, indexOfSecond); const frontPart = content.slice(0, indexOfSecond);
const contentPart = content.slice(indexOfSecond); const contentPart = content.slice(indexOfSecond);
const processedContent = contentPart.split("---").join("") const processedContent = contentPart.split("---").join("")
@ -111,7 +86,7 @@ export const Transformer = {
/* Normalize File Names */ /* Normalize File Names */
normalizeFileName: function (filename) { normalizeFileName: function (filename) {
var processedFileName = filename.replace(".md", "") let processedFileName = filename.replace(".md", "");
processedFileName = processedFileName.replace('(', '').replace(')', '') processedFileName = processedFileName.replace('(', '').replace(')', '')
processedFileName = processedFileName.split(" ").join("-") processedFileName = processedFileName.split(" ").join("-")
// processedFileName = processedFileName.toLowerCase() // processedFileName = processedFileName.toLowerCase()
@ -136,12 +111,12 @@ export const Transformer = {
}, },
/* Pair provided and existing Filenames*/ /* Pair provided and existing Filenames*/
pairCurrentFile: function (provided, ListOfFilePaths) { pairCurrentFile: function (provided, listOfFilePaths) {
//console.log(provided, ListOfFilePaths) //console.log(provided, ListOfFilePaths)
const providedSanitizedFileName = Transformer.normalizeFileName(provided); const providedSanitizedFileName = Transformer.normalizeFileName(provided);
// Map file paths and return true if it pairs with provided // Map file paths and return true if it pairs with provided
const possibleFilePath = ListOfFilePaths.filter(possibleFilePath => { const possibleFilePath = listOfFilePaths.filter(possibleFilePath => {
const possibleFileName = Transformer.parseFileNameFromPath(possibleFilePath); const possibleFileName = Transformer.parseFileNameFromPath(possibleFilePath);
const possibleSanitizedFileName = Transformer.normalizeFileName(possibleFileName) const possibleSanitizedFileName = Transformer.normalizeFileName(possibleFileName)
//console.log("----", providedSanitizedFileName, possibleSanitizedFileName) //console.log("----", providedSanitizedFileName, possibleSanitizedFileName)
@ -152,5 +127,49 @@ export const Transformer = {
}) })
console.log("p---", possibleFilePath) console.log("p---", possibleFilePath)
return possibleFilePath[0] return possibleFilePath[0]
},
getInternalLinks: function (aFilePath) {
const filePaths = Node.getFiles(postsDirectory);
const currentFilePath = Transformer.pairCurrentFile(aFilePath, filePaths)
const fileContent = Node.readFileSync(aFilePath);
const internalLinks = []
const sanitizedContent = Transformer.preprocessThreeDashes(fileContent)
unified()
.use(markdown, {gfm: true})
.use(wikiLinkPlugin, {
pageResolver: function (pageName) {
// let name = [Transformer.parseFileNameFromPath(pageName)];
let slug = Transformer.parseFileNameFromPath(pageName);
if (slug.includes('#')) {
console.log(slug)
}
const canonicalSlug = slug.includes('#') ? slug.split('#')[0] : slug
const backLink = {
title: canonicalSlug,
slug: canonicalSlug,
shortSummary: canonicalSlug
}
if (canonicalSlug != null && internalLinks.find(aLink => aLink.slug === canonicalSlug ) == null) {
internalLinks.push(backLink);
}
return [canonicalSlug]
}
,
hrefTemplate: function (permalink) {
permalink = Transformer.normalizeFileName(permalink)
permalink = permalink.replace("ç", "c").replace("ı", "i").replace("ş", "s")
return `/note/${permalink}`
},
aliasDivider: "|"
})
.use(html)
.processSync(sanitizedContent)
return internalLinks;
} }
} }

View File

@ -9,135 +9,109 @@ export function getAllFileNames() {
return Node.getFiles(postsDirectory).map(f => Transformer.parseFileNameFromPath(f)) return Node.getFiles(postsDirectory).map(f => Transformer.parseFileNameFromPath(f))
} }
export function getSinglePost(filename) { export function getFileNames(filename) {
console.log("\n\nFile is scanning: ", filename) let filePaths = Node.getFiles(postsDirectory);
// List of filenames that will provide existing links to wikilink
var filePaths = Node.getFiles(postsDirectory)
const fileNames = filePaths.map(f => Transformer.parseFileNameFromPath(f)) const fileNames = filePaths.map(f => Transformer.parseFileNameFromPath(f))
//console.log("\t filenames: ",fileNames, "\n") //console.log("\t filenames: ",fileNames, "\n")
// IF filename is not sidebar.md THEN Exclude sidebar.md from file list // IF filename is not sidebar.md THEN Exclude sidebar.md from file list
var currentFilePath; let currentFilePath;
if (filename === "sidebar"){ if (filename === "sidebar") {
//console.log(111) //console.log(111)
currentFilePath = path.join(postsDirectory, "/sidebar.md") currentFilePath = path.join(postsDirectory, "/sidebar.md")
} } else if (filename === "index") {
else if (filename === "index"){
//console.log(222) //console.log(222)
currentFilePath = path.join(postsDirectory, "/index.md") currentFilePath = path.join(postsDirectory, "/index.md")
} } else {
else { //TODO remove reference to index/sidebar md
//console.log(333)
filePaths = filePaths.filter(f => !(f.endsWith("sidebar.md") && f.endsWith("index.md"))) filePaths = filePaths.filter(f => !(f.endsWith("sidebar.md") && f.endsWith("index.md")))
//console.log("\tDirectory is scanning to find corresponding filename") //console.log("\tDirectory is scanning to find corresponding filename")
currentFilePath = Transformer.pairCurrentFile(filename, filePaths) currentFilePath = Transformer.pairCurrentFile(filename, filePaths)
//console.log("\tScan is finished. Founded filepath", currentFilePath, "\n") //console.log("\tScan is finished. Founded filepath", currentFilePath, "\n")
} }
return {fileNames, currentFilePath};
}
export function getSinglePost(filename) {
console.log("\n\nFile is scanning: ", filename)
// List of filenames that will provide existing links to wikilink
let {fileNames, currentFilePath} = getFileNames(filename);
//console.log("currentFilePath: ", currentFilePath) //console.log("currentFilePath: ", currentFilePath)
var fileContent = Node.readFileSync(currentFilePath) var fileContent = Node.readFileSync(currentFilePath)
const currentFileFrontMatter = Transformer.getFrontMatterData(fileContent) const currentFileFrontMatter = Transformer.getFrontMatterData(fileContent)
//console.log("\tFounded front matter data: ", currentFileFrontMatter, "\n") //console.log("\tFounded front matter data: ", currentFileFrontMatter, "\n")
// fileContent = Transformer.preprocessThreeDashes(fileContent) // fileContent = Transformer.preprocessThreeDashes(fileContent)
//fileContent = fileContent.split("---").join("") //fileContent = fileContent.split("---").join("")
//console.log("filecontent end") //console.log("filecontent end")
const [htmlContent, backlinks] = Transformer.getHtmlContent(fileContent, { const [htmlContent] = Transformer.getHtmlContent(fileContent, {
fileNames:fileNames, fileNames: fileNames,
}) })
//console.log("hrmlcontents and backlinks") //console.log("hrmlcontents and backlinks")
return { return {
id:filename, id: filename,
...currentFileFrontMatter, ...currentFileFrontMatter,
data:htmlContent, data: htmlContent,
backLinks: backlinks }
}
}
export function getAllBacklinks(){
//console.log("\n\nBacklinks are scanning")
//var bimap = new BiMap
var internalLinks = []
// Get file names under /posts
const filePaths = Node.getFiles(postsDirectory).filter(f => !f.endsWith("sidebar.md"))
const fileNames = filePaths.map(f => Transformer.parseFileNameFromPath(f))
//console.log("\tFounded filePaths: ", fileNames)
var allBacklinkData = filePaths.map(fileName => {
// Remove ".md" from file name to get id
const slug = Transformer.parseFileNameFromPath(fileName)
//console.log("filename", fileNames)
const fileData = {
id:slug
}
//console.log("AllBacklinks slug", slug)
// Read markdown file as string
var fileContent = Node.readFileSync(fileName, 'utf8')
const frontmatterData = Transformer.getFrontMatterData(fileContent)
const requiredParameters = ["title", "description"]
requiredParameters.forEach(param => {
if (frontmatterData[param])
fileData[param] = frontmatterData[param]
})
//fileContent = fileContent.split("---").join("")
const [htmlContent, backlinks] = Transformer.getHtmlContent(fileContent, {
fileNames:fileNames,
})
// Check if scanned slug post has any internal links
const existingInternalLink = backlinks.filter(bl => fileNames.includes(bl))
fileData.to = existingInternalLink
fileData.href = slug === "index" ? "/" : `/note/${slug}`
//console.log("\n\nbacklinks",[ slug, [backlinks]] )
//bimap.push(slug, backlinks)
// Check if internal link exists
//const internalLinks = backlinks.filter(bl => fileNames.includes(bl))
internalLinks.push(fileData)
//console.log("bimap: ", bimap.key(slug))
// Combine the data with the slug
//return backlinkList.length > 0 ? JSON.stringify(backlinkList) : null
})
//console.log("founded internal links for ", internalLinks)
//console.log("\n\ninternal list: ", internalLinks)
return internalLinks
//return [allBacklinkData.filter(bl => bl !== null), JSON.stringify(fileNames)]
} }
export function getGraphData(){ export function constructBackLinks() {
const backlinkData = getAllBacklinks()
const elements = [] const filePaths = getContentPaths()
const edges = []
// First create Nodes const nodes = []
backlinkData.forEach(el => {
const node = {data: {id: el.id}};
if(el.title){ filePaths.forEach( filename => {
node.data.title = el.title const {currentFilePath, fileNames} = getFileNames(filename)
} const internalLinks = Transformer.getInternalLinks(currentFilePath)
if (el.description){ internalLinks.forEach(aLink => {
node.data.description = el.description
} if (aLink.slug === null || aLink.slug.length === 0) return
elements.push(node)
const anEdge = {
source: filename,
target: aLink.slug,
}
edges.push(anEdge)
if (nodes.findIndex(aNode => aNode.slug === aLink.slug) === -1) {
nodes.push(aLink)
}
})
} }
) )
return {nodes, edges};
}
export function getGraphData() {
const backlinkData = constructBackLinks()
const elements = []
// First create Nodes
backlinkData.forEach(el => {
const node = {data: {id: el.id}};
if (el.title) {
node.data.title = el.title
}
if (el.description) {
node.data.description = el.description
}
elements.push(node)
}
)
// Second create Edges // Second create Edges
backlinkData.forEach(el => { backlinkData.forEach(el => {
// check if has any internal link // check if has any internal link
if (el.to.length > 0){ if (el.to.length > 0) {
// create edge from element to its links // create edge from element to its links
el.to.forEach(linkElement => { el.to.forEach(linkElement => {
const edge = { const edge = {
@ -151,36 +125,35 @@ export function getGraphData(){
}) })
} }
}) })
return elements return elements
} }
export function getPostListData() { export function getContentPaths() {
//console.log("\n\nAll Posts are scanning") //console.log("\n\nAll Posts are scanning")
// Get file names under /posts // Get file names under /posts
const filePaths = Node.getFiles(postsDirectory).filter(f => !(f.endsWith("index") || f.endsWith("sidebar"))) const filePaths = Node.getFiles(postsDirectory).filter(f => !(f.endsWith("index") || f.endsWith("sidebar")))
const fileNames = filePaths.map(f => Transformer.parseFileNameFromPath(f)) return filePaths.map(f => Transformer.parseFileNameFromPath(f))
//console.log("filePaths", filePaths)
return fileNames
} }
export function getDirectoryData() { export function getDirectoryData() {
const filteredDirectory = dirTree(postsDirectory,{ extensions: /\.md/ }); const filteredDirectory = dirTree(postsDirectory, {extensions: /\.md/});
const convertedData = convertObject(filteredDirectory) return convertObject(filteredDirectory)
// console.log()
// const array = getFlattenArray(convertedData)
return convertedData
} }
let _counter = 0; let _counter = 0;
export function convertObject(thisObject) { export function convertObject(thisObject) {
const children = [] const children = []
let routerPath = getContentPaths().find(fileName => fileName === Transformer.normalizeFileName(thisObject.name)) || null
let routerPath = getPostListData().find(fileName => fileName === Transformer.normalizeFileName(thisObject.name) ) || null routerPath = routerPath ? '/note/' + routerPath : null
routerPath = routerPath ? '/note/' +routerPath : null const newObject = {
const newObject = {name: thisObject.name, children: children, id: (_counter++).toString(), routePath: routerPath || null }; name: thisObject.name,
children: children,
id: (_counter++).toString(),
routePath: routerPath || null
};
if (thisObject.children != null && thisObject.children.length > 0) { if (thisObject.children != null && thisObject.children.length > 0) {
thisObject.children.forEach(aChild => { thisObject.children.forEach(aChild => {
@ -204,6 +177,6 @@ function flat(array) {
return result; return result;
} }
export function getFlattenArray (thisObject) { export function getFlattenArray(thisObject) {
return flat(thisObject.children) return flat(thisObject.children)
} }

View File

@ -1,12 +1,11 @@
import Head from "next/head"; import Head from "next/head";
import Layout from "../../components/layout"; import Layout from "../../components/layout";
import { import {
getPostListData, getContentPaths,
getSinglePost, getSinglePost,
getGraphData,
convertObject, convertObject,
getDirectoryData, getDirectoryData,
getAllFileNames constructBackLinks, getFileNames
} from "../../lib/utils"; } from "../../lib/utils";
import FolderTree from "../../components/FolderTree"; import FolderTree from "../../components/FolderTree";
import {getFlattenArray} from "../../lib/utils"; import {getFlattenArray} from "../../lib/utils";
@ -29,7 +28,7 @@ export default function Home({note, backLinks, fileNames, tree, flattenNodes}) {
} }
export async function getStaticPaths() { export async function getStaticPaths() {
const allPostsData = getPostListData(); const allPostsData = getContentPaths();
const paths = allPostsData.map(p => ({params: {id: p}})) const paths = allPostsData.map(p => ({params: {id: p}}))
return { return {
paths, paths,
@ -37,11 +36,17 @@ export async function getStaticPaths() {
}; };
} }
const {nodes, edges} = constructBackLinks()
export function getStaticProps({params}) { export function getStaticProps({params}) {
const note = getSinglePost(params.id); const note = getSinglePost(params.id);
const tree = convertObject(getDirectoryData()); const tree = convertObject(getDirectoryData());
const flattenNodes = getFlattenArray(tree) const flattenNodes = getFlattenArray(tree)
const fileNames = getAllFileNames() // const fileNames = getAllFileNames()
const { fileNames} = getFileNames(params.id)
const listOfEdges = edges.filter(anEdge => anEdge.target === params.id)
const internalLinks = listOfEdges.map(anEdge => nodes.find(aNode => aNode.slug === anEdge.source)).filter(element => element !== undefined)
return { return {
props: { props: {
@ -49,7 +54,7 @@ export function getStaticProps({params}) {
tree: tree, tree: tree,
flattenNodes: flattenNodes, flattenNodes: flattenNodes,
fileNames: fileNames, fileNames: fileNames,
backLinks: note.backLinks backLinks: internalLinks
}, },
}; };
} }