Run lint and prettier
CI Pipeline / test (20) (pull_request) Failing after 8m5s
CI Pipeline / test (18) (pull_request) Failing after 8m36s
CI Pipeline / e2e (chromium) (pull_request) Successful in 2m32s
CI Pipeline / e2e (webkit) (pull_request) Successful in 3m40s
CI Pipeline / e2e (firefox) (pull_request) Successful in 5m43s
CI Pipeline / performance (pull_request) Failing after 3m18s
CI Pipeline / visual-regression (pull_request) Failing after 3m20s
CI Pipeline / lint (pull_request) Successful in 1m7s
CI Pipeline / storybook (pull_request) Successful in 1m32s
CI Pipeline / build (pull_request) Successful in 1m22s

This commit is contained in:
adilallo
2025-09-12 14:33:46 -06:00
parent 8daea70cb8
commit 500d2d0965
22 changed files with 237 additions and 234 deletions
+10 -10
View File
@@ -60,7 +60,7 @@ export function getBlogPostFiles() {
try {
const files = fs.readdirSync(contentDirectory);
return files.filter(
(file) => file.endsWith(".md") || file.endsWith(".mdx")
(file) => file.endsWith(".md") || file.endsWith(".mdx"),
);
} catch (error) {
console.error("Error reading blog content directory:", error);
@@ -84,7 +84,7 @@ export function parseBlogPost(filePath) {
if (!validationResult.isValid) {
console.error(
`Validation errors for ${filePath}:`,
validationResult.errors
validationResult.errors,
);
return null;
}
@@ -116,7 +116,7 @@ export function getAllBlogPosts() {
.map((fileName) => parseBlogPost(fileName))
.filter(Boolean) // Filter out nulls (invalid posts)
.sort(
(a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date)
(a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date),
); // Sort by date descending
return allPosts;
}
@@ -141,11 +141,11 @@ export function getBlogPostBySlug(slug) {
export function getRelatedBlogPosts(
currentPostSlug,
relatedSlugs = [],
limit = 3
limit = 3,
) {
const allPosts = getAllBlogPosts();
const filteredPosts = allPosts.filter(
(post) => post.slug !== currentPostSlug
(post) => post.slug !== currentPostSlug,
);
let related = [];
@@ -191,7 +191,7 @@ export function getAllTags() {
export function getBlogPostsByTag(tag) {
const allPosts = getAllBlogPosts();
return allPosts.filter(
(post) => post.frontmatter.tags && post.frontmatter.tags.includes(tag)
(post) => post.frontmatter.tags && post.frontmatter.tags.includes(tag),
);
}
@@ -216,7 +216,7 @@ export function searchBlogPosts(query, limit = 10) {
.includes(searchTerm);
const contentMatch = post.content.toLowerCase().includes(searchTerm);
const tagMatch = post.frontmatter.tags?.some((tag) =>
tag.toLowerCase().includes(searchTerm)
tag.toLowerCase().includes(searchTerm),
);
return titleMatch || descriptionMatch || contentMatch || tagMatch;
@@ -233,7 +233,7 @@ export function searchBlogPosts(query, limit = 10) {
export function getBlogPostsByAuthor(author) {
const allPosts = getAllBlogPosts();
return allPosts.filter(
(post) => post.frontmatter.author.toLowerCase() === author.toLowerCase()
(post) => post.frontmatter.author.toLowerCase() === author.toLowerCase(),
);
}
@@ -274,9 +274,9 @@ export function getBlogStats() {
1,
(new Date(allPosts[0].frontmatter.date) -
new Date(allPosts[allPosts.length - 1].frontmatter.date)) /
(1000 * 60 * 60 * 24 * 30)
(1000 * 60 * 60 * 24 * 30),
)) *
10
10,
) / 10
: 0,
};
+7 -7
View File
@@ -41,7 +41,7 @@ class ContentProcessor {
// Warm up cache
await warmCache(
() => this.getAllPosts(),
() => this.getAllTags()
() => this.getAllTags(),
);
this.isInitialized = true;
@@ -60,7 +60,7 @@ class ContentProcessor {
try {
const files = fs.readdirSync(this.contentDirectory);
return files.filter(
(file) => file.endsWith(".md") || file.endsWith(".mdx")
(file) => file.endsWith(".md") || file.endsWith(".mdx"),
);
} catch (error) {
console.error("Error reading blog content directory:", error);
@@ -85,7 +85,7 @@ class ContentProcessor {
if (!validationResult.isValid) {
console.error(
`Validation errors for ${filePath}:`,
validationResult.errors
validationResult.errors,
);
return null;
}
@@ -145,7 +145,7 @@ class ContentProcessor {
.map((fileName) => this.processBlogPost(fileName))
.filter(Boolean)
.sort(
(a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date)
(a, b) => new Date(b.frontmatter.date) - new Date(a.frontmatter.date),
);
// Cache the result
@@ -230,7 +230,7 @@ class ContentProcessor {
return {
totalPosts: allPosts.length,
totalAuthors: new Set(
allPosts.map((post) => post.frontmatter.author).size
allPosts.map((post) => post.frontmatter.author).size,
),
dateRange: {
earliest:
@@ -247,9 +247,9 @@ class ContentProcessor {
1,
(new Date(allPosts[0].frontmatter.date) -
new Date(allPosts[allPosts.length - 1].frontmatter.date)) /
(1000 * 60 * 60 * 24 * 30)
(1000 * 60 * 60 * 24 * 30),
)) *
10
10,
) / 10
: 0,
};
+13 -13
View File
@@ -159,34 +159,34 @@ function markdownToHtml(markdown) {
// Headers with IDs
.replace(
/^###### (.*$)/gim,
(m, t) => `<h6 id="${generateHeadingId(t)}">${t}</h6>`
(m, t) => `<h6 id="${generateHeadingId(t)}">${t}</h6>`,
)
.replace(
/^##### (.*$)/gim,
(m, t) => `<h5 id="${generateHeadingId(t)}">${t}</h5>`
(m, t) => `<h5 id="${generateHeadingId(t)}">${t}</h5>`,
)
.replace(
/^#### (.*$)/gim,
(m, t) => `<h4 id="${generateHeadingId(t)}">${t}</h4>`
(m, t) => `<h4 id="${generateHeadingId(t)}">${t}</h4>`,
)
.replace(
/^### (.*$)/gim,
(m, t) => `<h3 id="${generateHeadingId(t)}">${t}</h3>`
(m, t) => `<h3 id="${generateHeadingId(t)}">${t}</h3>`,
)
.replace(
/^## (.*$)/gim,
(m, t) => `<h2 id="${generateHeadingId(t)}">${t}</h2>`
(m, t) => `<h2 id="${generateHeadingId(t)}">${t}</h2>`,
)
.replace(
/^# (.*$)/gim,
(m, t) => `<h1 id="${generateHeadingId(t)}">${t}</h1>`
(m, t) => `<h1 id="${generateHeadingId(t)}">${t}</h1>`,
)
// Code fences (block) and inline code
.replace(
/```(\w+)?\n([\s\S]*?)\n```/g,
(m, lang = "", code) =>
`<pre><code class="language-${lang}">${code}</code></pre>`
`<pre><code class="language-${lang}">${code}</code></pre>`,
)
.replace(/`([^`]+)`/g, "<code>$1</code>")
@@ -198,12 +198,12 @@ function markdownToHtml(markdown) {
.replace(
/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g,
(m, alt, src, title = "") =>
`<img alt="${alt}" src="${src}"${title ? ` title="${title}"` : ""}>`
`<img alt="${alt}" src="${src}"${title ? ` title="${title}"` : ""}>`,
)
.replace(
/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/g,
(m, text, href, title = "") =>
`<a href="${href}"${title ? ` title="${title}"` : ""}>${text}</a>`
`<a href="${href}"${title ? ` title="${title}"` : ""}>${text}</a>`,
)
// Blockquotes
@@ -211,7 +211,7 @@ function markdownToHtml(markdown) {
const inner = m.replace(/^>\s?/gm, "");
return `<blockquote><p>${inner.replace(
/\n{2,}/g,
"</p><p>"
"</p><p>",
)}</p></blockquote>`;
})
@@ -247,7 +247,7 @@ function markdownToHtml(markdown) {
// (Also skip our GAP_TOKEN so we can turn it into gap paragraphs later.)
.replace(
/^(?!\s*<(h[1-6]|ul|ol|li|blockquote|hr|pre|code|table|img)\b)(?!\s*<\/)(?!\s*<GAP\/>)(.+)$/gim,
"<p>$2</p>"
"<p>$2</p>",
)
// Clean up truly empty paragraphs but keep &nbsp; gap paragraphs
@@ -258,8 +258,8 @@ function markdownToHtml(markdown) {
/<GAP:(\d+)\/>/g,
(m, n) =>
`<div class="md-gap" style="--gap:${Number(
n
)}" aria-hidden="true"></div>`
n,
)}" aria-hidden="true"></div>`,
)
);
}
+4 -4
View File
@@ -81,12 +81,12 @@ export function validateBlogPost(frontmatter) {
if (config.type === "string" && typeof frontmatter[field] === "string") {
if (config.minLength && frontmatter[field].length < config.minLength) {
errors.push(
`Field ${field} must be at least ${config.minLength} characters`
`Field ${field} must be at least ${config.minLength} characters`,
);
}
if (config.maxLength && frontmatter[field].length > config.maxLength) {
errors.push(
`Field ${field} must be no more than ${config.maxLength} characters`
`Field ${field} must be no more than ${config.maxLength} characters`,
);
}
}
@@ -105,12 +105,12 @@ export function validateBlogPost(frontmatter) {
}
if (config.items.minLength && item.length < config.items.minLength) {
errors.push(
`Item ${i} in ${field} must be at least ${config.items.minLength} characters`
`Item ${i} in ${field} must be at least ${config.items.minLength} characters`,
);
}
if (config.items.maxLength && item.length > config.items.maxLength) {
errors.push(
`Item ${i} in ${field} must be no more than ${config.items.maxLength} characters`
`Item ${i} in ${field} must be no more than ${config.items.maxLength} characters`,
);
}
}