mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-12 20:24:21 +02:00
Update topic assignment
This commit is contained in:
@@ -1,184 +1,188 @@
|
|||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
|
|
||||||
const roadmapId = 'frontend';
|
const allRoadmapDirs = fs.readdirSync(
|
||||||
|
path.join(__dirname, '../src/data/roadmaps'),
|
||||||
const roadmapDir = path.join(
|
|
||||||
__dirname,
|
|
||||||
`../src/data/roadmaps/${roadmapId}/content`,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function getHostNameWithoutTld(hostname) {
|
allRoadmapDirs.forEach((roadmapId) => {
|
||||||
const parts = hostname.split('.');
|
const roadmapDir = path.join(
|
||||||
return parts.slice(0, parts.length - 1).join('.');
|
__dirname,
|
||||||
}
|
`../src/data/roadmaps/${roadmapId}/content`,
|
||||||
|
);
|
||||||
|
|
||||||
function isOfficialWebsite(hostname, fileName, roadmapId) {
|
function getHostNameWithoutTld(hostname) {
|
||||||
fileName = fileName.replace('/index.md', '').replace('.md', '');
|
const parts = hostname.split('.');
|
||||||
|
return parts.slice(0, parts.length - 1).join('.');
|
||||||
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)) {
|
function isOfficialWebsite(hostname, fileName, roadmapId) {
|
||||||
return true;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.', '');
|
||||||
|
|
||||||
// websites are educational websites that are of following types:
|
const videoHostnames = ['youtube.com', 'vimeo.com', 'youtu.be'];
|
||||||
// - @official@
|
const courseHostnames = ['coursera.org', 'udemy.com', 'edx.org'];
|
||||||
// - @article@
|
const podcastHostnames = ['spotify.com', 'apple.com'];
|
||||||
// - @course@
|
const opensourceHostnames = ['github.com', 'gitlab.com'];
|
||||||
// - @opensource@
|
const articleHostnames = [
|
||||||
// - @podcast@
|
'neilpatel.com',
|
||||||
// - @video@
|
'learningseo.io',
|
||||||
// - @website@
|
'htmlreference.io',
|
||||||
// content is only educational websites
|
'docs.gitlab.com',
|
||||||
function getTypeFromHostname(hostname, fileName, roadmapId) {
|
'docs.github.com',
|
||||||
hostname = hostname.replace('www.', '');
|
'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',
|
||||||
|
];
|
||||||
|
|
||||||
const videoHostnames = ['youtube.com', 'vimeo.com', 'youtu.be'];
|
if (articleHostnames.includes(hostname)) {
|
||||||
const courseHostnames = ['coursera.org', 'udemy.com', 'edx.org'];
|
return 'article';
|
||||||
const podcastHostnames = ['spotify.com', 'apple.com'];
|
}
|
||||||
const opensourceHostnames = ['github.com', 'gitlab.com'];
|
|
||||||
const articleHostnames = [
|
if (videoHostnames.includes(hostname)) {
|
||||||
'neilpatel.com',
|
return 'video';
|
||||||
'learningseo.io',
|
}
|
||||||
'htmlreference.io',
|
|
||||||
'docs.gitlab.com',
|
if (courseHostnames.includes(hostname)) {
|
||||||
'docs.github.com',
|
return 'course';
|
||||||
'skills.github.com',
|
}
|
||||||
'cloudflare.com',
|
|
||||||
'w3schools.com',
|
if (podcastHostnames.includes(hostname)) {
|
||||||
'medium.com',
|
return 'podcast';
|
||||||
'dev.to',
|
}
|
||||||
'web.dev',
|
|
||||||
'css-tricks.com',
|
if (opensourceHostnames.includes(hostname)) {
|
||||||
'developer.mozilla.org',
|
return 'opensource';
|
||||||
'smashingmagazine.com',
|
}
|
||||||
'freecodecamp.org',
|
|
||||||
'cs.fyi',
|
if (hostname === 'roadmap.sh') {
|
||||||
'thenewstack.io',
|
return 'roadmap.sh';
|
||||||
'html5rocks.com',
|
}
|
||||||
'html.com',
|
|
||||||
'javascript.info',
|
if (isOfficialWebsite(hostname, fileName, roadmapId)) {
|
||||||
'css-tricks.com',
|
return 'official';
|
||||||
'developer.apple.com',
|
}
|
||||||
];
|
|
||||||
|
|
||||||
if (articleHostnames.includes(hostname)) {
|
|
||||||
return 'article';
|
return 'article';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoHostnames.includes(hostname)) {
|
function readNestedMarkdownFiles(dir, files = []) {
|
||||||
return 'video';
|
const dirEnts = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
}
|
|
||||||
|
|
||||||
if (courseHostnames.includes(hostname)) {
|
for (const dirent of dirEnts) {
|
||||||
return 'course';
|
const fullPath = path.join(dir, dirent.name);
|
||||||
}
|
if (dirent.isDirectory()) {
|
||||||
|
readNestedMarkdownFiles(fullPath, files);
|
||||||
if (podcastHostnames.includes(hostname)) {
|
} else {
|
||||||
return 'podcast';
|
if (path.extname(fullPath) === '.md') {
|
||||||
}
|
files.push(fullPath);
|
||||||
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
const files = readNestedMarkdownFiles(roadmapDir);
|
||||||
}
|
|
||||||
|
|
||||||
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');
|
||||||
|
|
||||||
// for each of the files, assign the type of link to the beginning of each markdown link
|
const newContent = lines
|
||||||
// i.e. - [@article@abc](xyz) where @article@ is the type of link. Possible types:
|
.map((line) => {
|
||||||
// - @article@
|
if (line.startsWith('- [')) {
|
||||||
// - @course@
|
const type = line.match(/@(\w+)@/);
|
||||||
// - @opensource@
|
if (type) {
|
||||||
// - @podcast@
|
return line;
|
||||||
// - @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}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let urlMatches = line.match(/\((https?:\/\/[^)]+)\)/);
|
||||||
|
let fullUrl = urlMatches?.[1];
|
||||||
|
|
||||||
if (!fullUrl) {
|
if (!fullUrl) {
|
||||||
console.error('No URL found in line:', line);
|
// is it slashed URL i.e. - [abc](/xyz)
|
||||||
return;
|
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('](', '](');
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(fullUrl);
|
return line;
|
||||||
const hostname = url.hostname;
|
})
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
let urlType = getTypeFromHostname(hostname, file, roadmapId);
|
fs.writeFileSync(file, newContent);
|
||||||
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);
|
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user