Skip to content

Commit

Permalink
feat(preset-hugo): support configured post types
Browse files Browse the repository at this point in the history
  • Loading branch information
paulrobertlloyd committed Jan 20, 2024
1 parent ffa3e90 commit 05d3105
Show file tree
Hide file tree
Showing 7 changed files with 438 additions and 434 deletions.
223 changes: 6 additions & 217 deletions packages/preset-hugo/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import camelcaseKeys from "camelcase-keys";
import TOML from "@iarna/toml";
import YAML from "yaml";
import { getPostTemplate } from "./lib/post-template.js";
import { getPostTypes } from "./lib/post-types.js";

const defaults = {
frontMatterFormat: "yaml",
Expand Down Expand Up @@ -45,224 +44,14 @@ export default class HugoPreset {
];
}

/**
* Get content
* @access private
* @param {object} properties - JF2 properties
* @returns {string} Content
*/
#content(properties) {
if (properties.content) {
const content =
properties.content.text ||
properties.content.html ||
properties.content;
return `\n${content}\n`;
} else {
return "";
}
}

/**
* Get front matter
* @access private
* @param {object} properties - JF2 properties
* @returns {string} Front matter in chosen format
*/
#frontMatter(properties) {
let delimiters;
let frontMatter;

/*
* Go templates don’t accept hyphens in property names
* and Hugo camelCases its predefined front matter keys
* @see {link: https://gohugo.io/content-management/front-matter/}
*/
properties = camelcaseKeys(properties, { deep: true });

/*
* Replace Microformat properties with Hugo equivalents
* @see {link: https://gohugo.io/content-management/front-matter/}
*/
properties = {
date: properties.published,
publishDate: properties.published,
...(properties.postStatus === "draft" && { draft: true }),
...(properties.updated && { lastmod: properties.updated }),
...(properties.deleted && { expiryDate: properties.deleted }),
...(properties.name && { title: properties.name }),
...(properties.photo && {
images: properties.photo.map((image) => image.url),
}),
...properties,
};

delete properties.content; // Shown below front matter
delete properties.deleted; // Use `expiryDate`
delete properties.name; // Use `title`
delete properties.postStatus; // Use `draft`
delete properties.published; // Use `date`
delete properties.type; // Not required
delete properties.updated; // Use `lastmod`
delete properties.url; // Not required

switch (this.options.frontMatterFormat) {
case "json": {
delimiters = ["", "\n"];
frontMatter = JSON.stringify(properties, undefined, 2);
break;
}

case "toml": {
delimiters = ["+++\n", "+++\n"];
frontMatter = TOML.stringify(properties);
break;
}

default: {
delimiters = ["---\n", "---\n"];
frontMatter = YAML.stringify(properties, { lineWidth: 0 });
break;
}
}

return `${delimiters[0]}${frontMatter}${delimiters[1]}`;
}

/**
* Post types
* @returns {object} Post types configuration
*/
get postTypes() {
return [
{
type: "article",
name: "Article",
post: {
path: "content/articles/{slug}.md",
url: "articles/{slug}",
},
media: {
path: "static/articles/{filename}",
url: "articles/{filename}",
},
},
{
type: "note",
name: "Note",
post: {
path: "content/notes/{slug}.md",
url: "notes/{slug}",
},
},
{
type: "photo",
name: "Photo",
post: {
path: "content/photos/{slug}.md",
url: "photos/{slug}",
},
media: {
path: "static/photos/{filename}",
url: "photos/{filename}",
},
},
{
type: "video",
name: "Video",
post: {
path: "content/videos/{slug}.md",
url: "videos/{slug}",
},
media: {
path: "static/videos/{filename}",
url: "videos/{filename}",
},
},
{
type: "audio",
name: "Audio",
post: {
path: "content/audio/{slug}.md",
url: "audio/{slug}",
},
media: {
path: "static/audio/{filename}",
url: "audio/{filename}",
},
},
{
type: "bookmark",
name: "Bookmark",
post: {
path: "content/bookmarks/{slug}.md",
url: "bookmarks/{slug}",
},
},
{
type: "checkin",
name: "Checkin",
post: {
path: "content/checkins/{slug}.md",
url: "checkins/{slug}",
},
},
{
type: "event",
name: "Event",
post: {
path: "content/events/{slug}.md",
url: "events/{slug}",
},
},
{
type: "rsvp",
name: "RSVP",
post: {
path: "content/replies/{slug}.md",
url: "replies/{slug}",
},
},
{
type: "reply",
name: "Reply",
post: {
path: "content/replies/{slug}.md",
url: "replies/{slug}",
},
},
{
type: "repost",
name: "Repost",
post: {
path: "content/reposts/{slug}.md",
url: "reposts/{slug}",
},
},
{
type: "like",
name: "Like",
post: {
path: "content/likes/{slug}.md",
url: "likes/{slug}",
},
},
];
}

/**
* Post template
* @param {object} properties - JF2 properties
* @returns {string} Rendered template
*/
postTemplate(properties) {
const content = this.#content(properties);
const frontMatter = this.#frontMatter(properties);

return frontMatter + content;
return getPostTemplate(properties, this.options.frontMatterFormat);
}

init(Indiekit) {
const { publication } = Indiekit.config;
this.postTypes = getPostTypes(publication.postTypes);

Indiekit.addPreset(this);
}
}
99 changes: 99 additions & 0 deletions packages/preset-hugo/lib/post-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import camelcaseKeys from "camelcase-keys";
import TOML from "@iarna/toml";
import YAML from "yaml";

/**
* Get content
* @access private
* @param {object} properties - JF2 properties
* @returns {string} Content
*/
const getContent = (properties) => {
if (properties.content) {
const content =
properties.content.text || properties.content.html || properties.content;
return `\n${content}\n`;
} else {
return "";
}
};

/**
* Get front matter
* @access private
* @param {object} properties - JF2 properties
* @param {string} frontMatterFormat - Front matter format
* @returns {string} Front matter in chosen format
*/
const getFrontMatter = (properties, frontMatterFormat) => {
let delimiters;
let frontMatter;

/*
* Go templates don’t accept hyphens in property names
* and Hugo camelCases its predefined front matter keys
* @see {link: https://gohugo.io/content-management/front-matter/}
*/
properties = camelcaseKeys(properties, { deep: true });

/*
* Replace Microformat properties with Hugo equivalents
* @see {link: https://gohugo.io/content-management/front-matter/}
*/
properties = {
date: properties.published,
publishDate: properties.published,
...(properties.postStatus === "draft" && { draft: true }),
...(properties.updated && { lastmod: properties.updated }),
...(properties.deleted && { expiryDate: properties.deleted }),
...(properties.name && { title: properties.name }),
...(properties.photo && {
images: properties.photo.map((image) => image.url),
}),
...properties,
};

delete properties.content; // Shown below front matter
delete properties.deleted; // Use `expiryDate`
delete properties.name; // Use `title`
delete properties.postStatus; // Use `draft`
delete properties.published; // Use `date`
delete properties.type; // Not required
delete properties.updated; // Use `lastmod`
delete properties.url; // Not required

switch (frontMatterFormat) {
case "json": {
delimiters = ["", "\n"];
frontMatter = JSON.stringify(properties, undefined, 2);
break;
}

case "toml": {
delimiters = ["+++\n", "+++\n"];
frontMatter = TOML.stringify(properties);
break;
}

default: {
delimiters = ["---\n", "---\n"];
frontMatter = YAML.stringify(properties, { lineWidth: 0 });
break;
}
}

return `${delimiters[0]}${frontMatter}${delimiters[1]}`;
};

/**
* Get post template
* @param {object} properties - JF2 properties
* @param {string} [frontMatterFormat] - Front matter format
* @returns {string} Rendered template
*/
export const getPostTemplate = (properties, frontMatterFormat = "yaml") => {
const content = getContent(properties);
const frontMatter = getFrontMatter(properties, frontMatterFormat);

return frontMatter + content;
};
34 changes: 34 additions & 0 deletions packages/preset-hugo/lib/post-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import plur from "plur";

/**
* Get paths and URLs for configured post types
* @param {object} postTypes - Post type configuration
* @returns {object} Updated post type configuration
*/
export const getPostTypes = (postTypes) => {
const types = [];

for (const postType of postTypes) {
const { type } = postType;
const section = plur(type);

/**
* Follow Hugo content management guidelines
* @see {@link https://gohugo.io/content-management/organization/}
* @see {@link https://gohugo.io/content-management/static-files/}
*/
types.push({
type,
post: {
path: `content/${section}/{slug}.md`,
url: `${section}/{slug}`,
},
media: {
path: `static/${section}/{filename}`,
url: `${section}/{filename}`,
},
});
}

return types;
};
1 change: 1 addition & 0 deletions packages/preset-hugo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"main": "index.js",
"files": [
"assets",
"lib",
"index.js"
],
"bugs": {
Expand Down
Loading

0 comments on commit 05d3105

Please sign in to comment.