Skip to content

Commit 18fa16f

Browse files
refactor: simplify the way of handling page properties
- separate common page meta data (used by static site generators) from actual properties - simplify db property filter logic - remove default injection of #h1 heading on pages, this is better left to static site generator template engines
1 parent b8e21e7 commit 18fa16f

10 files changed

+160
-155
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"scripts": {
1515
"build": "tsc",
1616
"prepare": "tsc",
17-
"test": "jest"
17+
"test": "jest",
18+
"test:watch": "jest --watch"
1819
},
1920
"devDependencies": {
2021
"@types/jest": "^27.0.2",

src/DeferredRenderer.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,11 @@ export class DeferredRenderer {
8080
logger.success("sync complete");
8181
}
8282

83-
public getRenderedPages() : RenderedPage[] {
83+
public getRenderedPages(): RenderedPage[] {
8484
return Array.from(this.renderedPages.values()).map((x) => ({
85-
id: x.id,
86-
category: x.category,
8785
file: x.file,
86+
meta: x.properties.meta,
8887
properties: x.properties.values,
8988
}));
9089
}
9190
}
92-
93-

src/FrontmatterRenderer.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import * as yaml from "js-yaml";
2+
import { PageProperties } from "./PageProperties";
23

34
export class FrontmatterRenderer {
45
constructor() {}
56

6-
public renderFrontmatter(properties: Record<string, any>) {
7-
const frontmatter = `---\n${yaml.dump(properties)}---\n\n`;
7+
public renderFrontmatter(props: PageProperties) {
8+
const obj = {
9+
...props.meta,
10+
properties: props.values,
11+
};
812

9-
return frontmatter
13+
const frontmatter = `---\n${yaml.dump(obj)}---\n\n`;
14+
15+
return frontmatter;
1016
}
1117
}

src/PageProperties.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
export interface PageMeta {
2+
id: string;
3+
url: string;
4+
title: string;
5+
category: string;
6+
order?: number;
7+
}
18

29
export interface PageProperties {
10+
meta: PageMeta;
11+
312
/**
413
* A mapping of property object keys -> property values
514
*/
615
values: Record<string, any>;
16+
717
/**
818
* A mapping of Notion API property names -> property object keys
919
*/
1020
keys: Map<string, string>;
1121
}
22+
23+
export interface PagePropertiesWithMeta extends PageProperties {}

src/PageRenderer.ts

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import { DatabaseConfig } from "./SyncConfig";
1111
import { PropertiesParser } from "./PropertiesParser";
1212
import { logger } from "./logger";
1313

14-
const debug = require("debug")("page");
15-
1614
const fs = fsc.promises;
1715

1816
export class PageRenderer {
@@ -23,23 +21,12 @@ export class PageRenderer {
2321
) {}
2422

2523
renderPage(page: Page, config: DatabaseConfig): RenderPageTask {
26-
const parsed = this.propertiesParser.parse(page.properties);
27-
const props = this.propertiesParser.filter(config, parsed);
28-
29-
const name = props.values["name"];
30-
if (!name) {
31-
this.throwMissingRequiredProperty("name", page);
32-
}
33-
34-
const category = props.values["category"];
35-
if (!category) {
36-
this.throwMissingRequiredProperty("category", page);
37-
}
38-
39-
const nameSlug = slugify(name);
40-
const categorySlug = slugify(category);
24+
const props = this.propertiesParser.parse(page, config);
4125

26+
const categorySlug = slugify(props.meta.category);
4227
const destDir = `${config.outDir}/${categorySlug}`;
28+
29+
const nameSlug = slugify(props.meta.title);
4330
const file = `${destDir}/${nameSlug}.md`;
4431

4532
// Design: all the rendering performance could be greatly enhanced writing directly to output streams instead
@@ -48,20 +35,13 @@ export class PageRenderer {
4835

4936
return {
5037
id: page.id,
51-
category: categorySlug,
5238
file,
5339
properties: props,
5440
render: async () => {
5541
const assetWriter = new AssetWriter(destDir);
5642

57-
const frontmatter = this.frontmatterRenderer.renderFrontmatter(
58-
props.values
59-
);
60-
const body = await this.bodyRenderer.renderBody(
61-
page,
62-
props,
63-
assetWriter
64-
);
43+
const frontmatter = this.frontmatterRenderer.renderFrontmatter(props);
44+
const body = await this.bodyRenderer.renderBody(page, assetWriter);
6545

6646
await fs.mkdir(destDir, { recursive: true });
6747
await fs.writeFile(file, frontmatter + body);
@@ -70,11 +50,4 @@ export class PageRenderer {
7050
},
7151
};
7252
}
73-
74-
private throwMissingRequiredProperty(propertyName: string, page: Page) {
75-
const msg = `Page ${page.url} is missing required property ${propertyName}`;
76-
debug(msg + "\n%O", page);
77-
78-
throw new Error(msg);
79-
}
8053
}

src/PropertiesParser.spec.ts

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,41 @@
1+
import { Page } from "@notionhq/client/build/src/api-types";
12
import { PropertiesParser } from "./PropertiesParser";
3+
import { RichTextRenderer } from "./RichTextRenderer";
24
import { DatabaseConfig } from "./SyncConfig";
35

6+
const page: Partial<Page> = {
7+
id: "123",
8+
url: "http://example.com/123",
9+
properties: {
10+
order: { id: "a", type: "number", number: 30 },
11+
Category: { id: "b", type: "select", select: { name: "Tools" } },
12+
Name: {
13+
id: "c",
14+
type: "title",
15+
title: [
16+
{
17+
type: "text",
18+
text: { content: "Terraform" },
19+
plain_text: "Terraform",
20+
annotations: {
21+
bold: false,
22+
code: false,
23+
color: "default",
24+
italic: false,
25+
strikethrough: false,
26+
underline: false,
27+
},
28+
},
29+
],
30+
},
31+
},
32+
};
33+
434
describe("PropertiesParser", () => {
5-
describe("filter", () => {
6-
test("preserves all properties and adds conventional with no include filter", async () => {
7-
const sut = new PropertiesParser({} as any);
35+
describe("parse", () => {
836

9-
const props = {
10-
values: { order: 30, category: "Tools", name: "Terraform" },
11-
keys: new Map([
12-
["order", "order"],
13-
["Category", "category"],
14-
["Name", "name"],
15-
]),
16-
};
37+
test("preserves all properties and adds conventional with no include filter", async () => {
38+
const sut = new PropertiesParser(new RichTextRenderer());
1739

1840
const config: DatabaseConfig = {
1941
outDir: "db/",
@@ -22,31 +44,32 @@ describe("PropertiesParser", () => {
2244
},
2345
};
2446

25-
const result = sut.filter(config, props);
47+
const result = sut.parse(page as any, config);
48+
2649
const expected = {
27-
keys: props.keys,
50+
meta: {
51+
category: "Tools",
52+
id: "123",
53+
title: "Terraform",
54+
url: "http://example.com/123",
55+
order: 30
56+
},
57+
keys: new Map([
58+
["order", "order"],
59+
["Category", "category"],
60+
["Name", "name"],
61+
]),
2862
values: {
2963
order: 30,
3064
category: "Tools",
3165
name: "Terraform",
32-
title: "Terraform",
3366
},
3467
};
35-
3668
expect(result).toEqual(expected);
3769
});
3870

3971
test("filters according to include filter", async () => {
40-
const sut = new PropertiesParser({} as any);
41-
42-
const props = {
43-
values: { order: 30, category: "Tools", name: "Terraform" },
44-
keys: new Map([
45-
["order", "order"],
46-
["Category", "category"],
47-
["Name", "name"],
48-
]),
49-
};
72+
const sut = new PropertiesParser(new RichTextRenderer());
5073

5174
const config: DatabaseConfig = {
5275
outDir: "db/",
@@ -56,19 +79,25 @@ describe("PropertiesParser", () => {
5679
},
5780
};
5881

59-
const result = sut.filter(config, props);
82+
const result = sut.parse(page as any, config);
83+
6084
const expected = {
85+
meta: {
86+
category: "Tools",
87+
id: "123",
88+
title: "Terraform",
89+
url: "http://example.com/123",
90+
order: 30
91+
},
6192
keys: new Map([
6293
["Name", "name"],
6394
["Category", "category"],
6495
]),
6596
values: {
6697
category: "Tools",
6798
name: "Terraform",
68-
title: "Terraform",
6999
},
70100
};
71-
72101
expect(result).toEqual(expected);
73102
});
74103
});

0 commit comments

Comments
 (0)