noblog 0.0.10 → 0.0.11
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 +25 -23
- package/dist/cmds/generate.js +28 -0
- package/dist/cmds/generate.js.map +1 -0
- package/dist/generate.cjs +463 -38
- package/dist/generate.cjs.map +1 -1
- package/dist/generate.js +463 -38
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/nomd/format.d.ts.map +1 -1
- package/dist/lib/nomd/format.js +111 -0
- package/dist/lib/nomd/format.js.map +1 -0
- package/dist/lib/nomd/nomd.d.ts +8 -3
- package/dist/lib/nomd/nomd.d.ts.map +1 -1
- package/dist/lib/nomd/nomd.js +489 -0
- package/dist/lib/nomd/nomd.js.map +1 -0
- package/dist/lib/notion/client.d.ts +12 -3
- package/dist/lib/notion/client.d.ts.map +1 -1
- package/dist/lib/notion/client.js +98 -0
- package/dist/lib/notion/client.js.map +1 -0
- package/dist/lib/notion/object.d.ts.map +1 -1
- package/dist/lib/notion/object.js +2 -0
- package/dist/lib/notion/object.js.map +1 -0
- package/dist/lib/notion/request.js +2 -0
- package/dist/lib/notion/request.js.map +1 -0
- package/package.json +45 -37
package/dist/generate.cjs
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
var path = require('path');
|
|
5
5
|
var fs = require('fs/promises');
|
|
6
|
-
var
|
|
7
|
-
require('
|
|
8
|
-
require('markdown-table');
|
|
6
|
+
var fetch = require('node-fetch');
|
|
7
|
+
var markdownTable = require('markdown-table');
|
|
9
8
|
require('dotenv/config');
|
|
10
9
|
var retry = require('async-retry');
|
|
11
10
|
var client$1 = require('@notionhq/client');
|
|
@@ -30,6 +29,73 @@ function _interopNamespaceDefault(e) {
|
|
|
30
29
|
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
31
30
|
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
32
31
|
|
|
32
|
+
const inlineEquation = (text) => {
|
|
33
|
+
return `$${text}$`;
|
|
34
|
+
};
|
|
35
|
+
const link = (text, href) => {
|
|
36
|
+
return `[${text}](${href})`;
|
|
37
|
+
};
|
|
38
|
+
const codeBlock = (text, language) => {
|
|
39
|
+
if (language === "plain text")
|
|
40
|
+
language = "text";
|
|
41
|
+
return `\`\`\`${language}
|
|
42
|
+
${text}
|
|
43
|
+
\`\`\``;
|
|
44
|
+
};
|
|
45
|
+
const equation = (text) => {
|
|
46
|
+
return `$$
|
|
47
|
+
${text}
|
|
48
|
+
$$`;
|
|
49
|
+
};
|
|
50
|
+
const heading1 = (text) => {
|
|
51
|
+
return `# ${text}`;
|
|
52
|
+
};
|
|
53
|
+
const heading2 = (text) => {
|
|
54
|
+
return `## ${text}`;
|
|
55
|
+
};
|
|
56
|
+
const heading3 = (text) => {
|
|
57
|
+
return `### ${text}`;
|
|
58
|
+
};
|
|
59
|
+
const quote = (text) => {
|
|
60
|
+
// the replace is done to handle multiple lines
|
|
61
|
+
return `> ${text.replace(/\n/g, " \n> ")}`;
|
|
62
|
+
};
|
|
63
|
+
const callout = (text, icon) => {
|
|
64
|
+
let emoji;
|
|
65
|
+
if (icon?.type === "emoji") {
|
|
66
|
+
emoji = icon.emoji;
|
|
67
|
+
}
|
|
68
|
+
// the replace is done to handle multiple lines
|
|
69
|
+
return `> ${emoji ? emoji + " " : ""}${text.replace(/\n/g, " \n> ")}`;
|
|
70
|
+
};
|
|
71
|
+
const bullet = (text, count) => {
|
|
72
|
+
let renderText = text.trim();
|
|
73
|
+
return count ? `${count}. ${renderText}` : `- ${renderText}`;
|
|
74
|
+
};
|
|
75
|
+
const todo = (text, checked) => {
|
|
76
|
+
return checked ? `- [x] ${text}` : `- [ ] ${text}`;
|
|
77
|
+
};
|
|
78
|
+
const image = async (alt, href, convertToBase64 = false) => {
|
|
79
|
+
// In case the user does not want to convert the images to Base64
|
|
80
|
+
// or the image is already base64
|
|
81
|
+
if (!convertToBase64 || href.startsWith("data:")) {
|
|
82
|
+
if (href.startsWith("data:")) {
|
|
83
|
+
// Extract base64 data, i.e. the string after 'data:mime/type;base64,'
|
|
84
|
+
const base64 = href.split(",").pop();
|
|
85
|
+
// This overrides incorrect data: string format to png
|
|
86
|
+
// so that browsers can correctly render the data
|
|
87
|
+
return ``;
|
|
88
|
+
}
|
|
89
|
+
return ``;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// Otherwise, download the image and convert it to base64
|
|
93
|
+
const res = await fetch(href);
|
|
94
|
+
const buf = await res.arrayBuffer();
|
|
95
|
+
const base64 = Buffer.from(buf).toString("base64");
|
|
96
|
+
return ``;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
33
99
|
const addTabSpace = (text, n = 0) => {
|
|
34
100
|
const tab = " ";
|
|
35
101
|
for (let i = 0; i < n; i++) {
|
|
@@ -42,6 +108,9 @@ const addTabSpace = (text, n = 0) => {
|
|
|
42
108
|
}
|
|
43
109
|
return text;
|
|
44
110
|
};
|
|
111
|
+
const divider = () => {
|
|
112
|
+
return "---";
|
|
113
|
+
};
|
|
45
114
|
const toggle = (summary, children) => {
|
|
46
115
|
if (!summary)
|
|
47
116
|
return children || "";
|
|
@@ -50,9 +119,12 @@ const toggle = (summary, children) => {
|
|
|
50
119
|
${children || ""}
|
|
51
120
|
</details>\n\n`;
|
|
52
121
|
};
|
|
122
|
+
const table = (cells) => {
|
|
123
|
+
return markdownTable.markdownTable(cells);
|
|
124
|
+
};
|
|
53
125
|
|
|
54
|
-
const NOTION_API_SECRET = process.env.NOTION_API_SECRET ??
|
|
55
|
-
const NOBLOG_DATABASE_ID = process.env.NOBLOG_DATABASE_ID ??
|
|
126
|
+
const NOTION_API_SECRET = process.env.NOTION_API_SECRET ?? "";
|
|
127
|
+
const NOBLOG_DATABASE_ID = process.env.NOBLOG_DATABASE_ID ?? "";
|
|
56
128
|
const client = new client$1.Client({
|
|
57
129
|
auth: NOTION_API_SECRET,
|
|
58
130
|
});
|
|
@@ -61,15 +133,19 @@ async function GetAllPosts() {
|
|
|
61
133
|
const params = {
|
|
62
134
|
database_id: NOBLOG_DATABASE_ID,
|
|
63
135
|
filter: {
|
|
64
|
-
and: [
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
136
|
+
and: [
|
|
137
|
+
{
|
|
138
|
+
property: "publish",
|
|
139
|
+
checkbox: { equals: true },
|
|
140
|
+
},
|
|
141
|
+
],
|
|
68
142
|
},
|
|
69
|
-
sorts: [
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
143
|
+
sorts: [
|
|
144
|
+
{
|
|
145
|
+
property: "date",
|
|
146
|
+
direction: "descending",
|
|
147
|
+
},
|
|
148
|
+
],
|
|
73
149
|
page_size: 100,
|
|
74
150
|
};
|
|
75
151
|
let results = [];
|
|
@@ -86,12 +162,12 @@ async function GetAllPosts() {
|
|
|
86
162
|
}
|
|
87
163
|
throw error;
|
|
88
164
|
}
|
|
89
|
-
}, { retries: numberOfRetry
|
|
165
|
+
}, { retries: numberOfRetry });
|
|
90
166
|
results = results.concat(res.results);
|
|
91
167
|
if (!res.has_more) {
|
|
92
168
|
break;
|
|
93
169
|
}
|
|
94
|
-
params[
|
|
170
|
+
params["start_cursor"] = res.next_cursor;
|
|
95
171
|
}
|
|
96
172
|
return results;
|
|
97
173
|
}
|
|
@@ -108,18 +184,48 @@ async function GetPageMeta(page_id) {
|
|
|
108
184
|
}
|
|
109
185
|
throw error;
|
|
110
186
|
}
|
|
111
|
-
}, { retries: numberOfRetry
|
|
187
|
+
}, { retries: numberOfRetry });
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
async function GetBlockChildren(block_id, totalPage) {
|
|
191
|
+
let result = [];
|
|
192
|
+
let pageCount = 0;
|
|
193
|
+
let start_cursor = undefined;
|
|
194
|
+
do {
|
|
195
|
+
const response = (await client.blocks.children.list({
|
|
196
|
+
start_cursor: start_cursor,
|
|
197
|
+
block_id: block_id,
|
|
198
|
+
}));
|
|
199
|
+
result.push(...response.results);
|
|
200
|
+
start_cursor = response?.next_cursor;
|
|
201
|
+
pageCount += 1;
|
|
202
|
+
} while (start_cursor != null &&
|
|
203
|
+
(totalPage == null || pageCount < totalPage));
|
|
204
|
+
ModifyNumberedListObject(result);
|
|
112
205
|
return result;
|
|
113
206
|
}
|
|
207
|
+
function ModifyNumberedListObject(blocks) {
|
|
208
|
+
let numberedListIndex = 0;
|
|
209
|
+
for (const block of blocks) {
|
|
210
|
+
if ("type" in block && block.type === "numbered_list_item") {
|
|
211
|
+
// add numbers
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
block.numbered_list_item.number = ++numberedListIndex;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
numberedListIndex = 0;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
114
220
|
|
|
115
|
-
class Noblog
|
|
221
|
+
class Noblog {
|
|
116
222
|
Posts = [];
|
|
117
223
|
CurrPage = "";
|
|
118
224
|
SavePath = "./src/pages/posts/";
|
|
119
225
|
ChildPath = "nob_children/";
|
|
120
226
|
MdCollection = {};
|
|
227
|
+
CustomTransformers = {};
|
|
121
228
|
constructor(posts, save_path, child_path) {
|
|
122
|
-
super({ notionClient: client });
|
|
123
229
|
this.Posts = posts;
|
|
124
230
|
if (child_path != undefined) {
|
|
125
231
|
this.ChildPath = child_path;
|
|
@@ -127,21 +233,21 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
127
233
|
if (save_path != undefined) {
|
|
128
234
|
this.SavePath = save_path;
|
|
129
235
|
}
|
|
130
|
-
this.
|
|
236
|
+
this.CustomTransformers["child_page"] = async (block) => {
|
|
131
237
|
const page = block;
|
|
132
238
|
if (!page?.id) {
|
|
133
239
|
return false;
|
|
134
240
|
}
|
|
135
241
|
let sub_path;
|
|
136
|
-
// if (curr_page.id in this.Post) and (page.id in this.Post)
|
|
137
|
-
//
|
|
242
|
+
// if (curr_page.id in this.Post) and (page.id in this.Post) ||
|
|
243
|
+
// (curr_page.id not in this.Post) and (page.id not in this.Post)
|
|
138
244
|
// * path should be "../pageid"
|
|
139
245
|
// if (curr_page.id in this.Post) and (page.id not in this.Post)
|
|
140
246
|
// * path should be "../save_path/pageid"
|
|
141
247
|
// if (curr_page.id not in this.Post) and (page.id in this.Post)
|
|
142
248
|
// * path should be "../../pageid"
|
|
143
|
-
const parent_surface =
|
|
144
|
-
const child_surface =
|
|
249
|
+
const parent_surface = this.Posts.filter((post) => post.id === this.CurrPage).length > 0;
|
|
250
|
+
const child_surface = this.Posts.filter((post) => post.id === page.id).length > 0;
|
|
145
251
|
if (parent_surface === child_surface) {
|
|
146
252
|
sub_path = "";
|
|
147
253
|
}
|
|
@@ -153,7 +259,7 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
153
259
|
}
|
|
154
260
|
const full_path = path__namespace.join("../", sub_path, page.id);
|
|
155
261
|
return `&[${page.child_page.title}](${full_path})`;
|
|
156
|
-
}
|
|
262
|
+
};
|
|
157
263
|
}
|
|
158
264
|
async Collect(recur = true) {
|
|
159
265
|
const save_dir = this.SavePath;
|
|
@@ -164,7 +270,7 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
164
270
|
try {
|
|
165
271
|
for (const pageid of Object.keys(this.MdCollection)) {
|
|
166
272
|
let fpath = sub_dir;
|
|
167
|
-
if (this.Posts.find(page => page.id === pageid))
|
|
273
|
+
if (this.Posts.find((page) => page.id === pageid))
|
|
168
274
|
fpath = save_dir;
|
|
169
275
|
await this.SaveJelly(pageid + ".md", fpath, this.MdCollection[pageid]);
|
|
170
276
|
}
|
|
@@ -175,7 +281,7 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
175
281
|
console.log(`failed: consider run verbose with v=true - ${error.message}`);
|
|
176
282
|
}
|
|
177
283
|
else {
|
|
178
|
-
console.log(
|
|
284
|
+
console.log("failed: an unknown error occurred");
|
|
179
285
|
}
|
|
180
286
|
}
|
|
181
287
|
}
|
|
@@ -194,7 +300,8 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
194
300
|
block.type !== "numbered_list_item") {
|
|
195
301
|
line_wrap = "\n";
|
|
196
302
|
}
|
|
197
|
-
jelly.content +=
|
|
303
|
+
jelly.content +=
|
|
304
|
+
line_wrap + `${addTabSpace(block.parent, 0)}\n` + line_wrap;
|
|
198
305
|
if (block.type === "child_page") {
|
|
199
306
|
jelly.children = [...jelly.children, block.blockId];
|
|
200
307
|
if (recursive)
|
|
@@ -214,23 +321,326 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
214
321
|
if (this.MdCollection.hasOwnProperty(page_id)) {
|
|
215
322
|
return this.MdCollection[page_id];
|
|
216
323
|
}
|
|
217
|
-
const blocks = await this.
|
|
324
|
+
const blocks = await this.PageToMarkdown(page_id);
|
|
218
325
|
const jelly = await this.FromBlocks(blocks, recursive);
|
|
219
326
|
const meta = await GetPageMeta(page_id);
|
|
220
327
|
const astro_meta = await this.AssembleAstroFrontmatter(meta);
|
|
221
328
|
jelly.content = astro_meta + jelly.content;
|
|
222
329
|
this.MdCollection[page_id] = jelly;
|
|
223
|
-
// restore the prev page info
|
|
330
|
+
// restore the prev page info
|
|
224
331
|
this.CurrPage = prev_page;
|
|
225
332
|
return jelly;
|
|
226
333
|
}
|
|
334
|
+
async PageToMarkdown(id, totalPage) {
|
|
335
|
+
if (!client) {
|
|
336
|
+
throw new Error("notion client is not provided, for more details check out https://github.com/souvikinator/notion-to-md");
|
|
337
|
+
}
|
|
338
|
+
const blocks = await GetBlockChildren(id, totalPage);
|
|
339
|
+
const parsedData = await this.BlocksToMarkdown(blocks);
|
|
340
|
+
return parsedData;
|
|
341
|
+
}
|
|
342
|
+
async BlocksToMarkdown(blocks, totalPage, mdBlocks) {
|
|
343
|
+
if (!client) {
|
|
344
|
+
throw new Error("notion client is not provided, for more details check out https://github.com/souvikinator/notion-to-md");
|
|
345
|
+
}
|
|
346
|
+
if (!blocks)
|
|
347
|
+
return mdBlocks;
|
|
348
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
349
|
+
let block = blocks[i];
|
|
350
|
+
if (
|
|
351
|
+
// @ts-ignore
|
|
352
|
+
block.type === "unsupported" ||
|
|
353
|
+
// @ts-ignore
|
|
354
|
+
(block.type === "child_page" && !this.config.parseChildPages)) {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if ("has_children" in block && block.has_children) {
|
|
358
|
+
const block_id = block.type == "synced_block" &&
|
|
359
|
+
block.synced_block?.synced_from?.block_id
|
|
360
|
+
? block.synced_block.synced_from.block_id
|
|
361
|
+
: block.id;
|
|
362
|
+
// Get children of this block.
|
|
363
|
+
let child_blocks = await GetBlockChildren(block_id, totalPage);
|
|
364
|
+
// Recursively call BlocksToMarkdown to get children of this block.
|
|
365
|
+
// check for custom transformer before parsing child
|
|
366
|
+
if (!(block.type in this.CustomTransformers) &&
|
|
367
|
+
!this.CustomTransformers[block.type]) {
|
|
368
|
+
let l = mdBlocks.length;
|
|
369
|
+
if (mdBlocks !== undefined) {
|
|
370
|
+
await this.BlocksToMarkdown(child_blocks, totalPage, mdBlocks[l - 1]?.children);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Push this block to mdBlocks.
|
|
374
|
+
mdBlocks.push({
|
|
375
|
+
type: block.type,
|
|
376
|
+
blockId: block.id,
|
|
377
|
+
parent: await this.BlockToMarkdown(block),
|
|
378
|
+
children: [],
|
|
379
|
+
});
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
let tmp = await this.BlockToMarkdown(block);
|
|
383
|
+
mdBlocks.push({
|
|
384
|
+
// @ts-ignore
|
|
385
|
+
type: block.type,
|
|
386
|
+
blockId: block.id,
|
|
387
|
+
parent: tmp,
|
|
388
|
+
children: [],
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
return mdBlocks;
|
|
392
|
+
}
|
|
393
|
+
async BlockToMarkdown(block) {
|
|
394
|
+
if (typeof block !== "object" || !("type" in block))
|
|
395
|
+
return "";
|
|
396
|
+
let parsedData = "";
|
|
397
|
+
const { type } = block;
|
|
398
|
+
if (type in this.CustomTransformers && !!this.CustomTransformers[type]) {
|
|
399
|
+
const transformer = this.CustomTransformers[type];
|
|
400
|
+
const customTransformerValue = transformer(block);
|
|
401
|
+
if (typeof customTransformerValue === "string")
|
|
402
|
+
return customTransformerValue;
|
|
403
|
+
}
|
|
404
|
+
switch (type) {
|
|
405
|
+
case "image":
|
|
406
|
+
let blockContent = block.image;
|
|
407
|
+
let image_title = "image";
|
|
408
|
+
const image_caption_plain = blockContent.caption
|
|
409
|
+
.map((item) => item.plain_text)
|
|
410
|
+
.join("");
|
|
411
|
+
const image_type = blockContent.type;
|
|
412
|
+
let link$1 = "";
|
|
413
|
+
if (image_type === "external") {
|
|
414
|
+
link$1 = blockContent.external.url;
|
|
415
|
+
}
|
|
416
|
+
if (image_type === "file") {
|
|
417
|
+
link$1 = blockContent.file.url;
|
|
418
|
+
}
|
|
419
|
+
// image caption with high priority
|
|
420
|
+
if (image_caption_plain.trim().length > 0) {
|
|
421
|
+
image_title = image_caption_plain;
|
|
422
|
+
}
|
|
423
|
+
else if (image_type === "file" || image_type === "external") {
|
|
424
|
+
const matches = link$1.match(/[^\/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))/);
|
|
425
|
+
image_title = matches ? matches[0] : image_title;
|
|
426
|
+
}
|
|
427
|
+
return await image(image_title, link$1, false);
|
|
428
|
+
case "divider":
|
|
429
|
+
return divider();
|
|
430
|
+
case "equation":
|
|
431
|
+
return equation(block.equation.expression);
|
|
432
|
+
case "video":
|
|
433
|
+
case "file":
|
|
434
|
+
case "pdf":
|
|
435
|
+
{
|
|
436
|
+
let blockContent;
|
|
437
|
+
let title = type;
|
|
438
|
+
if (type === "video")
|
|
439
|
+
blockContent = block.video;
|
|
440
|
+
if (type === "file")
|
|
441
|
+
blockContent = block.file;
|
|
442
|
+
if (type === "pdf")
|
|
443
|
+
blockContent = block.pdf;
|
|
444
|
+
const caption = blockContent?.caption
|
|
445
|
+
.map((item) => item.plain_text)
|
|
446
|
+
.join("");
|
|
447
|
+
if (blockContent) {
|
|
448
|
+
const file_type = blockContent.type;
|
|
449
|
+
let link$1 = "";
|
|
450
|
+
if (file_type === "external")
|
|
451
|
+
link$1 = blockContent.external.url;
|
|
452
|
+
if (file_type === "file")
|
|
453
|
+
link$1 = blockContent.file.url;
|
|
454
|
+
if (caption && caption.trim().length > 0) {
|
|
455
|
+
title = caption;
|
|
456
|
+
}
|
|
457
|
+
else if (link$1) {
|
|
458
|
+
const matches = link$1.match(/[^\/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))/);
|
|
459
|
+
title = matches ? matches[0] : type;
|
|
460
|
+
}
|
|
461
|
+
return link(title, link$1);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
break;
|
|
465
|
+
case "bookmark":
|
|
466
|
+
case "embed":
|
|
467
|
+
case "link_preview":
|
|
468
|
+
case "link_to_page":
|
|
469
|
+
{
|
|
470
|
+
let blockContent;
|
|
471
|
+
let title = type;
|
|
472
|
+
if (type === "bookmark")
|
|
473
|
+
blockContent = block.bookmark;
|
|
474
|
+
if (type === "embed")
|
|
475
|
+
blockContent = block.embed;
|
|
476
|
+
if (type === "link_preview")
|
|
477
|
+
blockContent = block.link_preview;
|
|
478
|
+
if (type === "link_to_page" &&
|
|
479
|
+
block.link_to_page.type === "page_id") {
|
|
480
|
+
blockContent = {
|
|
481
|
+
url: `https://www.notion.so/${block.link_to_page.page_id}`,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
if (blockContent)
|
|
485
|
+
return link(title, blockContent.url);
|
|
486
|
+
}
|
|
487
|
+
break;
|
|
488
|
+
case "child_page": {
|
|
489
|
+
let pageTitle = block.child_page.title;
|
|
490
|
+
return heading2(pageTitle);
|
|
491
|
+
}
|
|
492
|
+
case "child_database": {
|
|
493
|
+
let pageTitle = block.child_database.title || `child_database`;
|
|
494
|
+
return heading2(pageTitle);
|
|
495
|
+
}
|
|
496
|
+
case "table": {
|
|
497
|
+
const { id, has_children } = block;
|
|
498
|
+
let tableArr = [];
|
|
499
|
+
if (has_children) {
|
|
500
|
+
const tableRows = await GetBlockChildren(id, 100);
|
|
501
|
+
let rowsPromise = tableRows?.map(async (row) => {
|
|
502
|
+
const { type } = row;
|
|
503
|
+
const cells = row[type]["cells"];
|
|
504
|
+
/**
|
|
505
|
+
* this is more like a hack since matching the type text was
|
|
506
|
+
* difficult. So converting each cell to paragraph type to
|
|
507
|
+
* reuse the BlockToMarkdown function
|
|
508
|
+
*/
|
|
509
|
+
let cellStringPromise = cells.map(async (cell) => await this.BlockToMarkdown({
|
|
510
|
+
type: "paragraph",
|
|
511
|
+
paragraph: { rich_text: cell },
|
|
512
|
+
}));
|
|
513
|
+
const cellStringArr = await Promise.all(cellStringPromise);
|
|
514
|
+
tableArr.push(cellStringArr);
|
|
515
|
+
});
|
|
516
|
+
await Promise.all(rowsPromise || []);
|
|
517
|
+
}
|
|
518
|
+
return table(tableArr);
|
|
519
|
+
}
|
|
520
|
+
// Rest of the types:
|
|
521
|
+
// "paragraph" "heading_1" "heading_2" "heading_3"
|
|
522
|
+
// "bulleted_list_item" "numbered_list_item"
|
|
523
|
+
// "quote" "to_do" "template" "synced_block"
|
|
524
|
+
// "child_page" "child_database" "code" "callout" "breadcrumb"
|
|
525
|
+
// "table_of_contents" "link_to_page" "audio" "unsupported"
|
|
526
|
+
default: {
|
|
527
|
+
// @ts-ignore
|
|
528
|
+
let blockContent = block[type].text || block[type].rich_text || [];
|
|
529
|
+
let bucket = [];
|
|
530
|
+
let code_range = [];
|
|
531
|
+
let bold_range = [];
|
|
532
|
+
let italic_range = [];
|
|
533
|
+
let underline_range = [];
|
|
534
|
+
let strikethrough_range = [];
|
|
535
|
+
const push_or_merge = (arr, idx) => {
|
|
536
|
+
if (arr.length == 0) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
// @ts-ignore
|
|
540
|
+
if (idx === arr[arr.length - 1][1]) {
|
|
541
|
+
// @ts-ignore
|
|
542
|
+
arr[arr.length - 1][1] += 1;
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
arr.push([idx, idx + 1]);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
for (let i = 0; i < blockContent.length; i++) {
|
|
549
|
+
let content = blockContent[i];
|
|
550
|
+
if (content.type === "equation") {
|
|
551
|
+
bucket.push(inlineEquation(content.equation.expression));
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
let plain_text = content.plain_text;
|
|
555
|
+
if (content["href"])
|
|
556
|
+
plain_text = link(plain_text, content["href"]);
|
|
557
|
+
bucket.push(plain_text);
|
|
558
|
+
const annotations = content.annotations;
|
|
559
|
+
if (annotations.code)
|
|
560
|
+
push_or_merge(code_range, i);
|
|
561
|
+
if (annotations.bold)
|
|
562
|
+
push_or_merge(bold_range, i);
|
|
563
|
+
if (annotations.italic)
|
|
564
|
+
push_or_merge(italic_range, i);
|
|
565
|
+
if (annotations.underline)
|
|
566
|
+
push_or_merge(underline_range, i);
|
|
567
|
+
if (annotations.strikethrough)
|
|
568
|
+
push_or_merge(strikethrough_range, i);
|
|
569
|
+
}
|
|
570
|
+
let annoed_bucket = [];
|
|
571
|
+
for (let range of code_range)
|
|
572
|
+
annoed_bucket.push({ range: range, type: "code" });
|
|
573
|
+
for (let range of bold_range)
|
|
574
|
+
annoed_bucket.push({ range: range, type: "bold" });
|
|
575
|
+
for (let range of italic_range)
|
|
576
|
+
annoed_bucket.push({ range: range, type: "italic" });
|
|
577
|
+
for (let range of underline_range)
|
|
578
|
+
annoed_bucket.push({ range: range, type: "underline" });
|
|
579
|
+
for (let range of strikethrough_range)
|
|
580
|
+
annoed_bucket.push({ range: range, type: "strikethrough" });
|
|
581
|
+
annoed_bucket.sort(
|
|
582
|
+
// @ts-ignore
|
|
583
|
+
(a, b) => a.range[1] - a.range[0] - (b.range[1] - b.range[0]));
|
|
584
|
+
for (let annoed of annoed_bucket) {
|
|
585
|
+
annoed.type;
|
|
586
|
+
let [from, to] = annoed.range;
|
|
587
|
+
// @ts-ignore
|
|
588
|
+
bucket[from] = annotation + bucket[from];
|
|
589
|
+
// @ts-ignore
|
|
590
|
+
bucket[to - 1] = bucket[to - 1] + annotation;
|
|
591
|
+
}
|
|
592
|
+
bucket.forEach((x) => (parsedData += x));
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
switch (type) {
|
|
596
|
+
case "code":
|
|
597
|
+
parsedData = codeBlock(parsedData, block[type].language);
|
|
598
|
+
break;
|
|
599
|
+
case "heading_1":
|
|
600
|
+
parsedData = heading1(parsedData);
|
|
601
|
+
break;
|
|
602
|
+
case "heading_2":
|
|
603
|
+
parsedData = heading2(parsedData);
|
|
604
|
+
break;
|
|
605
|
+
case "heading_3":
|
|
606
|
+
parsedData = heading3(parsedData);
|
|
607
|
+
break;
|
|
608
|
+
case "quote":
|
|
609
|
+
parsedData = quote(parsedData);
|
|
610
|
+
break;
|
|
611
|
+
case "callout":
|
|
612
|
+
const { id, has_children } = block;
|
|
613
|
+
let callout_string = "";
|
|
614
|
+
if (!has_children) {
|
|
615
|
+
return callout(parsedData, block[type].icon);
|
|
616
|
+
}
|
|
617
|
+
const callout_children_object = await GetBlockChildren(id, 100);
|
|
618
|
+
const callout_children = await this.BlocksToMarkdown(callout_children_object);
|
|
619
|
+
callout_string += `${parsedData}\n`;
|
|
620
|
+
callout_children.map((child) => {
|
|
621
|
+
callout_string += `${child.parent}\n\n`;
|
|
622
|
+
});
|
|
623
|
+
parsedData = callout(callout_string.trim(), block[type].icon);
|
|
624
|
+
break;
|
|
625
|
+
case "bulleted_list_item":
|
|
626
|
+
parsedData = bullet(parsedData);
|
|
627
|
+
break;
|
|
628
|
+
case "numbered_list_item":
|
|
629
|
+
parsedData = bullet(parsedData, block.numbered_list_item.number);
|
|
630
|
+
break;
|
|
631
|
+
case "to_do":
|
|
632
|
+
parsedData = todo(parsedData, block.to_do.checked);
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
return parsedData;
|
|
636
|
+
}
|
|
227
637
|
async SaveJelly(fname, dir, jelly) {
|
|
228
638
|
if (jelly === undefined)
|
|
229
639
|
return `failed: ${fname} has empty jelly: `;
|
|
230
640
|
try {
|
|
231
641
|
await fs__namespace.mkdir(dir, { recursive: true });
|
|
232
642
|
const filePath = path__namespace.join(dir, fname);
|
|
233
|
-
await fs__namespace.writeFile(filePath, jelly.content,
|
|
643
|
+
await fs__namespace.writeFile(filePath, jelly.content, "utf-8");
|
|
234
644
|
return `success: ${fname} saved to ${filePath}`;
|
|
235
645
|
}
|
|
236
646
|
catch (error) {
|
|
@@ -238,25 +648,40 @@ class Noblog extends notionToMd.NotionToMarkdown {
|
|
|
238
648
|
return `failed: ${fname} - ${error.message}`;
|
|
239
649
|
}
|
|
240
650
|
else {
|
|
241
|
-
return
|
|
651
|
+
return "failed: an unknown error occurred";
|
|
242
652
|
}
|
|
243
653
|
}
|
|
244
654
|
}
|
|
245
655
|
async AssembleAstroFrontmatter(page) {
|
|
246
656
|
let frontmatter = "";
|
|
247
657
|
// default layout
|
|
248
|
-
const ischild = this.Posts.filter(post => post.id === page.id).length > 0 ? "" : "../";
|
|
249
|
-
frontmatter +=
|
|
658
|
+
const ischild = this.Posts.filter((post) => post.id === page.id).length > 0 ? "" : "../";
|
|
659
|
+
frontmatter +=
|
|
660
|
+
"layout: " + ischild + "../../layouts/MarkdownPostLayout.astro" + "\n";
|
|
250
661
|
// get title
|
|
251
|
-
frontmatter +=
|
|
662
|
+
frontmatter +=
|
|
663
|
+
"title: " +
|
|
664
|
+
JSON.stringify(page.properties.title?.title?.[0]?.plain_text ?? "") +
|
|
665
|
+
"\n";
|
|
252
666
|
// get tags
|
|
253
|
-
frontmatter +=
|
|
667
|
+
frontmatter +=
|
|
668
|
+
"tags: " +
|
|
669
|
+
JSON.stringify((page.properties.tags?.multi_select ?? []).map((tag) => tag.name)) +
|
|
670
|
+
"\n";
|
|
254
671
|
// get date
|
|
255
|
-
frontmatter +=
|
|
672
|
+
frontmatter +=
|
|
673
|
+
"pubDate: " +
|
|
674
|
+
(page.properties.date?.date?.start ??
|
|
675
|
+
new Date().toISOString().split("T")[0]) +
|
|
676
|
+
"\n";
|
|
256
677
|
// get archived
|
|
257
|
-
frontmatter +=
|
|
678
|
+
frontmatter +=
|
|
679
|
+
"archived: " + (page.properties.archived ? "true" : "false") + "\n";
|
|
258
680
|
// get description
|
|
259
|
-
frontmatter +=
|
|
681
|
+
frontmatter +=
|
|
682
|
+
"description: " +
|
|
683
|
+
JSON.stringify(page.properties.description?.rich_text?.[0]?.plain_text ?? "") +
|
|
684
|
+
"\n";
|
|
260
685
|
return "---\n" + frontmatter + "---\n";
|
|
261
686
|
}
|
|
262
687
|
}
|