notion-to-md 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ <img src="https://imgur.com/WgXdz9r.png" />
2
+
3
+ # Notion to Markdown
4
+
5
+ Notion Markdown Exporter using **[notion-sdk-js](https://github.com/makenotion/notion-sdk-js)**
6
+
7
+ > **Note:** Before getting started, create [an integration and find the token](https://www.notion.so/my-integrations).
8
+
9
+ ## Todo
10
+
11
+ - [x] heading
12
+ - [x] images
13
+ - [x] quotes
14
+ - [x] links
15
+ - [x] bullets
16
+ - [x] todo
17
+ - [x] inline code
18
+ - [x] code block
19
+ - [x] strikethrough, underline, bold, italic
20
+ - [x] nested blocks
21
+ - [ ] embeds
22
+ - [ ] tables
23
+ - [ ] videos
24
+ - [ ] convert returned markdown object to string
25
+ - [ ] add tests
26
+
27
+ ## Install
28
+
29
+ ```Bash
30
+ $ npm install notion-to-md
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ### converting page to markdown
36
+
37
+ This is how the notion page looks for this example:
38
+
39
+ ![Imgur](https://imgur.com/9iqRpBl.png)
40
+
41
+ ```js
42
+ const { Client } = require("@notionhq/client");
43
+ const notion2md = require("notion2md");
44
+
45
+ const notion = new Client({
46
+ auth: "your integration token",
47
+ });
48
+
49
+ // passing notion client to the option
50
+ const n2m = new notion2md({ notionClient: notion });
51
+
52
+ (async () => {
53
+ const x = await n2m.pageToMarkdown("target_page_id");
54
+ console.log(x);
55
+ })();
56
+ ```
57
+
58
+ **Output:**
59
+
60
+ ```json
61
+ [
62
+ {
63
+ "parent": "# heading 1",
64
+ "children": []
65
+ },
66
+ {
67
+ "parent": "- bullet 1",
68
+ "children": [
69
+ {
70
+ "parent": "- bullet 1.1",
71
+ "children": []
72
+ },
73
+ {
74
+ "parent": "- bullet 1.2",
75
+ "children": []
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ "parent": "- bullet 2",
81
+ "children": []
82
+ },
83
+ {
84
+ "parent": "- [ ] check box 1",
85
+ "children": [
86
+ {
87
+ "parent": "- [x] check box 1.2",
88
+ "children": []
89
+ },
90
+ {
91
+ "parent": "- [ ] check box 1.3",
92
+ "children": []
93
+ }
94
+ ]
95
+ },
96
+ {
97
+ "parent": "- [ ] checkbox 2",
98
+ "children": []
99
+ }
100
+ ]
101
+ ```
102
+
103
+ ### converting list of blocks to markdown
104
+
105
+ > This example blocks from a single page is used. One construct array of blocks from different notion pages and pass in to the `blocksToMarkdown()`
106
+
107
+ same notion page as before
108
+
109
+ ```js
110
+ const { Client } = require("@notionhq/client");
111
+ const notion2md = require("notion2md");
112
+
113
+ const notion = new Client({
114
+ auth: "your integration token",
115
+ });
116
+
117
+ // passing notion client to the option
118
+ const n2m = new notion2md({ notionClient: notion });
119
+
120
+ (async () => {
121
+ // get all blocks in the page
122
+ const { results } = await notion.blocks.children.list({
123
+ block_id,
124
+ });
125
+
126
+ //convert to markdown
127
+ const x = await n2m.blocksToMarkdown(results);
128
+ console.log(x);
129
+ })();
130
+ ```
131
+
132
+ **Output**: same as before
133
+
134
+ ### Converting a single block to markdown
135
+
136
+ - just takes a single notion block and returns corresponding markdown string
137
+ - nesting is ignored
138
+
139
+ ```js
140
+ const result = n2m.blockToMarkdown(block);
141
+ console.log(result);
142
+ ```
143
+
144
+ **result**:
145
+
146
+ ```
147
+ ![image](https://media.giphy.com/media/Ju7l5y9osyymQ/giphy.gif)
148
+ ```
149
+
150
+ ## API
151
+
152
+ ### `pageToMarkdown(page_id)`
153
+
154
+ - Takes page_id as input and converts all the blocks in the page to corresponding markdown
155
+
156
+ ### `blockToMarkdown(block)`
157
+
158
+ - Takes one notion block and converts to markdown
159
+ - does not deal with nested notion blocks
160
+ - This method doesn't require the `notion-sdk-js`.
161
+ - Refer docs to know more about [notion blocks](https://developers.notion.com/reference/block)
162
+
163
+ ### `blocksToMarkdown(blocks)`
164
+
165
+ > **Note**: requires <u>**notion-sdk-js**</u> unlike `blockToMarkdown`
166
+
167
+ - `blocks`: array of notion blocks
168
+ - deals with <u>**nested blocks**</u>
169
+ - uses `blockToMarkdown` internally.
170
+
171
+ ## Contribution
172
+
173
+ Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
174
+ Please make sure to update tests as appropriate.
175
+
176
+ ## License
177
+
178
+ [MIT](https://choosealicense.com/licenses/mit/)
@@ -0,0 +1,98 @@
1
+ const md = require("./utils/md");
2
+ const { getBlockChildren } = require("./utils/notion");
3
+
4
+ class notion2md {
5
+ constructor(options) {
6
+ if (!options || !options.notionClient)
7
+ throw new Error(
8
+ "notion2md takes notion client as argument, for more details check out https://github.com/souvikinator/notion2md"
9
+ );
10
+ this.notionClient = options.notionClient;
11
+ }
12
+
13
+ async pageToMarkdown(id) {
14
+ if (!id) throw new Error("pageToMarkdown takes page_id as argument");
15
+ const blocks = await getBlockChildren(this.notionClient, id);
16
+ const parsedData = await this.blocksToMarkdown(blocks);
17
+ return parsedData;
18
+ }
19
+
20
+ /**
21
+ * @param {object} blocks - list of notion blocks
22
+ * @returns array of md blocks with their children
23
+ */
24
+ async blocksToMarkdown(blocks, mdBlocks = []) {
25
+ for (let i = 0; i < blocks.length; i++) {
26
+ let block = blocks[i];
27
+ if (block.has_children) {
28
+ let child_blocks = await getBlockChildren(this.notionClient, block.id);
29
+ mdBlocks.push({ parent: this.blockToMarkdown(block), children: [] });
30
+ let l = mdBlocks.length;
31
+ await this.blocksToMarkdown(child_blocks, mdBlocks[l - 1].children);
32
+ continue;
33
+ }
34
+ let tmp = this.blockToMarkdown(block);
35
+ // console.log(">>parsed data=", tmp, block);
36
+ mdBlocks.push({ parent: tmp, children: [] });
37
+ }
38
+ return mdBlocks;
39
+ }
40
+
41
+ /**
42
+ * @param {object} block - single notion block
43
+ * @returns markdown form of the passed block
44
+ */
45
+ blockToMarkdown(block) {
46
+ let parsedData = "",
47
+ blockContent;
48
+ const { type } = block;
49
+ if (type === "image") {
50
+ blockContent = block[type];
51
+ const image_type = blockContent["type"];
52
+
53
+ return md.image("image", blockContent[image_type].url);
54
+ } else {
55
+ blockContent = block[type]["text"] || [];
56
+ blockContent.map((content) => {
57
+ const annotations = content.annotations;
58
+ let plain_text = content.plain_text;
59
+
60
+ plain_text = this.annotatePlainText(plain_text, annotations);
61
+
62
+ if (content["href"]) plain_text = md.link(plain_text, content["href"]);
63
+
64
+ parsedData += plain_text;
65
+ });
66
+ }
67
+
68
+ // TODO: need to take care of escape sequences
69
+ if (type === "code") parsedData = md.codeBlock(parsedData);
70
+ if (type === "heading_1") parsedData = md.heading1(parsedData);
71
+ if (type === "heading_2") parsedData = md.heading2(parsedData);
72
+ if (type === "heading_3") parsedData = md.heading3(parsedData);
73
+ if (type === "quote") parsedData = md.quote(parsedData);
74
+
75
+ if (type === "numbered_list_item" || type === "bulleted_list_item")
76
+ parsedData = md.bullet(parsedData);
77
+
78
+ if (type === "to_do") parsedData = md.todo(parsedData, block[type].checked);
79
+
80
+ return parsedData;
81
+ }
82
+
83
+ /**
84
+ * @param {string} text string to be annotated
85
+ * @param {object} annotations annotation object of a notion block
86
+ */
87
+ annotatePlainText(text, annotations) {
88
+ if (annotations.code) text = md.inlineCode(text);
89
+ if (annotations.bold) text = md.bold(text);
90
+ if (annotations.italic) text = md.italic(text);
91
+ if (annotations.strikethrough) text = md.strikethrough(text);
92
+ if (annotations.underline) text = md.underline(text);
93
+
94
+ return text;
95
+ }
96
+ }
97
+
98
+ module.exports = notion2md;
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "notion-to-md",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "test": "echo \"Error: no test specified\" && exit 1"
7
+ },
8
+ "keywords": [
9
+ "notion",
10
+ "markdown",
11
+ "md",
12
+ "notion",
13
+ "notion-api",
14
+ "notion-to-md",
15
+ "notion2md"
16
+ ],
17
+ "author": "",
18
+ "license": "ISC",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/souvikinator/notion-to-md.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/souvikinator/notion-to-md/issues"
25
+ },
26
+ "homepage": "https://github.com/souvikinator/notion-to-md#readme",
27
+ "description": "convert notion pages, block and list of blocks to markdown (supports nesting)"
28
+ }
package/utils/md.js ADDED
@@ -0,0 +1,57 @@
1
+ exports.inlineCode = (text) => {
2
+ return `\`${text}\``;
3
+ };
4
+
5
+ exports.bold = (text) => {
6
+ return `**${text}**`;
7
+ };
8
+
9
+ exports.italic = (text) => {
10
+ return `_${text}_`;
11
+ };
12
+
13
+ exports.strikethrough = (text) => {
14
+ return `~~${text}~~`;
15
+ };
16
+
17
+ exports.underline = (text) => {
18
+ return `<u>${text}</u>`;
19
+ };
20
+
21
+ exports.link = (text, href) => {
22
+ return `[${text}](${href})`;
23
+ };
24
+
25
+ exports.codeBlock = (text) => {
26
+ return `\`\`\`${text}\`\`\``;
27
+ };
28
+
29
+ exports.heading1 = (text) => {
30
+ return `# ${text}`;
31
+ };
32
+
33
+ exports.heading2 = (text) => {
34
+ return `## ${text}`;
35
+ };
36
+
37
+ exports.heading3 = (text) => {
38
+ return `### ${text}`;
39
+ };
40
+
41
+ exports.quote = (text) => {
42
+ return `| ${text}`;
43
+ };
44
+
45
+ exports.bullet = (text) => {
46
+ return `- ${text}`;
47
+ };
48
+
49
+ exports.todo = (text, checked) => {
50
+ return checked ? `- [x] ${text}` : `- [ ] ${text}`;
51
+ };
52
+
53
+ exports.image = (alt, href) => {
54
+ return `![${alt}](${href})`;
55
+ };
56
+
57
+ //TODO: embed and fluid tags
@@ -0,0 +1,10 @@
1
+ exports.getBlockChildren = async (notionClient, block_id) => {
2
+ try {
3
+ const response = await notionClient.blocks.children.list({
4
+ block_id,
5
+ });
6
+ return response.results;
7
+ } catch (e) {
8
+ console.log(e);
9
+ }
10
+ };