Skip to content

Commit 0c6f249

Browse files
committed
Merge branch 'master' of github.com:souvikinator/notion-to-md
2 parents fc55a10 + 5dc153b commit 0c6f249

4 files changed

Lines changed: 62 additions & 6 deletions

File tree

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@ console.log(result);
195195
![image](https://media.giphy.com/media/Ju7l5y9osyymQ/giphy.gif)
196196
```
197197

198+
## Custom Transformers
199+
You can define your own custom transformer for a notion type, to parse and return your own string.
200+
`setCustomTransformer(type, func)` will overload the parsing for the giving type.
201+
202+
```js
203+
const { NotionToMarkdown } = require("notion-to-md");
204+
const n2m = new NotionToMarkdown({ notionClient: notion });
205+
n2m.setCustomTransformer('embed', async (block) => {
206+
const {embed} = block as any;
207+
if (!embed?.url) return '';
208+
return `<figure>
209+
<iframe src="${embed?.url}"></iframe>
210+
<figcaption>${await n2m.blockToMarkdown(embed?.caption)}</figcaption>
211+
</figure>`;
212+
});
213+
const result = n2m.blockToMarkdown(block);
214+
// Result will now parse the `embed` type with your custom function.
215+
```
216+
**Note** Be aware that `setCustomTransformer` will take only the last function for the given type. You can't set two different transforms for the same type.
217+
198218
## Contribution
199219
200220
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

src/notion-to-md.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { NotionToMarkdown } from './notion-to-md';
2+
3+
describe("setCustomTransformer", () => {
4+
5+
test("blockToMarkdown sends parsing block to customTransformer", () => {
6+
const customTransformerMock =jest.fn()
7+
const n2m = new NotionToMarkdown({notionClient: {} as any})
8+
n2m.setCustomTransformer("test", customTransformerMock)
9+
n2m.blockToMarkdown({
10+
id: "test", name: "test", type: "test", test: {"foo": "bar"}
11+
} as any)
12+
expect(customTransformerMock).toHaveBeenCalledWith(expect.objectContaining({
13+
type: "test", test: {"foo": "bar"}
14+
}))
15+
})
16+
test("supports only one customTransformer per type ", () => {
17+
const customTransformerMock1 =jest.fn()
18+
const customTransformerMock2 = jest.fn()
19+
const n2m = new NotionToMarkdown({notionClient: {} as any})
20+
n2m.setCustomTransformer("test", customTransformerMock1)
21+
n2m.setCustomTransformer("test", customTransformerMock2)
22+
n2m.blockToMarkdown({
23+
id: "test", name: "test", type: "test", test: {"foo": "bar"}
24+
} as any)
25+
expect(customTransformerMock1).not.toHaveBeenCalled()
26+
expect(customTransformerMock2).toHaveBeenCalled()
27+
})
28+
29+
30+
})

src/notion-to-md.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
MdBlock,
77
Text,
88
NotionToMarkdownOptions,
9+
CustomTransformer
910
} from "./types";
1011
import * as md from "./utils/md";
1112
import { getBlockChildren } from "./utils/notion";
@@ -15,11 +16,16 @@ import { getBlockChildren } from "./utils/notion";
1516
*/
1617
export class NotionToMarkdown {
1718
private notionClient: Client;
18-
19+
private customTransformers: Record<string, CustomTransformer>
1920
constructor(options: NotionToMarkdownOptions) {
2021
this.notionClient = options.notionClient;
22+
this.customTransformers = {}
2123
}
24+
setCustomTransformer(type: string, transformer: CustomTransformer): NotionToMarkdown {
25+
this.customTransformers[type] = transformer;
2226

27+
return this;
28+
}
2329
/**
2430
* Converts Markdown Blocks to string
2531
* @param {MdBlock[]} mdBlocks - Array of markdown blocks
@@ -122,12 +128,13 @@ ${md.addTabSpace(mdBlocks.parent, nestingLevel)}
122128
* @returns {string} corresponding markdown string of the passed block
123129
*/
124130
async blockToMarkdown(block: ListBlockChildrenResponseResult) {
125-
if (!("type" in block)) return "";
131+
if (typeof block !== "object" || !("type" in block)) return "";
126132

127133
let parsedData = "";
128134
const { type } = block;
129-
// console.log({ block });
130-
135+
if(type in this.customTransformers && !!this.customTransformers[type])
136+
return await this.customTransformers[type](block);
137+
131138
switch (type) {
132139
case "image":
133140
{
@@ -325,7 +332,6 @@ ${md.addTabSpace(mdBlocks.parent, nestingLevel)}
325332

326333
default: {
327334
// In this case typescript is not able to index the types properly, hence ignoring the error
328-
329335
// @ts-ignore
330336
let blockContent = block[type].text || block[type].rich_text || [];
331337
blockContent.map((content: Text) => {

src/types/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export type BlockAttributes = {
66
number?: number;
77
};
88
};
9-
109
export type ListBlockChildrenResponseResults =
1110
ListBlockChildrenResponse["results"] & BlockAttributes;
1211

@@ -70,3 +69,4 @@ export type CalloutIcon =
7069
| { type: "external"; external?: { url: string } }
7170
| { type: "file"; file: { url: string; expiry_time: string } }
7271
| null;
72+
export type CustomTransformer = (block: ListBlockChildrenResponseResult) => Promise<string>;

0 commit comments

Comments
 (0)