chore: change eslint & prettier config
This commit is contained in:
parent
fc827d74fe
commit
b43871c516
103 changed files with 3581 additions and 3543 deletions
|
@ -1,41 +1,41 @@
|
|||
{
|
||||
"name": "@developomp-site/blog-content",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "ts-node --experimental-specifier-resolution=node ./src",
|
||||
"clean": "rm -rf .turbo node_modules dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@developomp-site/tsconfig": "workspace:*",
|
||||
"@types/ejs": "^3.1.1",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/read-time-estimate": "^0.0.0",
|
||||
"@types/svgo": "^3.0.0",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"canvas": "^2.11.2",
|
||||
"ejs": "^3.1.8",
|
||||
"gray-matter": "^4.0.3",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-anchor": "^8.6.5",
|
||||
"markdown-it-attrs": "^4.1.4",
|
||||
"markdown-it-footnote": "^3.0.3",
|
||||
"markdown-it-highlight-lines": "^1.0.2",
|
||||
"markdown-it-mark": "^3.0.1",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-task-checkbox": "^1.0.6",
|
||||
"markdown-it-texmath": "^1.0.0",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"read-time-estimate": "^0.0.3",
|
||||
"simple-icons": "^7.21.0",
|
||||
"slugify": "^1.6.6",
|
||||
"svgo": "^3.0.2",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
"name": "@developomp-site/blog-content",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "ts-node --experimental-specifier-resolution=node ./src",
|
||||
"clean": "rm -rf .turbo node_modules dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@developomp-site/tsconfig": "workspace:*",
|
||||
"@types/ejs": "^3.1.1",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/read-time-estimate": "^0.0.0",
|
||||
"@types/svgo": "^3.0.0",
|
||||
"@types/tinycolor2": "^1.4.3",
|
||||
"canvas": "^2.11.2",
|
||||
"ejs": "^3.1.8",
|
||||
"gray-matter": "^4.0.3",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-anchor": "^8.6.5",
|
||||
"markdown-it-attrs": "^4.1.4",
|
||||
"markdown-it-footnote": "^3.0.3",
|
||||
"markdown-it-highlight-lines": "^1.0.2",
|
||||
"markdown-it-mark": "^3.0.1",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-task-checkbox": "^1.0.6",
|
||||
"markdown-it-texmath": "^1.0.0",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"read-time-estimate": "^0.0.3",
|
||||
"simple-icons": "^7.21.0",
|
||||
"slugify": "^1.6.6",
|
||||
"svgo": "^3.0.2",
|
||||
"tinycolor2": "^1.4.2",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,19 @@ import postProcess from "./postProcess"
|
|||
import { ContentMap, ParseMode, PortfolioData, SeriesMap } from "./types/types"
|
||||
|
||||
export const contentMap: ContentMap = {
|
||||
date: {},
|
||||
tags: {},
|
||||
meta: {
|
||||
tags: [],
|
||||
},
|
||||
posts: {},
|
||||
series: {},
|
||||
unsearchable: {},
|
||||
date: {},
|
||||
tags: {},
|
||||
meta: {
|
||||
tags: [],
|
||||
},
|
||||
posts: {},
|
||||
series: {},
|
||||
unsearchable: {},
|
||||
}
|
||||
export const seriesMap: SeriesMap = {}
|
||||
export const portfolioData: PortfolioData = {
|
||||
skills: new Set(),
|
||||
projects: {},
|
||||
skills: new Set(),
|
||||
projects: {},
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -36,8 +36,8 @@ export const portfolioData: PortfolioData = {
|
|||
*/
|
||||
|
||||
try {
|
||||
fs.rmSync("dist", { recursive: true })
|
||||
// eslint-disable-next-line no-empty
|
||||
fs.rmSync("dist", { recursive: true })
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (err) {}
|
||||
|
||||
/**
|
||||
|
@ -45,16 +45,16 @@ try {
|
|||
*/
|
||||
|
||||
if (!fs.lstatSync(markdownPath).isDirectory())
|
||||
throw Error("Invalid markdown path")
|
||||
throw Error("Invalid markdown path")
|
||||
|
||||
if (!fs.lstatSync(markdownPath + "/posts").isDirectory())
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
|
||||
if (!fs.lstatSync(markdownPath + "/unsearchable").isDirectory())
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
|
||||
if (!fs.lstatSync(markdownPath + "/series").isDirectory())
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
throw Error(`Cannot find directory: ${markdownPath + "/posts"}`)
|
||||
|
||||
/**
|
||||
* Parse
|
||||
|
@ -77,11 +77,11 @@ postProcess()
|
|||
|
||||
fs.writeFileSync(mapFilePath, JSON.stringify(contentMap))
|
||||
fs.writeFileSync(
|
||||
portfolioFilePath,
|
||||
JSON.stringify({
|
||||
...portfolioData,
|
||||
skills: Array.from(portfolioData.skills),
|
||||
})
|
||||
portfolioFilePath,
|
||||
JSON.stringify({
|
||||
...portfolioData,
|
||||
skills: Array.from(portfolioData.skills),
|
||||
})
|
||||
)
|
||||
|
||||
saveIndex()
|
||||
|
|
|
@ -24,37 +24,37 @@ import { MarkdownData, ParseMode } from "./types/types"
|
|||
const slugifyIt = (s: string) => slugify(s, { lower: true, strict: true })
|
||||
|
||||
const md = markdownIt({
|
||||
// https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md
|
||||
highlight: (str, lang) => {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (error) {}
|
||||
}
|
||||
// https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md
|
||||
highlight: (str, lang) => {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
return "" // use external default escaping
|
||||
},
|
||||
html: true,
|
||||
return "" // use external default escaping
|
||||
},
|
||||
html: true,
|
||||
})
|
||||
.use(markdownItTexMath, {
|
||||
engine: katex,
|
||||
delimiters: "dollars",
|
||||
})
|
||||
.use(markdownItAnchor, {
|
||||
permalink: markdownItAnchor.permalink.ariaHidden({
|
||||
placement: "before",
|
||||
symbol: "#",
|
||||
renderHref: (s) => `#${slugifyIt(s)}`,
|
||||
}),
|
||||
slugify: slugifyIt,
|
||||
})
|
||||
.use(markdownItTaskCheckbox)
|
||||
.use(markDownItMark)
|
||||
.use(markdownItSub)
|
||||
.use(markdownItSup)
|
||||
.use(highlightLines)
|
||||
.use(markdownItFootnote)
|
||||
.use(markdownItTexMath, {
|
||||
engine: katex,
|
||||
delimiters: "dollars",
|
||||
})
|
||||
.use(markdownItAnchor, {
|
||||
permalink: markdownItAnchor.permalink.ariaHidden({
|
||||
placement: "before",
|
||||
symbol: "#",
|
||||
renderHref: (s) => `#${slugifyIt(s)}`,
|
||||
}),
|
||||
slugify: slugifyIt,
|
||||
})
|
||||
.use(markdownItTaskCheckbox)
|
||||
.use(markDownItMark)
|
||||
.use(markdownItSub)
|
||||
.use(markdownItSup)
|
||||
.use(highlightLines)
|
||||
.use(markdownItFootnote)
|
||||
|
||||
/**
|
||||
* parse the front matter if it exists
|
||||
|
@ -64,70 +64,70 @@ const md = markdownIt({
|
|||
* @param {ParseMode} mode
|
||||
*/
|
||||
export default function parseMarkdown(
|
||||
markdownRaw: string,
|
||||
path: string,
|
||||
mode: ParseMode
|
||||
markdownRaw: string,
|
||||
path: string,
|
||||
mode: ParseMode
|
||||
): MarkdownData {
|
||||
const fileHasFrontMatter = markdownRaw.startsWith("---")
|
||||
const fileHasFrontMatter = markdownRaw.startsWith("---")
|
||||
|
||||
const frontMatter = fileHasFrontMatter
|
||||
? matter(markdownRaw.slice(0, nthIndex(markdownRaw, "---", 2) + 3)).data
|
||||
: {}
|
||||
const frontMatter = fileHasFrontMatter
|
||||
? matter(markdownRaw.slice(0, nthIndex(markdownRaw, "---", 2) + 3)).data
|
||||
: {}
|
||||
|
||||
if (fileHasFrontMatter) {
|
||||
if (mode != ParseMode.PORTFOLIO) {
|
||||
if (!frontMatter.title)
|
||||
throw Error(`Title is not defined in file: ${path}`)
|
||||
if (fileHasFrontMatter) {
|
||||
if (mode != ParseMode.PORTFOLIO) {
|
||||
if (!frontMatter.title)
|
||||
throw Error(`Title is not defined in file: ${path}`)
|
||||
|
||||
if (mode != ParseMode.UNSEARCHABLE && !frontMatter.date)
|
||||
throw Error(`Date is not defined in file: ${path}`)
|
||||
}
|
||||
if (mode != ParseMode.UNSEARCHABLE && !frontMatter.date)
|
||||
throw Error(`Date is not defined in file: ${path}`)
|
||||
}
|
||||
|
||||
if (mode === ParseMode.PORTFOLIO) {
|
||||
if (frontMatter.overview) {
|
||||
frontMatter.overview = md.render(frontMatter.overview)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode === ParseMode.PORTFOLIO) {
|
||||
if (frontMatter.overview) {
|
||||
frontMatter.overview = md.render(frontMatter.overview)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// work with rendered DOM
|
||||
//
|
||||
//
|
||||
// work with rendered DOM
|
||||
//
|
||||
|
||||
const dom = new JSDOM(
|
||||
md.render(
|
||||
fileHasFrontMatter
|
||||
? markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)
|
||||
: markdownRaw
|
||||
) || ""
|
||||
)
|
||||
const dom = new JSDOM(
|
||||
md.render(
|
||||
fileHasFrontMatter
|
||||
? markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)
|
||||
: markdownRaw
|
||||
) || ""
|
||||
)
|
||||
|
||||
// add .hljs class to all block codes
|
||||
// add .hljs class to all block codes
|
||||
|
||||
dom.window.document.querySelectorAll("pre > code").forEach((item) => {
|
||||
item.classList.add("hljs")
|
||||
})
|
||||
dom.window.document.querySelectorAll("pre > code").forEach((item) => {
|
||||
item.classList.add("hljs")
|
||||
})
|
||||
|
||||
// add parent div to tables (horizontally scroll table on small displays)
|
||||
// add parent div to tables (horizontally scroll table on small displays)
|
||||
|
||||
dom.window.document.querySelectorAll("table").forEach((item) => {
|
||||
// `element` is the element you want to wrap
|
||||
const parent = item.parentNode
|
||||
if (!parent) return // stop if table doesn't have a parent node
|
||||
const wrapper = dom.window.document.createElement("div")
|
||||
wrapper.style.overflowX = "auto"
|
||||
dom.window.document.querySelectorAll("table").forEach((item) => {
|
||||
// `element` is the element you want to wrap
|
||||
const parent = item.parentNode
|
||||
if (!parent) return // stop if table doesn't have a parent node
|
||||
const wrapper = dom.window.document.createElement("div")
|
||||
wrapper.style.overflowX = "auto"
|
||||
|
||||
parent.replaceChild(wrapper, item)
|
||||
wrapper.appendChild(item)
|
||||
})
|
||||
parent.replaceChild(wrapper, item)
|
||||
wrapper.appendChild(item)
|
||||
})
|
||||
|
||||
frontMatter.content = dom.window.document.documentElement.innerHTML
|
||||
frontMatter.content = dom.window.document.documentElement.innerHTML
|
||||
|
||||
return frontMatter as MarkdownData
|
||||
return frontMatter as MarkdownData
|
||||
}
|
||||
|
||||
export function generateToc(markdownRaw: string): string {
|
||||
return md.render(toc(markdownRaw).content, {
|
||||
slugify: slugifyIt,
|
||||
})
|
||||
return md.render(toc(markdownRaw).content, {
|
||||
slugify: slugifyIt,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
{
|
||||
"Programming Languages": [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"python",
|
||||
"rust",
|
||||
"csharp C#"
|
||||
],
|
||||
"Web Front End": ["react", "svelte", "tailwindcss Tailwind"],
|
||||
"Desktop Front End": ["gtk", "electron", "tauri"],
|
||||
"Back End": ["firebase"],
|
||||
"DevOps": ["docker", "githubactions GH Actions"],
|
||||
"Game Development": ["unity"],
|
||||
"Etc": [
|
||||
"figma",
|
||||
"markdown",
|
||||
"notion",
|
||||
"google Google-Fu",
|
||||
"discord Discord Bot"
|
||||
]
|
||||
"Programming Languages": [
|
||||
"javascript",
|
||||
"typescript",
|
||||
"python",
|
||||
"rust",
|
||||
"csharp C#"
|
||||
],
|
||||
"Web Front End": ["react", "svelte", "tailwindcss Tailwind"],
|
||||
"Desktop Front End": ["gtk", "electron", "tauri"],
|
||||
"Back End": ["firebase"],
|
||||
"DevOps": ["docker", "githubactions GH Actions"],
|
||||
"Game Development": ["unity"],
|
||||
"Etc": [
|
||||
"figma",
|
||||
"markdown",
|
||||
"notion",
|
||||
"google Google-Fu",
|
||||
"discord Discord Bot"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
svg {
|
||||
/* from github */
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
|
||||
sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
/* from github */
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
|
||||
sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
h1,
|
||||
|
@ -12,50 +12,50 @@ h3,
|
|||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.items-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
|
||||
column-gap: 10px;
|
||||
row-gap: 15px;
|
||||
column-gap: 10px;
|
||||
row-gap: 15px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
gap: 5px;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.badge-box {
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 7px;
|
||||
border-radius: 7px;
|
||||
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.icon-container > svg {
|
||||
height: 40px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: white;
|
||||
fill: white;
|
||||
color: white;
|
||||
fill: white;
|
||||
}
|
||||
|
||||
.black {
|
||||
color: black;
|
||||
fill: black;
|
||||
color: black;
|
||||
fill: black;
|
||||
}
|
||||
|
|
|
@ -12,127 +12,127 @@ import skills from "./portfolio/skills.json"
|
|||
import { writeToFile } from "./util"
|
||||
|
||||
export default function postProcess() {
|
||||
sortDates()
|
||||
fillTags()
|
||||
parseSeries()
|
||||
generatePortfolioSVGs()
|
||||
sortDates()
|
||||
fillTags()
|
||||
parseSeries()
|
||||
generatePortfolioSVGs()
|
||||
}
|
||||
|
||||
function sortDates() {
|
||||
const TmpDate = contentMap.date
|
||||
contentMap.date = {}
|
||||
Object.keys(TmpDate)
|
||||
.sort()
|
||||
.forEach((sortedDateKey) => {
|
||||
contentMap.date[sortedDateKey] = TmpDate[sortedDateKey]
|
||||
})
|
||||
const TmpDate = contentMap.date
|
||||
contentMap.date = {}
|
||||
Object.keys(TmpDate)
|
||||
.sort()
|
||||
.forEach((sortedDateKey) => {
|
||||
contentMap.date[sortedDateKey] = TmpDate[sortedDateKey]
|
||||
})
|
||||
}
|
||||
|
||||
function fillTags() {
|
||||
contentMap.meta.tags = Object.keys(contentMap.tags)
|
||||
contentMap.meta.tags = Object.keys(contentMap.tags)
|
||||
}
|
||||
|
||||
function parseSeries() {
|
||||
// sort series map
|
||||
for (const seriesURL in seriesMap) {
|
||||
seriesMap[seriesURL].sort((a, b) => {
|
||||
if (a.index < b.index) return -1
|
||||
if (a.index > b.index) return 1
|
||||
// sort series map
|
||||
for (const seriesURL in seriesMap) {
|
||||
seriesMap[seriesURL].sort((a, b) => {
|
||||
if (a.index < b.index) return -1
|
||||
if (a.index > b.index) return 1
|
||||
|
||||
return 0
|
||||
})
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
// series length and order
|
||||
for (const seriesURL in seriesMap) {
|
||||
contentMap.series[seriesURL].length = seriesMap[seriesURL].length
|
||||
contentMap.series[seriesURL].order = seriesMap[seriesURL].map(
|
||||
(item) => item.url
|
||||
)
|
||||
}
|
||||
// series length and order
|
||||
for (const seriesURL in seriesMap) {
|
||||
contentMap.series[seriesURL].length = seriesMap[seriesURL].length
|
||||
contentMap.series[seriesURL].order = seriesMap[seriesURL].map(
|
||||
(item) => item.url
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function generatePortfolioSVGs() {
|
||||
/**
|
||||
* render skills.svg
|
||||
*/
|
||||
/**
|
||||
* render skills.svg
|
||||
*/
|
||||
|
||||
// todo: wait add ejs once it's available
|
||||
// todo: wait add ejs once it's available
|
||||
|
||||
const style = readFileSync("./src/portfolio/style.css", "utf-8")
|
||||
const style = readFileSync("./src/portfolio/style.css", "utf-8")
|
||||
|
||||
const data: {
|
||||
[key: string]: Badge[] | { [key: string]: Badge[] }
|
||||
} = {}
|
||||
const data: {
|
||||
[key: string]: Badge[] | { [key: string]: Badge[] }
|
||||
} = {}
|
||||
|
||||
// C O G N I T O - H A Z A R D
|
||||
// THIS PART OF THE CODE WAS WRITTEN IN 3 AM
|
||||
// C O G N I T O - H A Z A R D
|
||||
// C O G N I T O - H A Z A R D
|
||||
// THIS PART OF THE CODE WAS WRITTEN IN 3 AM
|
||||
// C O G N I T O - H A Z A R D
|
||||
|
||||
for (const key in skills) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (skills[key] instanceof Array) {
|
||||
if (!data[key]) {
|
||||
data[key] = []
|
||||
}
|
||||
for (const key in skills) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (skills[key] instanceof Array) {
|
||||
if (!data[key]) {
|
||||
data[key] = []
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
;(skills[key] as string[]).forEach((badge) =>
|
||||
(data[key] as Badge[]).push(parseBadge(badge))
|
||||
)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
for (const subKey in skills[key]) {
|
||||
if (!data[key]) data[key] = {}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
;(skills[key] as string[]).forEach((badge) =>
|
||||
(data[key] as Badge[]).push(parseBadge(badge))
|
||||
)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
for (const subKey in skills[key]) {
|
||||
if (!data[key]) data[key] = {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (!data[key][subKey]) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
data[key][subKey] = []
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
if (!data[key][subKey]) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
data[key][subKey] = []
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
skills[key][subKey].forEach((badge: string) =>
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
(data[key][subKey] as Badge[]).push(parseBadge(badge))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
skills[key][subKey].forEach((badge: string) =>
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
(data[key][subKey] as Badge[]).push(parseBadge(badge))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const renderedSVG = ejs.render(
|
||||
readFileSync("./src/portfolio/skills.ejs", "utf-8"),
|
||||
{ style, data },
|
||||
{ views: ["./src/portfolio"] }
|
||||
)
|
||||
const renderedSVG = ejs.render(
|
||||
readFileSync("./src/portfolio/skills.ejs", "utf-8"),
|
||||
{ style, data },
|
||||
{ views: ["./src/portfolio"] }
|
||||
)
|
||||
|
||||
writeToFile(
|
||||
"./dist/public/img/skills.svg",
|
||||
optimize(renderedSVG, { multipass: true }).data
|
||||
)
|
||||
writeToFile(
|
||||
"./dist/public/img/skills.svg",
|
||||
optimize(renderedSVG, { multipass: true }).data
|
||||
)
|
||||
}
|
||||
|
||||
function parseBadge(badgeRaw: string): Badge {
|
||||
const isMultiWord = badgeRaw.includes(" ")
|
||||
const words = badgeRaw.split(" ")
|
||||
const slug = words[0]
|
||||
const isMultiWord = badgeRaw.includes(" ")
|
||||
const words = badgeRaw.split(" ")
|
||||
const slug = words[0]
|
||||
|
||||
// @ts-ignore
|
||||
const icon = icons["si" + slug[0].toUpperCase() + slug.slice(1)]
|
||||
// @ts-ignore
|
||||
const icon = icons["si" + slug[0].toUpperCase() + slug.slice(1)]
|
||||
|
||||
const color = tinycolor(icon.hex).lighten(5).desaturate(5)
|
||||
const color = tinycolor(icon.hex).lighten(5).desaturate(5)
|
||||
|
||||
return {
|
||||
svg: icon.svg,
|
||||
hex: color.toHexString(),
|
||||
isDark: color.isDark(),
|
||||
title: isMultiWord ? words.slice(1).join(" ") : icon.title,
|
||||
}
|
||||
return {
|
||||
svg: icon.svg,
|
||||
hex: color.toHexString(),
|
||||
isDark: color.isDark(),
|
||||
title: isMultiWord ? words.slice(1).join(" ") : icon.title,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@ import { ParseMode } from "../types/types"
|
|||
* Data that's passed from {@link parseFile} to other function
|
||||
*/
|
||||
export interface DataToPass {
|
||||
path: string
|
||||
urlPath: string
|
||||
markdownRaw: string
|
||||
markdownData: {
|
||||
content: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
humanizedDuration: string
|
||||
totalWords: number
|
||||
path: string
|
||||
urlPath: string
|
||||
markdownRaw: string
|
||||
markdownData: {
|
||||
content: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
humanizedDuration: string
|
||||
totalWords: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,23 +33,23 @@ export interface DataToPass {
|
|||
* @param {string} path - path of file or folder
|
||||
*/
|
||||
export function recursiveParse(mode: ParseMode, path: string): void {
|
||||
// get name of the file or folder that's currently being parsed
|
||||
const fileOrFolderName = path2FileOrFolderName(path)
|
||||
// get name of the file or folder that's currently being parsed
|
||||
const fileOrFolderName = path2FileOrFolderName(path)
|
||||
|
||||
// stop if the file or folder starts with a underscore
|
||||
if (fileOrFolderName.startsWith("_")) return
|
||||
// stop if the file or folder starts with a underscore
|
||||
if (fileOrFolderName.startsWith("_")) return
|
||||
|
||||
const stats = fs.lstatSync(path)
|
||||
const stats = fs.lstatSync(path)
|
||||
|
||||
// if it's a directory, call this function to every files/directories in it
|
||||
// if it's a file, parse it and then save it to file
|
||||
if (stats.isDirectory()) {
|
||||
fs.readdirSync(path).map((childPath) => {
|
||||
recursiveParse(mode, `${path}/${childPath}`)
|
||||
})
|
||||
} else if (stats.isFile()) {
|
||||
parseFile(mode, path)
|
||||
}
|
||||
// if it's a directory, call this function to every files/directories in it
|
||||
// if it's a file, parse it and then save it to file
|
||||
if (stats.isDirectory()) {
|
||||
fs.readdirSync(path).map((childPath) => {
|
||||
recursiveParse(mode, `${path}/${childPath}`)
|
||||
})
|
||||
} else if (stats.isFile()) {
|
||||
parseFile(mode, path)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,50 +59,50 @@ export function recursiveParse(mode: ParseMode, path: string): void {
|
|||
* @param {string} path - path of the markdown file
|
||||
*/
|
||||
function parseFile(mode: ParseMode, path: string): void {
|
||||
// stop if it is not a markdown file
|
||||
if (!path.endsWith(".md")) {
|
||||
console.log(`Ignoring non markdown file at: ${path}`)
|
||||
return
|
||||
}
|
||||
// stop if it is not a markdown file
|
||||
if (!path.endsWith(".md")) {
|
||||
console.log(`Ignoring non markdown file at: ${path}`)
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse markdown
|
||||
*/
|
||||
/**
|
||||
* Parse markdown
|
||||
*/
|
||||
|
||||
const markdownRaw = fs.readFileSync(path, "utf8")
|
||||
const markdownData = parseMarkdown(markdownRaw, path, mode)
|
||||
const { humanizedDuration, totalWords } = readTimeEstimate(
|
||||
markdownData.content,
|
||||
275,
|
||||
12,
|
||||
500,
|
||||
["img", "Image"]
|
||||
)
|
||||
const markdownRaw = fs.readFileSync(path, "utf8")
|
||||
const markdownData = parseMarkdown(markdownRaw, path, mode)
|
||||
const { humanizedDuration, totalWords } = readTimeEstimate(
|
||||
markdownData.content,
|
||||
275,
|
||||
12,
|
||||
500,
|
||||
["img", "Image"]
|
||||
)
|
||||
|
||||
const dataToPass: DataToPass = {
|
||||
path,
|
||||
urlPath: path2URL(path),
|
||||
markdownRaw,
|
||||
markdownData,
|
||||
humanizedDuration,
|
||||
totalWords,
|
||||
}
|
||||
const dataToPass: DataToPass = {
|
||||
path,
|
||||
urlPath: path2URL(path),
|
||||
markdownRaw,
|
||||
markdownData,
|
||||
humanizedDuration,
|
||||
totalWords,
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case ParseMode.POSTS:
|
||||
parsePost(dataToPass)
|
||||
break
|
||||
switch (mode) {
|
||||
case ParseMode.POSTS:
|
||||
parsePost(dataToPass)
|
||||
break
|
||||
|
||||
case ParseMode.SERIES:
|
||||
parseSeries(dataToPass)
|
||||
break
|
||||
case ParseMode.SERIES:
|
||||
parseSeries(dataToPass)
|
||||
break
|
||||
|
||||
case ParseMode.UNSEARCHABLE:
|
||||
parseUnsearchable(dataToPass)
|
||||
break
|
||||
case ParseMode.UNSEARCHABLE:
|
||||
parseUnsearchable(dataToPass)
|
||||
break
|
||||
|
||||
case ParseMode.PORTFOLIO:
|
||||
parseProjects(dataToPass)
|
||||
break
|
||||
}
|
||||
case ParseMode.PORTFOLIO:
|
||||
parseProjects(dataToPass)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,65 +8,70 @@ import { DataToPass } from "."
|
|||
import { PostData } from "../types/types"
|
||||
|
||||
export default function parsePost(data: DataToPass): void {
|
||||
const { urlPath, markdownRaw, markdownData, humanizedDuration, totalWords } =
|
||||
data
|
||||
const {
|
||||
urlPath,
|
||||
markdownRaw,
|
||||
markdownData,
|
||||
humanizedDuration,
|
||||
totalWords,
|
||||
} = data
|
||||
|
||||
const postData: PostData = {
|
||||
title: markdownData.title as string,
|
||||
date: "",
|
||||
readTime: humanizedDuration,
|
||||
wordCount: totalWords,
|
||||
tags: [],
|
||||
}
|
||||
const postData: PostData = {
|
||||
title: markdownData.title as string,
|
||||
date: "",
|
||||
readTime: humanizedDuration,
|
||||
wordCount: totalWords,
|
||||
tags: [],
|
||||
}
|
||||
|
||||
/**
|
||||
* Dates
|
||||
*/
|
||||
/**
|
||||
* Dates
|
||||
*/
|
||||
|
||||
const postDate = new Date(markdownData.date as string)
|
||||
postData.date = postDate.toLocaleString("default", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
const postDate = new Date(markdownData.date as string)
|
||||
postData.date = postDate.toLocaleString("default", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
|
||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||
if (contentMap.date[YYYY_MM_DD]) {
|
||||
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||
} else {
|
||||
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||
}
|
||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||
if (contentMap.date[YYYY_MM_DD]) {
|
||||
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||
} else {
|
||||
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags
|
||||
*/
|
||||
/**
|
||||
* Tags
|
||||
*/
|
||||
|
||||
postData.tags = markdownData.tags as string[]
|
||||
if (postData.tags) {
|
||||
postData.tags.forEach((tag) => {
|
||||
if (contentMap.tags[tag]) {
|
||||
contentMap.tags[tag].push(urlPath)
|
||||
} else {
|
||||
contentMap.tags[tag] = [urlPath]
|
||||
}
|
||||
})
|
||||
}
|
||||
postData.tags = markdownData.tags as string[]
|
||||
if (postData.tags) {
|
||||
postData.tags.forEach((tag) => {
|
||||
if (contentMap.tags[tag]) {
|
||||
contentMap.tags[tag].push(urlPath)
|
||||
} else {
|
||||
contentMap.tags[tag] = [urlPath]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
contentMap.posts[urlPath] = postData
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
contentMap.posts[urlPath] = postData
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,46 +9,46 @@ import { portfolioData } from ".."
|
|||
import { DataToPass } from "."
|
||||
|
||||
export default function parseProjects(data: DataToPass): void {
|
||||
const { urlPath, markdownRaw, markdownData } = data
|
||||
const { urlPath, markdownRaw, markdownData } = data
|
||||
|
||||
if (markdownData.badges) {
|
||||
;(markdownData.badges as string[]).forEach((slug) => {
|
||||
// todo: handle cases when icon is not on simple-icons
|
||||
const icon: SimpleIcon =
|
||||
// @ts-ignore
|
||||
icons["si" + slug[0].toUpperCase() + slug.slice(1)]
|
||||
if (markdownData.badges) {
|
||||
;(markdownData.badges as string[]).forEach((slug) => {
|
||||
// todo: handle cases when icon is not on simple-icons
|
||||
const icon: SimpleIcon =
|
||||
// @ts-ignore
|
||||
icons["si" + slug[0].toUpperCase() + slug.slice(1)]
|
||||
|
||||
portfolioData.skills.add(slug)
|
||||
portfolioData.skills.add(slug)
|
||||
|
||||
const color = tinycolor(icon.hex).lighten(5).desaturate(5)
|
||||
const color = tinycolor(icon.hex).lighten(5).desaturate(5)
|
||||
|
||||
// save svg icon
|
||||
writeToFile(
|
||||
`${iconsDirectoryPath}/${icon.slug}.json`,
|
||||
JSON.stringify({
|
||||
svg: icon.svg,
|
||||
hex: color.toHexString(),
|
||||
isDark: color.isDark(),
|
||||
title: icon.title,
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
// save svg icon
|
||||
writeToFile(
|
||||
`${iconsDirectoryPath}/${icon.slug}.json`,
|
||||
JSON.stringify({
|
||||
svg: icon.svg,
|
||||
hex: color.toHexString(),
|
||||
isDark: color.isDark(),
|
||||
title: icon.title,
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// remove /projects/ prefix
|
||||
portfolioData.projects[urlPath.replace("/projects/", "")] = {
|
||||
name: markdownData.name as string,
|
||||
image: markdownData.image as string,
|
||||
overview: markdownData.overview as string,
|
||||
badges: (markdownData.badges as string[]) || [],
|
||||
repo: (markdownData.repo as string) || "",
|
||||
}
|
||||
// remove /projects/ prefix
|
||||
portfolioData.projects[urlPath.replace("/projects/", "")] = {
|
||||
name: markdownData.name as string,
|
||||
image: markdownData.image as string,
|
||||
overview: markdownData.overview as string,
|
||||
badges: (markdownData.badges as string[]) || [],
|
||||
repo: (markdownData.repo as string) || "",
|
||||
}
|
||||
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,140 +8,141 @@ import { DataToPass } from "."
|
|||
import { PostData } from "../types/types"
|
||||
|
||||
export default function parseSeries(data: DataToPass): void {
|
||||
const {
|
||||
path,
|
||||
urlPath: _urlPath,
|
||||
markdownRaw,
|
||||
markdownData,
|
||||
humanizedDuration,
|
||||
totalWords,
|
||||
} = data
|
||||
const {
|
||||
path,
|
||||
urlPath: _urlPath,
|
||||
markdownRaw,
|
||||
markdownData,
|
||||
humanizedDuration,
|
||||
totalWords,
|
||||
} = data
|
||||
|
||||
// last part of the url without the slash
|
||||
let lastPath = _urlPath.slice(_urlPath.lastIndexOf("/") + 1)
|
||||
if (!lastPath.includes("_") && !lastPath.startsWith("0"))
|
||||
throw Error(`Invalid series file name at: "${path}"`)
|
||||
// last part of the url without the slash
|
||||
let lastPath = _urlPath.slice(_urlPath.lastIndexOf("/") + 1)
|
||||
if (!lastPath.includes("_") && !lastPath.startsWith("0"))
|
||||
throw Error(`Invalid series file name at: "${path}"`)
|
||||
|
||||
// if file is a series descriptor or not (not = regular series post)
|
||||
const isFileDescriptor = lastPath.startsWith("0") && !lastPath.includes("_")
|
||||
// if file is a series descriptor or not (not = regular series post)
|
||||
const isFileDescriptor = lastPath.startsWith("0") && !lastPath.includes("_")
|
||||
|
||||
// series post url
|
||||
if (isFileDescriptor) {
|
||||
lastPath = ""
|
||||
} else {
|
||||
lastPath = lastPath
|
||||
.slice(lastPath.indexOf("_") + 1) // get string after the series index
|
||||
.replace(/\/$/, "") // remove trailing slash
|
||||
}
|
||||
// series post url
|
||||
if (isFileDescriptor) {
|
||||
lastPath = ""
|
||||
} else {
|
||||
lastPath = lastPath
|
||||
.slice(lastPath.indexOf("_") + 1) // get string after the series index
|
||||
.replace(/\/$/, "") // remove trailing slash
|
||||
}
|
||||
|
||||
// get url until right before the lastPath
|
||||
const urlUntilLastPath = _urlPath.slice(0, _urlPath.lastIndexOf("/") + 1)
|
||||
// get url until right before the lastPath
|
||||
const urlUntilLastPath = _urlPath.slice(0, _urlPath.lastIndexOf("/") + 1)
|
||||
|
||||
// remove trailing slash if it's a regular series post
|
||||
const urlPath =
|
||||
(isFileDescriptor
|
||||
? urlUntilLastPath.replace(/\/$/, "")
|
||||
: urlUntilLastPath) + lastPath
|
||||
// remove trailing slash if it's a regular series post
|
||||
const urlPath =
|
||||
(isFileDescriptor
|
||||
? urlUntilLastPath.replace(/\/$/, "")
|
||||
: urlUntilLastPath) + lastPath
|
||||
|
||||
// todo: separate interface for series descriptor (no word count and read time)
|
||||
const postData: PostData = {
|
||||
title: markdownData.title as string,
|
||||
date: "",
|
||||
readTime: humanizedDuration,
|
||||
wordCount: totalWords,
|
||||
tags: [],
|
||||
}
|
||||
// todo: separate interface for series descriptor (no word count and read time)
|
||||
const postData: PostData = {
|
||||
title: markdownData.title as string,
|
||||
date: "",
|
||||
readTime: humanizedDuration,
|
||||
wordCount: totalWords,
|
||||
tags: [],
|
||||
}
|
||||
|
||||
/**
|
||||
* Date
|
||||
*/
|
||||
/**
|
||||
* Date
|
||||
*/
|
||||
|
||||
const postDate = new Date(markdownData.date as string)
|
||||
postData.date = postDate.toLocaleString("default", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
const postDate = new Date(markdownData.date as string)
|
||||
postData.date = postDate.toLocaleString("default", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
|
||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||
if (contentMap.date[YYYY_MM_DD]) {
|
||||
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||
} else {
|
||||
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||
}
|
||||
const YYYY_MM_DD = postDate.toISOString().split("T")[0]
|
||||
if (contentMap.date[YYYY_MM_DD]) {
|
||||
contentMap.date[YYYY_MM_DD].push(urlPath)
|
||||
} else {
|
||||
contentMap.date[YYYY_MM_DD] = [urlPath]
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags
|
||||
*/
|
||||
/**
|
||||
* Tags
|
||||
*/
|
||||
|
||||
postData.tags = markdownData.tags as string[]
|
||||
if (postData.tags) {
|
||||
postData.tags.forEach((tag) => {
|
||||
if (contentMap.tags[tag]) {
|
||||
contentMap.tags[tag].push(urlPath)
|
||||
} else {
|
||||
contentMap.tags[tag] = [urlPath]
|
||||
}
|
||||
})
|
||||
}
|
||||
postData.tags = markdownData.tags as string[]
|
||||
if (postData.tags) {
|
||||
postData.tags.forEach((tag) => {
|
||||
if (contentMap.tags[tag]) {
|
||||
contentMap.tags[tag].push(urlPath)
|
||||
} else {
|
||||
contentMap.tags[tag] = [urlPath]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
|
||||
contentMap.posts[urlPath] = postData
|
||||
contentMap.posts[urlPath] = postData
|
||||
|
||||
// series markdown starting with 0 is a series descriptor
|
||||
if (isFileDescriptor) {
|
||||
contentMap.series[urlPath] = {
|
||||
...postData,
|
||||
order: [],
|
||||
length: 0,
|
||||
}
|
||||
} else {
|
||||
// put series post in appropriate series
|
||||
for (const key of Object.keys(contentMap.series)) {
|
||||
if (urlPath.includes(key)) {
|
||||
const index = parseInt(
|
||||
_urlPath.slice(
|
||||
_urlPath.lastIndexOf("/") + 1,
|
||||
_urlPath.lastIndexOf("_")
|
||||
)
|
||||
)
|
||||
// series markdown starting with 0 is a series descriptor
|
||||
if (isFileDescriptor) {
|
||||
contentMap.series[urlPath] = {
|
||||
...postData,
|
||||
order: [],
|
||||
length: 0,
|
||||
}
|
||||
} else {
|
||||
// put series post in appropriate series
|
||||
for (const key of Object.keys(contentMap.series)) {
|
||||
if (urlPath.includes(key)) {
|
||||
const index = parseInt(
|
||||
_urlPath.slice(
|
||||
_urlPath.lastIndexOf("/") + 1,
|
||||
_urlPath.lastIndexOf("_")
|
||||
)
|
||||
)
|
||||
|
||||
if (isNaN(index)) throw Error(`Invalid series index at: ${path}`)
|
||||
if (isNaN(index))
|
||||
throw Error(`Invalid series index at: ${path}`)
|
||||
|
||||
const itemToPush = {
|
||||
index: index,
|
||||
url: urlPath,
|
||||
}
|
||||
const itemToPush = {
|
||||
index: index,
|
||||
url: urlPath,
|
||||
}
|
||||
|
||||
if (seriesMap[key]) {
|
||||
seriesMap[key].push(itemToPush)
|
||||
} else {
|
||||
seriesMap[key] = [itemToPush]
|
||||
}
|
||||
if (seriesMap[key]) {
|
||||
seriesMap[key].push(itemToPush)
|
||||
} else {
|
||||
seriesMap[key] = [itemToPush]
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save content
|
||||
*/
|
||||
/**
|
||||
* Save content
|
||||
*/
|
||||
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
toc: generateToc(markdownRaw),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,30 +5,30 @@ import { contentMap } from ".."
|
|||
import { DataToPass } from "."
|
||||
|
||||
export default function parseUnsearchable(data: DataToPass): void {
|
||||
const { urlPath: _urlPath, markdownData } = data
|
||||
const { urlPath: _urlPath, markdownData } = data
|
||||
|
||||
// convert path like /XXX/YYY/ZZZ to /YYY/ZZZ
|
||||
const urlPath = _urlPath.slice(_urlPath.slice(1).indexOf("/") + 1)
|
||||
// convert path like /XXX/YYY/ZZZ to /YYY/ZZZ
|
||||
const urlPath = _urlPath.slice(_urlPath.slice(1).indexOf("/") + 1)
|
||||
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
addDocument({
|
||||
title: markdownData.title,
|
||||
body: markdownData.content,
|
||||
url: urlPath,
|
||||
})
|
||||
|
||||
// Parse data that will be written to map.js
|
||||
contentMap.unsearchable[urlPath] = {
|
||||
title: markdownData.title as string,
|
||||
}
|
||||
// Parse data that will be written to map.js
|
||||
contentMap.unsearchable[urlPath] = {
|
||||
title: markdownData.title as string,
|
||||
}
|
||||
|
||||
/**
|
||||
* Save content
|
||||
*/
|
||||
/**
|
||||
* Save content
|
||||
*/
|
||||
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}/unsearchable${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
})
|
||||
)
|
||||
writeToFile(
|
||||
`${contentDirectoryPath}/unsearchable${urlPath}.json`,
|
||||
JSON.stringify({
|
||||
content: markdownData.content,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,19 +8,19 @@ import elasticlunr from "elasticlunr"
|
|||
import { searchIndexFilePath } from "./config"
|
||||
|
||||
const elasticlunrIndex = elasticlunr(function () {
|
||||
this.addField("title" as never)
|
||||
this.addField("body" as never)
|
||||
this.setRef("url" as never)
|
||||
this.addField("title" as never)
|
||||
this.addField("body" as never)
|
||||
this.setRef("url" as never)
|
||||
})
|
||||
|
||||
export function addDocument(doc: {
|
||||
title?: unknown
|
||||
body?: string
|
||||
url?: string
|
||||
title?: unknown
|
||||
body?: string
|
||||
url?: string
|
||||
}) {
|
||||
elasticlunrIndex.addDoc(doc)
|
||||
elasticlunrIndex.addDoc(doc)
|
||||
}
|
||||
|
||||
export function saveIndex() {
|
||||
fs.writeFileSync(searchIndexFilePath, JSON.stringify(elasticlunrIndex))
|
||||
fs.writeFileSync(searchIndexFilePath, JSON.stringify(elasticlunrIndex))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
declare module "markdown-it-texmath" {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default function texmath(md: MarkdownIt, ...params: any[]): void
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default function texmath(md: MarkdownIt, ...params: any[]): void
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
declare module "markdown-toc" {
|
||||
export default function toc(str: string): {
|
||||
json: JSON
|
||||
content: string
|
||||
}
|
||||
export default function toc(str: string): {
|
||||
json: JSON
|
||||
content: string
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
export interface ContentMap {
|
||||
// key: YYYY-MM-DD
|
||||
// value: url
|
||||
date: { [key: string]: string[] }
|
||||
// key: YYYY-MM-DD
|
||||
// value: url
|
||||
date: { [key: string]: string[] }
|
||||
|
||||
// key: tag name
|
||||
// value: url
|
||||
tags: {
|
||||
[key: string]: string[]
|
||||
}
|
||||
// key: tag name
|
||||
// value: url
|
||||
tags: {
|
||||
[key: string]: string[]
|
||||
}
|
||||
|
||||
// list of all meta data
|
||||
meta: {
|
||||
tags: string[]
|
||||
}
|
||||
// list of all meta data
|
||||
meta: {
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
// searchable, non-series posts
|
||||
// must have a post date
|
||||
// tag is not required
|
||||
posts: {
|
||||
[key: string]: PostData
|
||||
}
|
||||
// searchable, non-series posts
|
||||
// must have a post date
|
||||
// tag is not required
|
||||
posts: {
|
||||
[key: string]: PostData
|
||||
}
|
||||
|
||||
// series posts have "previous post" and "next post" button so they need to be ordered
|
||||
series: { [key: string]: Series }
|
||||
// series posts have "previous post" and "next post" button so they need to be ordered
|
||||
series: { [key: string]: Series }
|
||||
|
||||
// urls of unsearchable posts
|
||||
// it is here to quickly check if a post exists or not
|
||||
unsearchable: { [key: string]: { title: string } }
|
||||
// urls of unsearchable posts
|
||||
// it is here to quickly check if a post exists or not
|
||||
unsearchable: { [key: string]: { title: string } }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,58 +34,58 @@ export interface ContentMap {
|
|||
*/
|
||||
|
||||
export enum ParseMode {
|
||||
POSTS,
|
||||
SERIES,
|
||||
UNSEARCHABLE,
|
||||
PORTFOLIO,
|
||||
POSTS,
|
||||
SERIES,
|
||||
UNSEARCHABLE,
|
||||
PORTFOLIO,
|
||||
}
|
||||
|
||||
export interface MarkdownData {
|
||||
content: string
|
||||
[key: string]: unknown
|
||||
content: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface PostData {
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
tags?: string[]
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
tags?: string[]
|
||||
}
|
||||
|
||||
export interface PageData {
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
tags: string[]
|
||||
toc?: string
|
||||
content: string
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
tags: string[]
|
||||
toc?: string
|
||||
content: string
|
||||
|
||||
// series
|
||||
// series
|
||||
|
||||
seriesHome: string
|
||||
prev?: string
|
||||
next?: string
|
||||
seriesHome: string
|
||||
prev?: string
|
||||
next?: string
|
||||
|
||||
// series home
|
||||
// series home
|
||||
|
||||
order: string[]
|
||||
length: number
|
||||
order: string[]
|
||||
length: number
|
||||
|
||||
// portfolio
|
||||
// portfolio
|
||||
|
||||
image: string // image url
|
||||
overview: string
|
||||
badges: string[]
|
||||
repo: string
|
||||
image: string // image url
|
||||
overview: string
|
||||
badges: string[]
|
||||
repo: string
|
||||
}
|
||||
|
||||
export interface Badge {
|
||||
svg: string
|
||||
hex: string
|
||||
isDark: boolean
|
||||
title: string
|
||||
svg: string
|
||||
hex: string
|
||||
isDark: boolean
|
||||
title: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,23 +93,23 @@ export interface Badge {
|
|||
*/
|
||||
|
||||
export interface Series {
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
order: string[]
|
||||
length: number
|
||||
tags?: string[]
|
||||
title: string
|
||||
date: string
|
||||
readTime: string
|
||||
wordCount: number
|
||||
order: string[]
|
||||
length: number
|
||||
tags?: string[]
|
||||
}
|
||||
|
||||
export interface SeriesMap {
|
||||
// key: url
|
||||
[key: string]: SeriesEntry[]
|
||||
// key: url
|
||||
[key: string]: SeriesEntry[]
|
||||
}
|
||||
|
||||
export interface SeriesEntry {
|
||||
index: number
|
||||
url: string
|
||||
index: number
|
||||
url: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,25 +117,25 @@ export interface SeriesEntry {
|
|||
*/
|
||||
|
||||
export interface PortfolioData {
|
||||
// a set of valid simple icons slug
|
||||
skills: Set<string>
|
||||
// a set of valid simple icons slug
|
||||
skills: Set<string>
|
||||
|
||||
// key: url
|
||||
projects: {
|
||||
[key: string]: PortfolioProject
|
||||
}
|
||||
// key: url
|
||||
projects: {
|
||||
[key: string]: PortfolioProject
|
||||
}
|
||||
}
|
||||
|
||||
export interface PortfolioOverview {
|
||||
// link to my github
|
||||
github: string
|
||||
description: string
|
||||
// link to my github
|
||||
github: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface PortfolioProject {
|
||||
name: string
|
||||
image: string // url to the image
|
||||
overview: string
|
||||
badges: string[] // array of valid simpleIcons slug
|
||||
repo: string // url of the git repository
|
||||
name: string
|
||||
image: string // url to the image
|
||||
overview: string
|
||||
badges: string[] // array of valid simpleIcons slug
|
||||
repo: string // url of the git repository
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ import { markdownPath } from "./config"
|
|||
* @param {string} pathToConvert
|
||||
*/
|
||||
export function path2URL(pathToConvert: string): string {
|
||||
return `/${relative(markdownPath, pathToConvert)}`
|
||||
.replace(/\.[^/.]+$/, "") // remove the file extension
|
||||
.replace(/ /g, "-") // replace all space with a dash
|
||||
return `/${relative(markdownPath, pathToConvert)}`
|
||||
.replace(/\.[^/.]+$/, "") // remove the file extension
|
||||
.replace(/ /g, "-") // replace all space with a dash
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,33 +20,34 @@ export function path2URL(pathToConvert: string): string {
|
|||
* @param {string} inputPath - path to parse
|
||||
*/
|
||||
export function path2FileOrFolderName(inputPath: string): string {
|
||||
// remove trailing slash
|
||||
if (inputPath[-1] == "/") inputPath = inputPath.slice(0, inputPath.length - 1)
|
||||
// remove trailing slash
|
||||
if (inputPath[-1] == "/")
|
||||
inputPath = inputPath.slice(0, inputPath.length - 1)
|
||||
|
||||
// get the last section
|
||||
return inputPath.slice(inputPath.lastIndexOf("/") + 1)
|
||||
// get the last section
|
||||
return inputPath.slice(inputPath.lastIndexOf("/") + 1)
|
||||
}
|
||||
|
||||
// gets the nth occurance of a pattern in string
|
||||
// returns -1 if nothing is found
|
||||
// https://stackoverflow.com/a/14482123/12979111
|
||||
export function nthIndex(str: string, pat: string, n: number) {
|
||||
let i = -1
|
||||
let i = -1
|
||||
|
||||
while (n-- && i++ < str.length) {
|
||||
i = str.indexOf(pat, i)
|
||||
if (i < 0) break
|
||||
}
|
||||
while (n-- && i++ < str.length) {
|
||||
i = str.indexOf(pat, i)
|
||||
if (i < 0) break
|
||||
}
|
||||
|
||||
return i
|
||||
return i
|
||||
}
|
||||
|
||||
export function writeToFile(filePath: string, dataToWrite: string) {
|
||||
// create directory to put the files
|
||||
fs.mkdirSync(filePath.slice(0, filePath.lastIndexOf("/")), {
|
||||
recursive: true,
|
||||
})
|
||||
// create directory to put the files
|
||||
fs.mkdirSync(filePath.slice(0, filePath.lastIndexOf("/")), {
|
||||
recursive: true,
|
||||
})
|
||||
|
||||
// write content to the file
|
||||
fs.writeFileSync(filePath, dataToWrite)
|
||||
// write content to the file
|
||||
fs.writeFileSync(filePath, dataToWrite)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"extends": "@developomp-site/tsconfig/node16.json",
|
||||
"include": ["src"],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
},
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"isolatedModules": false,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": ["dist", "node_modules"]
|
||||
"extends": "@developomp-site/tsconfig/node16.json",
|
||||
"include": ["src"],
|
||||
"ts-node": {
|
||||
"esm": true
|
||||
},
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"isolatedModules": false,
|
||||
"noImplicitAny": false,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue