noblog 0.1.1 → 0.2.1

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.cjs CHANGED
@@ -8,7 +8,10 @@ var markdownTable = require('markdown-table');
8
8
  require('dotenv/config');
9
9
  var retry = require('async-retry');
10
10
  var client$1 = require('@notionhq/client');
11
+ var fs$1 = require('fs');
12
+ var url = require('url');
11
13
 
14
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
12
15
  function _interopNamespaceDefault(e) {
13
16
  var n = Object.create(null);
14
17
  if (e) {
@@ -155,9 +158,12 @@ const client = new client$1.Client({
155
158
  auth: NOTION_API_SECRET,
156
159
  });
157
160
  const numberOfRetry = 2;
158
- async function GetAllPosts() {
159
- const params = {
161
+ async function ListPages() {
162
+ const respDatabase = (await client.databases.retrieve({
160
163
  database_id: NOBLOG_DATABASE_ID,
164
+ }));
165
+ const reqDataSources = respDatabase.data_sources.map((source) => ({
166
+ data_source_id: source.id,
161
167
  filter: {
162
168
  and: [
163
169
  {
@@ -173,40 +179,41 @@ async function GetAllPosts() {
173
179
  },
174
180
  ],
175
181
  page_size: 100,
176
- };
182
+ }));
177
183
  let results = [];
178
- while (true) {
179
- const res = await retry(async (bail) => {
180
- try {
181
- return (await client.databases.query(params));
182
- }
183
- catch (error) {
184
- if (error instanceof client$1.APIResponseError) {
185
- if (error.status && error.status >= 400 && error.status < 500) {
184
+ for (const req of reqDataSources) {
185
+ let params = req;
186
+ while (true) {
187
+ const resp = await retry(async (bail) => {
188
+ try {
189
+ return client.dataSources.query(params);
190
+ }
191
+ catch (error) {
192
+ if (client$1.isNotionClientError(error)) {
186
193
  bail(error);
187
194
  }
195
+ throw error;
188
196
  }
189
- throw error;
197
+ }, { retries: numberOfRetry });
198
+ results = results.concat(resp.results);
199
+ if (!resp.has_more) {
200
+ break;
190
201
  }
191
- }, { retries: numberOfRetry });
192
- results = results.concat(res.results);
193
- if (!res.has_more) {
194
- break;
202
+ params.start_cursor = resp.next_cursor;
195
203
  }
196
- params["start_cursor"] = res.next_cursor;
197
204
  }
198
205
  return results;
199
206
  }
200
- async function GetPageMeta(page_id) {
207
+ async function GetPage(page_id) {
201
208
  const result = await retry(async (bail) => {
202
209
  try {
203
- return (await client.pages.retrieve({ page_id: page_id }));
210
+ return (await client.pages.retrieve({
211
+ page_id: page_id,
212
+ }));
204
213
  }
205
214
  catch (error) {
206
- if (error instanceof client$1.APIResponseError) {
207
- if (error.status && error.status >= 400 && error.status < 500) {
208
- bail(error);
209
- }
215
+ if (client$1.isNotionClientError(error)) {
216
+ bail(error);
210
217
  }
211
218
  throw error;
212
219
  }
@@ -214,7 +221,7 @@ async function GetPageMeta(page_id) {
214
221
  return result;
215
222
  }
216
223
  async function GetBlockChildren(block_id, totalPage) {
217
- const result = [];
224
+ const results = [];
218
225
  let pageCount = 0;
219
226
  let start_cursor = undefined;
220
227
  do {
@@ -222,13 +229,13 @@ async function GetBlockChildren(block_id, totalPage) {
222
229
  start_cursor: start_cursor,
223
230
  block_id: block_id,
224
231
  }));
225
- result.push(...response.results);
232
+ results.push(...response.results);
226
233
  start_cursor = response?.next_cursor;
227
234
  pageCount += 1;
228
235
  } while (start_cursor != null &&
229
236
  (totalPage == null || pageCount < totalPage));
230
- ModifyNumberedListObject(result);
231
- return result;
237
+ ModifyNumberedListObject(results);
238
+ return results;
232
239
  }
233
240
  function ModifyNumberedListObject(blocks) {
234
241
  let numberedListIndex = 0;
@@ -244,14 +251,66 @@ function ModifyNumberedListObject(blocks) {
244
251
  }
245
252
  }
246
253
 
254
+ const BLOCK_TO_DO = "to_do";
255
+ const BLOCK_TOGGLE = "toggle";
256
+ const BLOCK_CALLOUT = "callout";
257
+ const BLOCK_CHILD_PAGE = "child_page";
258
+ const BLOCK_UNSUPPORTED = "supported";
259
+ const BLOCK_SYNCED_BLOCK = "synced_block";
260
+ const BLOCK_NUMBERED_LIST_ITEM = "numbered_list_item";
261
+ const BLOCK_BULLETED_LIST_ITEM = "bulleted_list_item";
262
+ const BLOCK_IMAGE = "image";
263
+ const BLOCK_DIVIDER = "divider";
264
+ const BLOCK_EQUATION = "equation";
265
+ const BLOCK_PDF = "pdf";
266
+ const BLOCK_FILE = "file";
267
+ const BLOCK_VIDEO = "video";
268
+ const BLOCK_EMBED = "embed";
269
+ const BLOCK_BOOKMARK = "bookmark";
270
+ const BLOCK_LINK_PREVIEW = "link_preview";
271
+ const BLOCK_LINK_TO_PAGE = "link_to_page";
272
+ const BLOCK_CHILD_DATABASE = "child_database";
273
+ const BLOCK_TABLE = "table";
274
+ const BLOCK_CODE = "code";
275
+ const BLOCK_HEADING_1 = "heading_1";
276
+ const BLOCK_HEADING_2 = "heading_2";
277
+ const BLOCK_HEADING_3 = "heading_3";
278
+ const BLOCK_QUOTE = "quote";
279
+ const BLOCK_PARAGRAPH = "paragraph";
280
+ const LINEWRAP_NULL = "";
281
+ const LINEWRAP_NEWLINE = "\n";
282
+
283
+ async function SaveJelly(fname, dir, jelly, dry_run = false) {
284
+ if (jelly === undefined)
285
+ return `failed: ${fname} has empty jelly: `;
286
+ try {
287
+ if (dry_run) {
288
+ console.log(jelly.content);
289
+ return `success: ${fname} saved to ${dir}`;
290
+ }
291
+ await fs__namespace.mkdir(dir, { recursive: true });
292
+ const filePath = path__namespace.join(dir, fname);
293
+ await fs__namespace.writeFile(filePath, jelly.content, "utf-8");
294
+ return `success: ${fname} saved to ${filePath}`;
295
+ }
296
+ catch (error) {
297
+ if (error instanceof Error) {
298
+ return `failed: ${fname} - ${error.message}`;
299
+ }
300
+ else {
301
+ return "failed: an unknown error occurred";
302
+ }
303
+ }
304
+ }
247
305
  class Noblog {
248
306
  Posts = [];
249
307
  CurrPage = "";
250
308
  SavePath = "./src/pages/posts/";
251
309
  ChildPath = "nob_children/";
310
+ LayoutPath = "../../layouts/MarkdownPostLayout.astro";
252
311
  MdCollection = {};
253
312
  CustomTransformers = {};
254
- constructor(posts, save_path, child_path) {
313
+ constructor(posts, save_path, child_path, layout_path) {
255
314
  this.Posts = posts;
256
315
  if (child_path != undefined) {
257
316
  this.ChildPath = child_path;
@@ -259,7 +318,10 @@ class Noblog {
259
318
  if (save_path != undefined) {
260
319
  this.SavePath = save_path;
261
320
  }
262
- this.CustomTransformers["child_page"] = async (block) => {
321
+ if (layout_path != undefined) {
322
+ this.LayoutPath = layout_path;
323
+ }
324
+ this.CustomTransformers[BLOCK_CHILD_PAGE] = async (block) => {
263
325
  const page = block;
264
326
  if (!page?.id) {
265
327
  return false;
@@ -287,18 +349,19 @@ class Noblog {
287
349
  return `(」゚ロ゚)」 [${page.child_page.title}](${full_path})`;
288
350
  };
289
351
  }
290
- async Collect(recur = true) {
352
+ // Collect converts all pages in database to markdown files
353
+ async Collect(recursive = true) {
291
354
  const save_dir = this.SavePath;
292
355
  const sub_dir = path__namespace.join(save_dir, this.ChildPath);
293
356
  for (const page of this.Posts) {
294
- await this.FromPageid(page.id, recur);
357
+ await this.FromPageId(page.id, recursive);
295
358
  }
296
359
  try {
297
- for (const pageid of Object.keys(this.MdCollection)) {
360
+ for (const page_id of Object.keys(this.MdCollection)) {
298
361
  let fpath = sub_dir;
299
- if (this.Posts.find((page) => page.id === pageid))
362
+ if (this.Posts.find((page) => page.id === page_id))
300
363
  fpath = save_dir;
301
- await this.SaveJelly(pageid + ".md", fpath, this.MdCollection[pageid]);
364
+ await SaveJelly(page_id + ".md", fpath, this.MdCollection[page_id]);
302
365
  }
303
366
  console.log(`success: finish dump all files to "${save_dir}"`);
304
367
  }
@@ -311,27 +374,34 @@ class Noblog {
311
374
  }
312
375
  }
313
376
  }
377
+ // FromBlocks converts blocks fetched from notion api to
378
+ // rendered chunk (which is called jelly). Content in jelly
379
+ // will be collected to form the final markdown. If recursive
380
+ // is true, it will also fetch child pages exists in the given
381
+ // blocks.
314
382
  async FromBlocks(blocks, recursive) {
315
383
  const jelly = { content: "", children: [] };
316
384
  for (const block of blocks) {
317
385
  const subjelly = await this.FromBlocks(block.children, recursive);
318
- if (block.type === "toggle") {
319
- jelly.content += toggle(block.parent, subjelly.content);
320
- jelly.children = [...jelly.children, ...subjelly.children];
321
- continue;
386
+ let line_wrap = LINEWRAP_NULL;
387
+ if (block.type !== BLOCK_TO_DO &&
388
+ block.type !== BLOCK_BULLETED_LIST_ITEM &&
389
+ block.type !== BLOCK_NUMBERED_LIST_ITEM) {
390
+ line_wrap = LINEWRAP_NEWLINE;
322
391
  }
323
- let line_wrap = "";
324
- if (block.type !== "to_do" &&
325
- block.type !== "bulleted_list_item" &&
326
- block.type !== "numbered_list_item") {
327
- line_wrap = "\n";
392
+ switch (block.type) {
393
+ case BLOCK_TOGGLE:
394
+ jelly.content += toggle(block.parent, subjelly.content);
395
+ jelly.children = [...jelly.children, ...subjelly.children];
396
+ continue;
397
+ default:
398
+ jelly.content +=
399
+ line_wrap + `${addTabSpace(block.parent, 0)}\n` + line_wrap;
328
400
  }
329
- jelly.content +=
330
- line_wrap + `${addTabSpace(block.parent, 0)}\n` + line_wrap;
331
- if (block.type === "child_page") {
401
+ if (block.type === BLOCK_CHILD_PAGE) {
332
402
  jelly.children = [...jelly.children, block.blockId];
333
403
  if (recursive)
334
- await this.FromPageid(block.blockId, recursive);
404
+ await this.FromPageId(block.blockId, recursive);
335
405
  }
336
406
  else {
337
407
  jelly.content += subjelly.content;
@@ -340,7 +410,11 @@ class Noblog {
340
410
  }
341
411
  return jelly;
342
412
  }
343
- async FromPageid(page_id, recursive = true) {
413
+ // FromPageid converts a page id to rendered chunk (which is
414
+ // called jelly). Content in jelly will be collected to form
415
+ // the final markdown. If recursive is true, it will also
416
+ // fetch child pages exists in the given page.
417
+ async FromPageId(page_id, recursive = true) {
344
418
  // preserve the curr page info
345
419
  const prev_page = this.CurrPage;
346
420
  this.CurrPage = page_id;
@@ -349,7 +423,7 @@ class Noblog {
349
423
  }
350
424
  const blocks = await this.PageToMarkdown(page_id);
351
425
  const jelly = await this.FromBlocks(blocks, recursive);
352
- const meta = await GetPageMeta(page_id);
426
+ const meta = await GetPage(page_id);
353
427
  const astro_meta = await this.AssembleAstroFrontmatter(meta);
354
428
  jelly.content = astro_meta + jelly.content;
355
429
  this.MdCollection[page_id] = jelly;
@@ -359,7 +433,7 @@ class Noblog {
359
433
  }
360
434
  async PageToMarkdown(id, totalPage) {
361
435
  if (!client) {
362
- throw new Error("notion client is not provided, for more details check out https://github.com/souvikinator/notion-to-md");
436
+ throw new Error("notion client is not provided");
363
437
  }
364
438
  const blocks = await GetBlockChildren(id, totalPage);
365
439
  const parsedData = await this.BlocksToMarkdown(blocks);
@@ -367,59 +441,55 @@ class Noblog {
367
441
  }
368
442
  async BlocksToMarkdown(blocks, totalPage = null, mdBlocks = []) {
369
443
  if (!client) {
370
- throw new Error("notion client is not provided, for more details check out https://github.com/souvikinator/notion-to-md");
444
+ throw new Error("notion client is not provided");
371
445
  }
372
- if (!mdBlocks)
373
- mdBlocks = [];
374
446
  if (!blocks)
375
447
  return mdBlocks;
376
- for (let i = 0; i < blocks.length; i++) {
377
- const block = blocks[i];
378
- if (
448
+ for (const block of blocks) {
379
449
  // @ts-ignore
380
- block.type === "unsupported") {
450
+ if (block.type === BLOCK_UNSUPPORTED) {
381
451
  continue;
382
452
  }
383
- if ("has_children" in block && block.has_children) {
384
- const block_id = block.type == "synced_block" &&
385
- block.synced_block?.synced_from?.block_id
386
- ? block.synced_block.synced_from.block_id
387
- : block.id;
388
- // Get children of this block.
389
- const child_blocks = await GetBlockChildren(block_id, totalPage);
390
- // Push this block to mdBlocks.
453
+ if (!("has_children" in block) || !block.has_children) {
391
454
  mdBlocks.push({
455
+ // @ts-ignore
392
456
  type: block.type,
393
457
  blockId: block.id,
394
- parent: await this.BlockToMarkdown(block),
395
458
  children: [],
459
+ parent: await this.BlockToMarkdown(block),
396
460
  });
397
- // Recursively call BlocksToMarkdown to get children of this block.
398
- // check for custom transformer before parsing child
399
- if (!(block.type in this.CustomTransformers) &&
400
- !this.CustomTransformers[block.type]) {
401
- const l = mdBlocks.length;
402
- if (mdBlocks !== undefined) {
403
- await this.BlocksToMarkdown(child_blocks, totalPage, mdBlocks[l - 1]?.children);
404
- }
405
- }
406
461
  continue;
407
462
  }
408
- const tmp = await this.BlockToMarkdown(block);
463
+ const block_id = block.type == BLOCK_SYNCED_BLOCK &&
464
+ block.synced_block?.synced_from?.block_id
465
+ ? block.synced_block.synced_from.block_id
466
+ : block.id;
467
+ // Get children of this block.
468
+ const child_blocks = await GetBlockChildren(block_id, totalPage);
469
+ // Push this block to mdBlocks.
409
470
  mdBlocks.push({
410
- // @ts-ignore
411
471
  type: block.type,
412
472
  blockId: block.id,
413
- parent: tmp,
473
+ parent: await this.BlockToMarkdown(block),
414
474
  children: [],
415
475
  });
476
+ if (block.type === BLOCK_CALLOUT) {
477
+ continue;
478
+ }
479
+ if (!(block.type in this.CustomTransformers)) {
480
+ continue;
481
+ }
482
+ // Recursively call BlocksToMarkdown to collect children. check for custom transformer before parsing child
483
+ if (mdBlocks !== undefined) {
484
+ await this.BlocksToMarkdown(child_blocks, totalPage, mdBlocks[mdBlocks.length - 1]?.children);
485
+ }
416
486
  }
417
487
  return mdBlocks;
418
488
  }
419
489
  async BlockToMarkdown(block) {
420
490
  if (typeof block !== "object" || !("type" in block))
421
491
  return "";
422
- let parsedData = "";
492
+ let renderedData = "";
423
493
  const { type } = block;
424
494
  if (type in this.CustomTransformers && !!this.CustomTransformers[type]) {
425
495
  const transformer = this.CustomTransformers[type];
@@ -428,7 +498,7 @@ class Noblog {
428
498
  return customTransformerValue;
429
499
  }
430
500
  switch (type) {
431
- case "image":
501
+ case BLOCK_IMAGE:
432
502
  const blockContent = block.image;
433
503
  let image_title = "image";
434
504
  const image_caption_plain = blockContent.caption
@@ -451,21 +521,21 @@ class Noblog {
451
521
  image_title = matches ? matches[0] : image_title;
452
522
  }
453
523
  return await image(image_title, link$1, false);
454
- case "divider":
524
+ case BLOCK_DIVIDER:
455
525
  return divider();
456
- case "equation":
526
+ case BLOCK_EQUATION:
457
527
  return equation(block.equation.expression);
458
- case "pdf":
459
- case "file":
460
- case "video":
528
+ case BLOCK_PDF:
529
+ case BLOCK_FILE:
530
+ case BLOCK_VIDEO:
461
531
  {
462
532
  let blockContent;
463
533
  let title = type;
464
- if (type === "pdf")
534
+ if (type === BLOCK_PDF)
465
535
  blockContent = block.pdf;
466
- if (type === "file")
536
+ if (type === BLOCK_FILE)
467
537
  blockContent = block.file;
468
- if (type === "video")
538
+ if (type === BLOCK_VIDEO)
469
539
  blockContent = block.video;
470
540
  const caption = blockContent?.caption
471
541
  .map((item) => item.plain_text)
@@ -488,20 +558,20 @@ class Noblog {
488
558
  }
489
559
  }
490
560
  break;
491
- case "embed":
492
- case "bookmark":
493
- case "link_preview":
494
- case "link_to_page":
561
+ case BLOCK_EMBED:
562
+ case BLOCK_BOOKMARK:
563
+ case BLOCK_LINK_PREVIEW:
564
+ case BLOCK_LINK_TO_PAGE:
495
565
  {
496
566
  let blockContent;
497
567
  const title = type;
498
- if (type === "embed")
568
+ if (type === BLOCK_EMBED)
499
569
  blockContent = block.embed;
500
- if (type === "bookmark")
570
+ if (type === BLOCK_BOOKMARK)
501
571
  blockContent = block.bookmark;
502
- if (type === "link_preview")
572
+ if (type === BLOCK_LINK_PREVIEW)
503
573
  blockContent = block.link_preview;
504
- if (type === "link_to_page" &&
574
+ if (type === BLOCK_LINK_TO_PAGE &&
505
575
  block.link_to_page.type === "page_id") {
506
576
  blockContent = {
507
577
  url: `https://www.notion.so/${block.link_to_page.page_id}`,
@@ -511,15 +581,15 @@ class Noblog {
511
581
  return link(title, blockContent.url);
512
582
  }
513
583
  break;
514
- case "child_page": {
584
+ case BLOCK_CHILD_PAGE: {
515
585
  const pageTitle = block.child_page.title;
516
586
  return heading2(pageTitle);
517
587
  }
518
- case "child_database": {
588
+ case BLOCK_CHILD_DATABASE: {
519
589
  const pageTitle = block.child_database.title || `child_database`;
520
590
  return heading2(pageTitle);
521
591
  }
522
- case "table": {
592
+ case BLOCK_TABLE: {
523
593
  const { id, has_children } = block;
524
594
  const tableArr = [];
525
595
  if (has_children) {
@@ -533,7 +603,7 @@ class Noblog {
533
603
  * reuse the BlockToMarkdown function
534
604
  */
535
605
  const cellStringPromise = cells.map(async (cell) => await this.BlockToMarkdown({
536
- type: "paragraph",
606
+ type: BLOCK_PARAGRAPH,
537
607
  paragraph: { rich_text: cell },
538
608
  }));
539
609
  const cellStringArr = await Promise.all(cellStringPromise);
@@ -616,125 +686,277 @@ class Noblog {
616
686
  // @ts-ignore
617
687
  bucket[to - 1] = bucket[to - 1] + sanno;
618
688
  }
619
- bucket.forEach((x) => (parsedData += x));
689
+ bucket.forEach((x) => (renderedData += x));
620
690
  }
621
691
  }
622
692
  switch (type) {
623
- case "code":
624
- parsedData = codeBlock(parsedData, block[type].language);
693
+ case BLOCK_CODE:
694
+ renderedData = codeBlock(renderedData, block[type].language);
625
695
  break;
626
- case "heading_1":
627
- parsedData = heading1(parsedData);
696
+ case BLOCK_HEADING_1:
697
+ renderedData = heading1(renderedData);
628
698
  break;
629
- case "heading_2":
630
- parsedData = heading2(parsedData);
699
+ case BLOCK_HEADING_2:
700
+ renderedData = heading2(renderedData);
631
701
  break;
632
- case "heading_3":
633
- parsedData = heading3(parsedData);
702
+ case BLOCK_HEADING_3:
703
+ renderedData = heading3(renderedData);
634
704
  break;
635
- case "quote":
636
- parsedData = quote(parsedData);
705
+ case BLOCK_QUOTE:
706
+ renderedData = quote(renderedData);
637
707
  break;
638
- case "callout":
708
+ case BLOCK_CALLOUT:
639
709
  const { id, has_children } = block;
640
710
  let callout_string = "";
641
711
  if (!has_children) {
642
- return callout(parsedData, block[type].icon);
712
+ return callout(renderedData, block.callout.icon);
643
713
  }
644
714
  const callout_children_object = await GetBlockChildren(id, 100);
645
715
  const callout_children = await this.BlocksToMarkdown(callout_children_object);
646
- callout_string += `${parsedData}\n`;
647
- callout_children.map((child) => {
648
- callout_string += `${child.parent}\n\n`;
649
- });
650
- parsedData = callout(callout_string.trim(), block[type].icon);
716
+ callout_string += `${renderedData}\n`;
717
+ callout_string += (await this.FromBlocks(callout_children, true))
718
+ .content;
719
+ renderedData = callout(callout_string.trim(), block.callout.icon);
651
720
  break;
652
- case "bulleted_list_item":
653
- parsedData = bullet(parsedData);
721
+ case BLOCK_BULLETED_LIST_ITEM:
722
+ renderedData = bullet(renderedData);
654
723
  break;
655
- case "numbered_list_item":
656
- parsedData = bullet(parsedData, block.numbered_list_item.number);
724
+ case BLOCK_NUMBERED_LIST_ITEM:
725
+ renderedData = bullet(renderedData, block.numbered_list_item.number);
657
726
  break;
658
- case "to_do":
659
- parsedData = todo(parsedData, block.to_do.checked);
727
+ case BLOCK_TO_DO:
728
+ renderedData = todo(renderedData, block.to_do.checked);
660
729
  break;
661
730
  }
662
- return parsedData;
663
- }
664
- async SaveJelly(fname, dir, jelly) {
665
- if (jelly === undefined)
666
- return `failed: ${fname} has empty jelly: `;
667
- try {
668
- await fs__namespace.mkdir(dir, { recursive: true });
669
- const filePath = path__namespace.join(dir, fname);
670
- await fs__namespace.writeFile(filePath, jelly.content, "utf-8");
671
- return `success: ${fname} saved to ${filePath}`;
672
- }
673
- catch (error) {
674
- if (error instanceof Error) {
675
- return `failed: ${fname} - ${error.message}`;
676
- }
677
- else {
678
- return "failed: an unknown error occurred";
679
- }
680
- }
731
+ return renderedData;
681
732
  }
682
733
  async AssembleAstroFrontmatter(page) {
683
734
  let frontmatter = "";
684
- // default layout
735
+ // Default layout
685
736
  const ischild = this.Posts.filter((post) => post.id === page.id).length > 0 ? "" : "../";
686
- frontmatter +=
687
- "layout: " + ischild + "../../layouts/MarkdownPostLayout.astro" + "\n";
688
- // get title
689
- frontmatter +=
690
- "title: " +
691
- JSON.stringify(page.properties.title?.title?.[0]?.plain_text ?? "") +
692
- "\n";
693
- // get tags
694
- frontmatter +=
695
- "tags: " +
696
- JSON.stringify((page.properties.tags?.multi_select ?? []).map((tag) => tag.name)) +
697
- "\n";
698
- // get date
699
- frontmatter +=
700
- "pubDate: " +
701
- (page.properties.date?.date?.start ??
702
- new Date().toISOString().split("T")[0]) +
703
- "\n";
704
- // get archived
705
- frontmatter +=
706
- "archived: " + (page.properties.archived ? "true" : "false") + "\n";
707
- // get description
708
- frontmatter +=
709
- "description: " +
710
- JSON.stringify(page.properties.description?.rich_text?.[0]?.plain_text ?? "") +
711
- "\n";
737
+ frontmatter += "layout: " + ischild + this.LayoutPath + "\n";
738
+ let title = "";
739
+ let description = "";
740
+ let tags = [];
741
+ let pubDate = "";
742
+ let archived = "";
743
+ Object.entries(page.properties).forEach(([key, property]) => {
744
+ switch (property.type) {
745
+ case "title": // Get title
746
+ title = property.title
747
+ ?.map((title) => title.plain_text)
748
+ .reduce((a, b) => a + b);
749
+ break;
750
+ case "multi_select": // Get tags
751
+ tags = property.multi_select?.map((tag) => tag.name);
752
+ break;
753
+ case "date": // Get date
754
+ pubDate =
755
+ property.date?.start ?? new Date().toISOString().split("T")[0];
756
+ break;
757
+ default: // Customized properties from the template given in the Github repo
758
+ switch (key) {
759
+ case "archived": // Get archived
760
+ archived =
761
+ property.type === "checkbox" && property.checkbox
762
+ ? "true"
763
+ : "false";
764
+ break;
765
+ case "description": // Get description
766
+ description =
767
+ property.type === "rich_text"
768
+ ? property.rich_text
769
+ ?.map((text) => text.plain_text)
770
+ .reduce((a, b) => a + b)
771
+ : "";
772
+ break;
773
+ }
774
+ }
775
+ });
776
+ frontmatter += "title: " + JSON.stringify(title) + "\n";
777
+ frontmatter += "description: " + JSON.stringify(description) + "\n";
778
+ frontmatter += "tags: " + JSON.stringify(tags) + "\n";
779
+ frontmatter += "pubDate: " + JSON.stringify(pubDate) + "\n";
780
+ frontmatter += "archived: " + JSON.stringify(archived) + "\n";
712
781
  return "---\n" + frontmatter + "---\n";
713
782
  }
714
783
  }
715
784
 
785
+ function getVersion() {
786
+ try {
787
+ const __filename = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('generate.cjs', document.baseURI).href)));
788
+ const __dirname = path.dirname(__filename);
789
+ const packagePath = path.join(__dirname, "../../package.json");
790
+ const packageJson = JSON.parse(fs$1.readFileSync(packagePath, "utf-8"));
791
+ return packageJson.version;
792
+ }
793
+ catch {
794
+ return "unknown";
795
+ }
796
+ }
716
797
  function help() {
717
- console.log(`\n
718
- Usage: noblog [SAVE_PATH] [SUB_PATH]
798
+ console.log(`
799
+ noblog - Generate static blog content from Notion.so
800
+
801
+ Usage: noblog [command] [options] [SAVE_PATH] [SUB_PATH]
802
+
803
+ Options:
804
+ -v, --verbose Print more messages for debugging
805
+ -h, --help Show help message
806
+ --version Show version information
807
+ --layout PATH Custom layout path (default: ../../layouts/MarkdownPostLayout.astro)
808
+
809
+ Commands:
810
+ help Show this help message
811
+ version Show version information
812
+ generate Generate blog content (default command)
813
+
814
+ Options:
815
+ -v, --verbose Print more messages for debugging
816
+ -h, --help Show help message
817
+ --version Show version information
818
+
819
+ Arguments:
820
+ SAVE_PATH Directory to save main posts (default: ./src/pages/posts/)
821
+ SUB_PATH Subdirectory for nested content (default: nob_children/)
822
+
823
+ Layout Options:
824
+ --layout PATH Custom layout path relative to save directory (default: ../../layouts/MarkdownPostLayout.astro)
719
825
 
720
- Example:
721
- noblog
826
+ Examples:
827
+ noblog help
828
+ noblog version
829
+ noblog generate
830
+ noblog -v
722
831
  noblog src/pages/posts/ nob_children/
832
+ noblog --layout ../../layouts/BlogLayout.astro
833
+ noblog src/posts/ children/ --layout ../../../layouts/CustomLayout.astro -v
723
834
 
724
- Available <option>:
725
- -v Print more messages for debugging.\n`);
835
+ Environment Variables:
836
+ NOTION_API_SECRET Your Notion API secret
837
+ NOBLOG_DATABASE_ID Your Notion database ID
838
+ `);
839
+ }
840
+ function parseArgs(argv) {
841
+ const options = {
842
+ verbose: false,
843
+ help: false,
844
+ version: false,
845
+ savePath: "./src/pages/posts/",
846
+ subPath: "nob_children/",
847
+ layoutPath: "../../layouts/MarkdownPostLayout.astro",
848
+ };
849
+ const positionalArgs = [];
850
+ for (let i = 0; i < argv.length; i++) {
851
+ const arg = argv[i];
852
+ switch (arg) {
853
+ case "-v":
854
+ case "--verbose":
855
+ options.verbose = true;
856
+ break;
857
+ case "-h":
858
+ case "--help":
859
+ case "help":
860
+ options.help = true;
861
+ break;
862
+ case "--version":
863
+ case "version":
864
+ options.version = true;
865
+ break;
866
+ case "--layout":
867
+ if (i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
868
+ options.layoutPath = argv[++i];
869
+ }
870
+ else {
871
+ console.error("Error: --layout requires a path argument");
872
+ help();
873
+ process.exit(1);
874
+ }
875
+ break;
876
+ case "generate":
877
+ // Explicit generate command, skip it
878
+ break;
879
+ default:
880
+ if (arg.startsWith("-")) {
881
+ console.error(`Unknown option: ${arg}`);
882
+ help();
883
+ process.exit(1);
884
+ }
885
+ positionalArgs.push(arg);
886
+ break;
887
+ }
888
+ }
889
+ // Handle positional arguments
890
+ if (positionalArgs.length > 0) {
891
+ options.savePath = positionalArgs[0];
892
+ }
893
+ if (positionalArgs.length > 1) {
894
+ options.subPath = positionalArgs[1];
895
+ }
896
+ if (positionalArgs.length > 2) {
897
+ console.error("Error: Too many arguments.");
898
+ help();
899
+ process.exit(1);
900
+ }
901
+ return options;
902
+ }
903
+ async function generateBlog(options) {
904
+ try {
905
+ if (options.verbose) {
906
+ console.log("Fetching posts from Notion...");
907
+ }
908
+ const pages = await ListPages();
909
+ if (options.verbose) {
910
+ console.log(`Found ${pages.length} pages`);
911
+ console.log(`Save path: ${options.savePath}`);
912
+ console.log(`Sub path: ${options.subPath}`);
913
+ console.log(`Layout path: ${options.layoutPath}`);
914
+ }
915
+ const nob = new Noblog(pages, options.savePath, options.subPath, options.layoutPath);
916
+ await nob.Collect(true);
917
+ console.log(`✅ Successfully generated blog content`);
918
+ }
919
+ catch (error) {
920
+ console.error(`❌ Error generating blog content:`);
921
+ if (error instanceof Error) {
922
+ console.error(` ${error.message}`);
923
+ if (options.verbose) {
924
+ console.error(error.stack);
925
+ }
926
+ }
927
+ else {
928
+ console.error(` An unknown error occurred`);
929
+ }
930
+ process.exit(1);
931
+ }
726
932
  }
727
933
  async function main() {
728
934
  const argv = process.argv.slice(2);
729
- if (argv.length > 2) {
730
- console.error("Error: invallid arg.");
935
+ if (argv.length === 0) {
936
+ // Default behavior: generate with default options
937
+ await generateBlog({
938
+ verbose: false,
939
+ help: false,
940
+ version: false,
941
+ savePath: "./src/pages/posts/",
942
+ subPath: "nob_children/",
943
+ layoutPath: "../../layouts/MarkdownPostLayout.astro",
944
+ });
945
+ return;
946
+ }
947
+ const options = parseArgs(argv);
948
+ if (options.help) {
731
949
  help();
950
+ return;
732
951
  }
733
- const save_dir = argv[0] ?? "./src/pages/posts/";
734
- const sub_dir = argv[1] ?? "nob_children/";
735
- const pages = await GetAllPosts();
736
- const nob = new Noblog(pages, save_dir, sub_dir);
737
- nob.Collect(true);
952
+ if (options.version) {
953
+ console.log(`noblog v${getVersion()}`);
954
+ return;
955
+ }
956
+ await generateBlog(options);
738
957
  }
739
- main();
958
+ main().catch((error) => {
959
+ console.error(`❌ Unexpected error:`, error);
960
+ process.exit(1);
961
+ });
740
962
  //# sourceMappingURL=generate.cjs.map