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