Stuff for drafts, handling missing slugs and dates

This commit is contained in:
Will Boyd
2025-02-09 12:21:13 -05:00
parent a645b2bfdc
commit 42d0688654
7 changed files with 53 additions and 28 deletions
+6 -1
View File
@@ -24,11 +24,16 @@ export function coverImage(post) {
} }
// get post date, previously saved as a luxon datetime object on post // get post date, previously saved as a luxon datetime object on post
// this value is also used for year/month folders, date prefixes, etc. as needed
export function date(post) { export function date(post) {
return post.date; return post.date;
} }
// get boolean indicating if post is a draft
// this will only be included if true, otherwise it's left off
export function draft(post) {
return post.isDraft ? true : undefined;
}
// get excerpt, not decoded, newlines collapsed // get excerpt, not decoded, newlines collapsed
export function excerpt(post) { export function excerpt(post) {
return post.data.encoded[1].replace(/[\r\n]+/gm, ' '); return post.data.encoded[1].replace(/[\r\n]+/gm, ' ');
+6 -1
View File
@@ -156,5 +156,10 @@ function normalize(value, type, onError) {
} }
export function buildSamplePostPath(overrideConfig) { export function buildSamplePostPath(overrideConfig) {
return shared.buildPostPath('', luxon.DateTime.now(), 'my-post', overrideConfig); const samplePost = {
date: luxon.DateTime.now(),
slug: 'my-post'
};
return shared.buildPostPath(samplePost, overrideConfig);
} }
+4 -3
View File
@@ -58,7 +58,7 @@ function collectPosts(channelData, postTypes) {
let allPosts = []; let allPosts = [];
postTypes.forEach(postType => { postTypes.forEach(postType => {
const postsForType = getItemsOfType(channelData, postType) const postsForType = getItemsOfType(channelData, postType)
.filter(postData => postData.status[0] !== 'trash' && postData.status[0] !== 'draft') .filter(postData => postData.status[0] !== 'trash')
.filter(postData => !(postType === 'page' && postData.post_name[0] === 'sample-page')) .filter(postData => !(postType === 'page' && postData.post_name[0] === 'sample-page'))
.map(postData => buildPost(postData, turndownService)); .map(postData => buildPost(postData, turndownService));
@@ -83,8 +83,9 @@ function buildPost(data, turndownService) {
// these are not written to file, but help with other things // these are not written to file, but help with other things
type: data.post_type[0], type: data.post_type[0],
id: data.post_id[0], id: data.post_id[0],
isDraft: data.status[0] === 'draft',
slug: decodeURIComponent(data.post_name[0]), slug: decodeURIComponent(data.post_name[0]),
date: luxon.DateTime.fromRFC2822(data.pubDate[0], { zone: shared.config.customDateTimezone }), date: data.pubDate[0] ? luxon.DateTime.fromRFC2822(data.pubDate[0], { zone: shared.config.customDateTimezone }) : undefined,
coverImageId: getPostMetaValue(data.postmeta, '_thumbnail_id'), coverImageId: getPostMetaValue(data.postmeta, '_thumbnail_id'),
// these are possibly set later in mergeImagesIntoPosts() // these are possibly set later in mergeImagesIntoPosts()
@@ -171,7 +172,7 @@ function populateFrontmatter(posts) {
throw `Could not find a frontmatter getter named "${key}".`; throw `Could not find a frontmatter getter named "${key}".`;
} }
post.frontmatter[alias || key] = frontmatterGetter(post); post.frontmatter[alias ?? key] = frontmatterGetter(post);
}); });
}); });
} }
+1 -1
View File
@@ -109,7 +109,7 @@ export function load() {
{ {
name: 'frontmatter-fields', name: 'frontmatter-fields',
type: 'list', type: 'list',
default: ['title', 'date', 'categories', 'tags', 'coverImage'] default: ['title', 'date', 'categories', 'tags', 'coverImage', 'draft']
}, },
{ {
name: 'image-file-request-delay', name: 'image-file-request-delay',
+29 -14
View File
@@ -7,31 +7,46 @@ export function camelCase(str) {
return str.replace(/-(.)/g, (match) => match[1].toUpperCase()); return str.replace(/-(.)/g, (match) => match[1].toUpperCase());
} }
export function buildPostPath(type, date, slug, overrideConfig) { export function buildPostPath(post, overrideConfig) {
const pathConfig = overrideConfig ?? config; const pathConfig = overrideConfig ?? config;
// start with base output dir and post type // start with output folder
const pathSegments = [pathConfig.output, type]; const pathSegments = [pathConfig.output];
if (pathConfig.dateFolders === 'year' || pathConfig.dateFolders === 'year-month') { // add folder for post type if exists
pathSegments.push(date.toFormat('yyyy')); if (post.type) {
pathSegments.push(post.type);
} }
if (pathConfig.dateFolders === 'year-month') { // add drafts folder if this is a draft post
pathSegments.push(date.toFormat('LL')); if (post.isDraft) {
pathSegments.push('_drafts');
} }
// create slug fragment, possibly date prefixed // add folders for date year/month as appropriate
let slugFragment = slug; if (post.date) {
if (pathConfig.prefixDate) { if (pathConfig.dateFolders === 'year' || pathConfig.dateFolders === 'year-month') {
slugFragment = date.toFormat('yyyy-LL-dd') + '-' + slugFragment; pathSegments.push(post.date.toFormat('yyyy'));
}
if (pathConfig.dateFolders === 'year-month') {
pathSegments.push(post.date.toFormat('LL'));
}
} }
// use slug fragment as folder or filename as specified // get slug with fallback
let slug = post.slug ? post.slug : 'id-' + post.id;
// prepend date to slug as appropriate
if (pathConfig.prefixDate && post.date) {
slug = post.date.toFormat('yyyy-LL-dd') + '-' + slug;
}
// use slug as folder or filename as specified
if (pathConfig.postFolders) { if (pathConfig.postFolders) {
pathSegments.push(slugFragment, 'index.md'); pathSegments.push(slug, 'index.md');
} else { } else {
pathSegments.push(slugFragment + '.md'); pathSegments.push(slug + '.md');
} }
return path.join(...pathSegments); return path.join(...pathSegments);
+1 -1
View File
@@ -87,7 +87,7 @@ export function initTurndownService() {
return node.nodeName === 'PRE' && !node.querySelector('code'); return node.nodeName === 'PRE' && !node.querySelector('code');
}, },
replacement: (content, node) => { replacement: (content, node) => {
const language = node.getAttribute('data-wetm-language') || ''; const language = node.getAttribute('data-wetm-language') ?? '';
return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'; return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n';
} }
}); });
+6 -7
View File
@@ -46,7 +46,7 @@ async function writeMarkdownFilesPromise(posts) {
let skipCount = 0; let skipCount = 0;
let delay = 0; let delay = 0;
const payloads = posts.flatMap(post => { const payloads = posts.flatMap(post => {
const destinationPath = buildPostPath(post); const destinationPath = shared.buildPostPath(post);
if (checkFile(destinationPath)) { if (checkFile(destinationPath)) {
// already exists, don't need to save again // already exists, don't need to save again
skipCount++; skipCount++;
@@ -96,9 +96,12 @@ async function loadMarkdownFilePromise(post) {
if (shared.config.quoteDate) { if (shared.config.quoteDate) {
outputValue = `"${outputValue}"`; outputValue = `"${outputValue}"`;
} }
} else if (typeof value === 'boolean') {
// output unquoted
outputValue = value.toString();
} else { } else {
// single string value // single string value
const escapedValue = (value || '').replace(/"/g, '\\"'); const escapedValue = (value ?? '').replace(/"/g, '\\"');
if (escapedValue.length > 0) { if (escapedValue.length > 0) {
outputValue = `"${escapedValue}"`; outputValue = `"${escapedValue}"`;
} }
@@ -118,7 +121,7 @@ async function writeImageFilesPromise(posts) {
let skipCount = 0; let skipCount = 0;
let delay = 0; let delay = 0;
const payloads = posts.flatMap(post => { const payloads = posts.flatMap(post => {
const postPath = buildPostPath(post); const postPath = shared.buildPostPath(post);
const imagesDir = path.join(path.dirname(postPath), 'images'); const imagesDir = path.join(path.dirname(postPath), 'images');
return post.imageUrls.flatMap(imageUrl => { return post.imageUrls.flatMap(imageUrl => {
const filename = shared.getFilenameFromUrl(imageUrl); const filename = shared.getFilenameFromUrl(imageUrl);
@@ -185,10 +188,6 @@ async function loadImageFilePromise(imageUrl) {
return buffer; return buffer;
} }
function buildPostPath(post) {
return shared.buildPostPath(post.type, post.date, post.slug);
}
function checkFile(path) { function checkFile(path) {
return fs.existsSync(path); return fs.existsSync(path);
} }