datahub/examples/openspending/lib/computeFields.ts

112 lines
3.2 KiB
TypeScript

// This file is a temporary replacement for legacy contentlayer's computeFields + default fields values
import { remark } from "remark";
import stripMarkdown, { Options } from "strip-markdown";
import { defaultConfig as siteConfig } from '@portaljs/core'
// TODO return type
const sluggify = (urlPath: string) => {
return urlPath.replace(/^(.+?\/)*/, "");
};
const computeFields = async ({
frontMatter,
urlPath,
filePath,
source,
}: {
frontMatter: Record<string, any>;
urlPath: string;
filePath: string;
source: string;
}) => {
// Fields with corresponding config options
// TODO see _app.tsx
const showEditLink =
frontMatter.showEditLink ?? siteConfig.showEditLink ?? false;
// TODO take config into accout
const showLinkPreviews =
frontMatter.showLinkPreviews ?? siteConfig.showLinkPreviews ?? false;
const showToc = frontMatter.showToc ?? siteConfig.showToc ?? false;
const showSidebar =
frontMatter.showSidebar ?? siteConfig.showSidebar ?? false;
// Computed fields
// const title = frontMatter.title ?? (await extractTitle(source));
const title = frontMatter.title ?? null;
const description =
frontMatter.description ?? (await extractDescription(source));
const date = frontMatter.date ?? frontMatter.created ?? null;
const layout = (() => {
if (frontMatter.layout) return frontMatter.layout;
if (urlPath.startsWith("blog/")) return "blog";
// if (urlPath.startsWith("docs/")) return "docs";
return "docs"; // TODO default layout from config?
})();
// TODO Temporary, should probably be a column in the database
const slug = sluggify(urlPath);
// TODO take into accout include/exclude fields in config
const isDraft = frontMatter.isDraft ?? false;
return {
...frontMatter,
title,
description,
date,
layout,
slug,
urlPath, // extra for blogs index page; temporary here
isDraft,
showEditLink,
showLinkPreviews,
showToc,
showSidebar,
};
};
const extractTitle = async (source: string) => {
const heading = source.trim().match(/^#\s+(.*)/);
if (heading) {
const title = heading[1]
// replace wikilink with only text value
.replace(/\[\[([\S]*?)]]/, "$1");
const stripTitle = await remark().use(stripMarkdown).process(title);
return stripTitle.toString().trim();
}
return null;
};
const extractDescription = async (source: string) => {
const content = source
// remove commented lines
.replace(/{\/\*.*\*\/}/g, "")
// remove import statements
.replace(
/^import\s*(?:\{\s*[\w\s,\n]+\s*\})?(\s*(\w+))?\s*from\s*("|')[^"]+("|');?$/gm,
""
)
// remove youtube links
.replace(/^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$/gm, "")
// replace wikilinks with only text
.replace(/([^!])\[\[(\S*?)\]]/g, "$1$2")
// remove wikilink images
.replace(/!\[[\S]*?]]/g, "");
// remove markdown formatting
const stripped = await remark()
.use(stripMarkdown, {
remove: ["heading", "blockquote", "list", "image", "html", "code"],
} as Options)
.process(content);
if (stripped.value) {
const description: string = stripped.value.toString().slice(0, 200);
return description + "...";
}
return null;
};
export default computeFields;