computer-scienceangular-roadmapbackend-roadmapblockchain-roadmapdba-roadmapdeveloper-roadmapdevops-roadmapfrontend-roadmapgo-roadmaphactoberfestjava-roadmapjavascript-roadmapnodejs-roadmappython-roadmapqa-roadmapreact-roadmaproadmapstudy-planvue-roadmapweb3-roadmap
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
4.8 KiB
188 lines
4.8 KiB
const fs = require('node:fs'); |
|
const path = require('node:path'); |
|
|
|
const allRoadmapDirs = fs.readdirSync( |
|
path.join(__dirname, '../src/data/roadmaps'), |
|
); |
|
|
|
allRoadmapDirs.forEach((roadmapId) => { |
|
const roadmapDir = path.join( |
|
__dirname, |
|
`../src/data/roadmaps/${roadmapId}/content`, |
|
); |
|
|
|
function getHostNameWithoutTld(hostname) { |
|
const parts = hostname.split('.'); |
|
return parts.slice(0, parts.length - 1).join('.'); |
|
} |
|
|
|
function isOfficialWebsite(hostname, fileName, roadmapId) { |
|
fileName = fileName.replace('/index.md', '').replace('.md', ''); |
|
|
|
const parts = fileName.split('/'); |
|
const lastPart = parts[parts.length - 1]; |
|
|
|
const normalizedFilename = lastPart.replace(/\d+/g, '').replace(/-/g, ''); |
|
const normalizedHostname = getHostNameWithoutTld(hostname); |
|
|
|
if (normalizedFilename === normalizedHostname) { |
|
return true; |
|
} |
|
|
|
if (normalizedFilename.includes(normalizedHostname)) { |
|
return true; |
|
} |
|
|
|
return !!roadmapId.includes(normalizedHostname); |
|
} |
|
|
|
// websites are educational websites that are of following types: |
|
// - @official@ |
|
// - @article@ |
|
// - @course@ |
|
// - @opensource@ |
|
// - @podcast@ |
|
// - @video@ |
|
// - @website@ |
|
// content is only educational websites |
|
function getTypeFromHostname(hostname, fileName, roadmapId) { |
|
hostname = hostname.replace('www.', ''); |
|
|
|
const videoHostnames = ['youtube.com', 'vimeo.com', 'youtu.be']; |
|
const courseHostnames = ['coursera.org', 'udemy.com', 'edx.org']; |
|
const podcastHostnames = ['spotify.com', 'apple.com']; |
|
const opensourceHostnames = ['github.com', 'gitlab.com']; |
|
const articleHostnames = [ |
|
'neilpatel.com', |
|
'learningseo.io', |
|
'htmlreference.io', |
|
'docs.gitlab.com', |
|
'docs.github.com', |
|
'skills.github.com', |
|
'cloudflare.com', |
|
'w3schools.com', |
|
'medium.com', |
|
'dev.to', |
|
'web.dev', |
|
'css-tricks.com', |
|
'developer.mozilla.org', |
|
'smashingmagazine.com', |
|
'freecodecamp.org', |
|
'cs.fyi', |
|
'thenewstack.io', |
|
'html5rocks.com', |
|
'html.com', |
|
'javascript.info', |
|
'css-tricks.com', |
|
'developer.apple.com', |
|
]; |
|
|
|
if (articleHostnames.includes(hostname)) { |
|
return 'article'; |
|
} |
|
|
|
if (videoHostnames.includes(hostname)) { |
|
return 'video'; |
|
} |
|
|
|
if (courseHostnames.includes(hostname)) { |
|
return 'course'; |
|
} |
|
|
|
if (podcastHostnames.includes(hostname)) { |
|
return 'podcast'; |
|
} |
|
|
|
if (opensourceHostnames.includes(hostname)) { |
|
return 'opensource'; |
|
} |
|
|
|
if (hostname === 'roadmap.sh') { |
|
return 'roadmap.sh'; |
|
} |
|
|
|
if (isOfficialWebsite(hostname, fileName, roadmapId)) { |
|
return 'official'; |
|
} |
|
|
|
return 'article'; |
|
} |
|
|
|
function readNestedMarkdownFiles(dir, files = []) { |
|
const dirEnts = fs.readdirSync(dir, { withFileTypes: true }); |
|
|
|
for (const dirent of dirEnts) { |
|
const fullPath = path.join(dir, dirent.name); |
|
if (dirent.isDirectory()) { |
|
readNestedMarkdownFiles(fullPath, files); |
|
} else { |
|
if (path.extname(fullPath) === '.md') { |
|
files.push(fullPath); |
|
} |
|
} |
|
} |
|
|
|
return files; |
|
} |
|
|
|
const files = readNestedMarkdownFiles(roadmapDir); |
|
|
|
// for each of the files, assign the type of link to the beginning of each markdown link |
|
// i.e. - [@article@abc](xyz) where @article@ is the type of link. Possible types: |
|
// - @article@ |
|
// - @course@ |
|
// - @opensource@ |
|
// - @podcast@ |
|
// - @video@ |
|
// - @website@ |
|
files.forEach((file) => { |
|
const content = fs.readFileSync(file, 'utf-8'); |
|
const lines = content.split('\n'); |
|
|
|
const newContent = lines |
|
.map((line) => { |
|
if (line.startsWith('- [')) { |
|
const type = line.match(/@(\w+)@/); |
|
if (type) { |
|
return line; |
|
} |
|
|
|
let urlMatches = line.match(/\((https?:\/\/[^)]+)\)/); |
|
let fullUrl = urlMatches?.[1]; |
|
|
|
if (!fullUrl) { |
|
// is it slashed URL i.e. - [abc](/xyz) |
|
fullUrl = line.match(/\((\/[^)]+)\)/)?.[1]; |
|
if (fullUrl) { |
|
fullUrl = `https://roadmap.sh${fullUrl}`; |
|
} |
|
|
|
if (!fullUrl) { |
|
console.error('No URL found in line:', line); |
|
return; |
|
} |
|
} |
|
|
|
const url = new URL(fullUrl); |
|
const hostname = url.hostname; |
|
|
|
let urlType = getTypeFromHostname(hostname, file, roadmapId); |
|
const linkText = line.match(/\[([^\]]+)\]/)[1]; |
|
|
|
if ( |
|
linkText.toLowerCase().startsWith('visit dedicated') && |
|
linkText.toLowerCase().endsWith('roadmap') |
|
) { |
|
urlType = 'roadmap'; |
|
} |
|
|
|
return line.replace('- [', `- [@${urlType}@`).replace('](', ']('); |
|
} |
|
|
|
return line; |
|
}) |
|
.join('\n'); |
|
|
|
fs.writeFileSync(file, newContent); |
|
}); |
|
});
|
|
|