140 lines
No EOL
3.5 KiB
JavaScript
140 lines
No EOL
3.5 KiB
JavaScript
const path = require("path");
|
|
const fs = require("fs");
|
|
const { execSync } = require("child_process");
|
|
const { DateTime } = require("luxon");
|
|
|
|
const getGitCreatedTime = (filePath) => {
|
|
try {
|
|
const result = execSync(
|
|
`git log --diff-filter=A --follow --format=%aI -- "${filePath}" | tail -1`,
|
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
).trim();
|
|
if (result) {
|
|
return DateTime.fromISO(result);
|
|
}
|
|
} catch (e) {
|
|
// Git command failed, return null
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const getGitModifiedTime = (filePath) => {
|
|
try {
|
|
const result = execSync(
|
|
`git log -1 --format=%aI -- "${filePath}"`,
|
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
).trim();
|
|
if (result) {
|
|
return DateTime.fromISO(result);
|
|
}
|
|
} catch (e) {
|
|
// Git command failed, return null
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const hasMermaidContent = (filePath) => {
|
|
try {
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
return /```mermaid/i.test(content);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const getTitleFromFilename = (filePath) => {
|
|
const basename = path.basename(filePath, '.md');
|
|
return basename
|
|
.split('-')
|
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
.join(' ');
|
|
}
|
|
|
|
const getFileCreatedTime = (filePath) => {
|
|
// Try git first for accurate cross-system creation time
|
|
const gitTime = getGitCreatedTime(filePath);
|
|
if (gitTime) {
|
|
return gitTime;
|
|
}
|
|
|
|
// Fall back to filesystem for untracked files
|
|
try {
|
|
const stats = fs.statSync(filePath);
|
|
const time = stats.birthtime ?? stats.mtime;
|
|
return DateTime.fromJSDate(time);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const getFileModifiedTime = (filePath) => {
|
|
try {
|
|
const stats = fs.statSync(filePath);
|
|
return DateTime.fromJSDate(stats.mtime);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const parseDate = (value) => {
|
|
if (!value) return null;
|
|
if (DateTime.isDateTime(value)) return value;
|
|
if (value instanceof Date) return DateTime.fromJSDate(value);
|
|
const parsed = DateTime.fromISO(value);
|
|
return parsed.isValid ? parsed : null;
|
|
}
|
|
|
|
const getPostCreatedAt = (data) => {
|
|
const frontmatterDate = parseDate(data.createdAt);
|
|
if (frontmatterDate) {
|
|
return frontmatterDate;
|
|
}
|
|
const gitDate = getGitCreatedTime(data.page.inputPath);
|
|
if (gitDate) {
|
|
return gitDate;
|
|
}
|
|
const fileDate = getFileCreatedTime(data.page.inputPath);
|
|
if (fileDate) {
|
|
return fileDate;
|
|
}
|
|
|
|
return DateTime.fromJSDate(data.page.date);
|
|
}
|
|
|
|
module.exports = {
|
|
layout: "post.njk",
|
|
tags: ["posts"],
|
|
eleventyComputed: {
|
|
released: (data) => {
|
|
if(data.page.inputPath.startsWith('./posts/drafts/')) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
},
|
|
title: (data) => {
|
|
if (data.title && data.title !== data.page.fileSlug) {
|
|
return data.title;
|
|
}
|
|
return getTitleFromFilename(data.page.inputPath);
|
|
},
|
|
createdAt: getPostCreatedAt,
|
|
updatedAt: (data) => {
|
|
return parseDate(data.updatedAt) ??
|
|
getGitModifiedTime(data.page.inputPath) ??
|
|
getFileModifiedTime(data.page.inputPath);
|
|
},
|
|
mermaid: (data) => {
|
|
return hasMermaidContent(data.page.inputPath);
|
|
},
|
|
permalink: (data) => {
|
|
const title = data.title || getTitleFromFilename(data.page.inputPath);
|
|
const slug = title.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');
|
|
|
|
const createdDate = getPostCreatedAt(data);
|
|
|
|
const isoDate = createdDate.toISODate();
|
|
return `/post/${slug}/${isoDate}/`;
|
|
}
|
|
}
|
|
}; |