Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created a plugin for frontmatter #51

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/config/default.docunotion.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { standardNumberedListTransformer } from "../plugins/NumberedListTransfor
import { standardTableTransformer } from "../plugins/TableTransformer";
import { standardExternalLinkConversion } from "../plugins/externalLinks";
import { IDocuNotionConfig } from "./configuration";
import { standardFrontmatterTransformer } from "../plugins/FrontMatterTransformer";

const defaultConfig: IDocuNotionConfig = {
plugins: [
Expand All @@ -35,6 +36,9 @@ const defaultConfig: IDocuNotionConfig = {
standardInternalLinkConversion,
standardExternalLinkConversion,

// Frontmatter transformers, add information to the page frontMatter
standardFrontmatterTransformer,

// Regexps plus javascript `import`s that operate on the Markdown output
imgurGifEmbed,
gifEmbed,
Expand Down
154 changes: 154 additions & 0 deletions src/plugins/FrontMatterTransformer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { GetPageResponse } from "@notionhq/client/build/src/api-endpoints";
import { NotionPage } from "../NotionPage";
import { standardFrontmatterTransformer } from "./FrontMatterTransformer";
import { IDocuNotionContext } from "..";

const getFrontMatter = standardFrontmatterTransformer.frontMatterGenerator
?.getFrontMatter as (context: IDocuNotionContext, page: NotionPage) => string;

const sampleMetadata: GetPageResponse = {
object: "page",
id: "6e6921b9-b1f5-4614-ab3c-bf1a73358a1f",
created_time: "2023-04-11T10:17:00.000Z",
last_edited_time: "2023-04-13T20:24:00.000Z",
created_by: {
object: "user",
id: "USERID",
},
last_edited_by: {
object: "user",
id: "USERID",
},
cover: null,
icon: {
type: "file",
file: {
url: "https:/dummy_URL",
expiry_time: "2023-04-15T11:50:20.461Z",
},
},
parent: {
type: "workspace",
workspace: true,
},
archived: false,
properties: {
title: {
id: "title",
type: "title",
title: [
{
type: "text",
text: {
content: "Foo",
link: null,
},
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: "default",
},
plain_text: "Foo",
href: null,
},
{
type: "text",
text: {
content: "Bar",
link: null,
},
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: "default",
},
plain_text: "Bar",
href: null,
},
],
},
Keywords: {
id: "keywords",
type: "rich_text",
rich_text: [
{
type: "text",
text: {
content: "Foo, Bar",
link: null,
},
annotations: {
bold: false,
italic: false,
strikethrough: false,
underline: false,
code: false,
color: "default",
},
plain_text: "Foo, Bar",
href: null,
},
],
},
date_property: {
id: "a%3Cql",
type: "date",
date: {
start: "2021-10-24",
end: "2021-10-28",
time_zone: null,
},
},
},
url: "https://www.notion.so/Site-docu-notion-PAGEID",
};

describe("getFrontMatter", () => {
let page: NotionPage;

beforeEach(() => {
page = new NotionPage({
layoutContext: "Test Context",
pageId: "123",
order: 1,
metadata: JSON.parse(JSON.stringify(sampleMetadata)),
foundDirectlyInOutline: true,
});
});

it("should generate frontMatter with all available properties", () => {
const expectedFrontmatter = `title: FooBar\nsidebar_position: 1\nslug: /123\nkeywords: [Foo, Bar]\n`;
(page.metadata as any).properties.Keywords.rich_text[0].plain_text =
"Foo, Bar";

const result = getFrontMatter({} as IDocuNotionContext, page);

expect(result).toEqual(expectedFrontmatter);
});

// "title: Foo-Barsidebar_position: 1slug: keywords: [Foo, Bar]"
// "title: FooBar\nsidebar_position: 1\nslug: /123\n"
it("should generate frontMatter with no keywords", () => {
const expectedFrontmatter = `title: FooBar\nsidebar_position: 1\nslug: /123\n`;
(page.metadata as any).properties.Keywords = undefined;

const result = getFrontMatter({} as IDocuNotionContext, page);

expect(result).toEqual(expectedFrontmatter);
});

it("should replace colons with dashes in the title", () => {
const expectedFrontmatter = `title: FooBaz-\nsidebar_position: 1\nslug: /123\nkeywords: [Foo, Bar]\n`;
(page.metadata as any).properties.title.title[1].plain_text = "Baz:";

const result = getFrontMatter({} as IDocuNotionContext, page);

expect(result).toEqual(expectedFrontmatter);
});
});
20 changes: 20 additions & 0 deletions src/plugins/FrontMatterTransformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IDocuNotionContext, IPlugin } from "./pluginTypes";
import { NotionPage } from "../NotionPage";

function getFrontmatter(context: IDocuNotionContext, page: NotionPage): string {
let frontMatter = "";
frontMatter += `title: ${page.nameOrTitle.replaceAll(":", "-")}\n`; // I have not found a way to escape colons
frontMatter += `sidebar_position: ${page.order}\n`;
frontMatter += `slug: ${page.slug ?? ""}\n`;
if (page.keywords) frontMatter += `keywords: [${page.keywords}]\n`;

return frontMatter;
}

export const standardFrontmatterTransformer: IPlugin = {
name: "standardFrontmatterTransformer",

frontMatterGenerator: {
getFrontMatter: getFrontmatter,
},
};
2 changes: 1 addition & 1 deletion src/plugins/pluginTestRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export async function blocksToMarkdown(
return r;
}

// This is used for things like testing links to other pages and frontmatter creation,
// This is used for things like testing links to other pages and frontMatter creation,
// when just testing what happens to individual blocks is not enough.
// after getting this, you can make changes to it, then pass it to blocksToMarkdown
export function makeSamplePageObject(options: {
Expand Down
5 changes: 5 additions & 0 deletions src/plugins/pluginTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export type IPlugin = {
// simple regex replacements on the markdown output
regexMarkdownModifications?: IRegexMarkdownModification[];

// operations on pages to define the markdown's frontMatter
frontMatterGenerator?: {
getFrontMatter: (context: IDocuNotionContext, page: NotionPage) => string;
};

// Allow a plugin to perform an async operation at the start of docu-notion.
// Notice that the plugin itself is given, so you can add things to it.
init?(plugin: IPlugin): Promise<void>;
Expand Down
28 changes: 16 additions & 12 deletions src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ export async function getMarkdownForPage(
logDebugFn("markdown from page", () => JSON.stringify(blocks, null, 2));

const body = await getMarkdownFromNotionBlocks(context, config, blocks);
const frontmatter = getFrontMatter(page); // todo should be a plugin
return `${frontmatter}\n${body}`;
const frontMatter = getMarkdownFrontMatter(context, config, page);
return `${frontMatter}\n${body}`;
}

// this is split off from getMarkdownForPage so that unit tests can provide the block contents
Expand Down Expand Up @@ -252,14 +252,18 @@ function registerNotionToMarkdownCustomTransforms(
});
}

// enhance:make this built-in plugin so that it can be overridden
function getFrontMatter(page: NotionPage): string {
let frontmatter = "---\n";
frontmatter += `title: ${page.nameOrTitle.replaceAll(":", "-")}\n`; // I have not found a way to escape colons
frontmatter += `sidebar_position: ${page.order}\n`;
frontmatter += `slug: ${page.slug ?? ""}\n`;
if (page.keywords) frontmatter += `keywords: [${page.keywords}]\n`;

frontmatter += "---\n";
return frontmatter;
function getMarkdownFrontMatter(
context: IDocuNotionContext,
config: IDocuNotionConfig,
page: NotionPage
): string {
let frontMatter = "---\n";
config.plugins.forEach(plugin => {
if (plugin.frontMatterGenerator) {
logDebug("transforming page with plugin", plugin.name);
frontMatter += plugin.frontMatterGenerator?.getFrontMatter(context, page);
}
});
frontMatter += "---\n";
return frontMatter;
}