noblog 0.0.13 → 0.2.0-beta
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 +169 -48
- package/dist/generate.cjs +407 -187
- package/dist/generate.cjs.map +1 -1
- package/dist/generate.js +408 -188
- package/dist/generate.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/{nomd → noblog}/format.d.ts +1 -16
- package/dist/lib/noblog/format.d.ts.map +1 -0
- package/dist/lib/noblog/noblog.d.ts +31 -0
- package/dist/lib/noblog/noblog.d.ts.map +1 -0
- package/dist/lib/noblog/utils.d.ts +36 -0
- package/dist/lib/noblog/utils.d.ts.map +1 -0
- package/dist/lib/notion/client.d.ts +4 -12
- package/dist/lib/notion/client.d.ts.map +1 -1
- package/package.json +19 -19
- package/dist/lib/nomd/format.d.ts.map +0 -1
- package/dist/lib/nomd/nomd.d.ts +0 -32
- package/dist/lib/nomd/nomd.d.ts.map +0 -1
- package/dist/lib/nomd/utils.d.ts +0 -6
- package/dist/lib/nomd/utils.d.ts.map +0 -1
- package/dist/lib/notion/object.d.ts +0 -148
- package/dist/lib/notion/object.d.ts.map +0 -1
- package/dist/lib/notion/request.d.ts +0 -36
- package/dist/lib/notion/request.d.ts.map +0 -1
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
|
|
159
|
-
const
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
197
|
+
}, { retries: numberOfRetry });
|
|
198
|
+
results = results.concat(resp.results);
|
|
199
|
+
if (!resp.has_more) {
|
|
200
|
+
break;
|
|
190
201
|
}
|
|
191
|
-
|
|
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
|
|
207
|
+
async function GetPage(page_id) {
|
|
201
208
|
const result = await retry(async (bail) => {
|
|
202
209
|
try {
|
|
203
|
-
return (await client.pages.retrieve({
|
|
210
|
+
return (await client.pages.retrieve({
|
|
211
|
+
page_id: page_id,
|
|
212
|
+
}));
|
|
204
213
|
}
|
|
205
214
|
catch (error) {
|
|
206
|
-
if (
|
|
207
|
-
|
|
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
|
|
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
|
-
|
|
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(
|
|
231
|
-
return
|
|
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,12 +318,14 @@ class Noblog {
|
|
|
259
318
|
if (save_path != undefined) {
|
|
260
319
|
this.SavePath = save_path;
|
|
261
320
|
}
|
|
262
|
-
|
|
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;
|
|
266
328
|
}
|
|
267
|
-
let sub_path;
|
|
268
329
|
// if (curr_page.id in this.Post) and (page.id in this.Post) ||
|
|
269
330
|
// (curr_page.id not in this.Post) and (page.id not in this.Post)
|
|
270
331
|
// * path should be "../pageid"
|
|
@@ -272,6 +333,7 @@ class Noblog {
|
|
|
272
333
|
// * path should be "../save_path/pageid"
|
|
273
334
|
// if (curr_page.id not in this.Post) and (page.id in this.Post)
|
|
274
335
|
// * path should be "../../pageid"
|
|
336
|
+
let sub_path;
|
|
275
337
|
const parent_surface = this.Posts.filter((post) => post.id === this.CurrPage).length > 0;
|
|
276
338
|
const child_surface = this.Posts.filter((post) => post.id === page.id).length > 0;
|
|
277
339
|
if (parent_surface === child_surface) {
|
|
@@ -284,21 +346,22 @@ class Noblog {
|
|
|
284
346
|
sub_path = "..";
|
|
285
347
|
}
|
|
286
348
|
const full_path = path__namespace.join("../", sub_path, page.id);
|
|
287
|
-
return
|
|
349
|
+
return `(」゚ロ゚)」 [${page.child_page.title}](${full_path})`;
|
|
288
350
|
};
|
|
289
351
|
}
|
|
290
|
-
|
|
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.
|
|
357
|
+
await this.FromPageId(page.id, recursive);
|
|
295
358
|
}
|
|
296
359
|
try {
|
|
297
|
-
for (const
|
|
360
|
+
for (const page_id of Object.keys(this.MdCollection)) {
|
|
298
361
|
let fpath = sub_dir;
|
|
299
|
-
if (this.Posts.find((page) => page.id ===
|
|
362
|
+
if (this.Posts.find((page) => page.id === page_id))
|
|
300
363
|
fpath = save_dir;
|
|
301
|
-
await
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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,68 +441,64 @@ 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
|
|
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 (
|
|
377
|
-
const block = blocks[i];
|
|
378
|
-
if (
|
|
448
|
+
for (const block of blocks) {
|
|
379
449
|
// @ts-ignore
|
|
380
|
-
block.type ===
|
|
450
|
+
if (block.type === BLOCK_UNSUPPORTED) {
|
|
381
451
|
continue;
|
|
382
452
|
}
|
|
383
|
-
if ("has_children" in block
|
|
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
|
-
// Recursively call BlocksToMarkdown to get children of this block.
|
|
391
|
-
// check for custom transformer before parsing child
|
|
392
|
-
if (!(block.type in this.CustomTransformers) &&
|
|
393
|
-
!this.CustomTransformers[block.type]) {
|
|
394
|
-
const l = mdBlocks.length;
|
|
395
|
-
if (mdBlocks !== undefined) {
|
|
396
|
-
await this.BlocksToMarkdown(child_blocks, totalPage, mdBlocks[l - 1]?.children);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
// Push this block to mdBlocks.
|
|
453
|
+
if (!("has_children" in block) || !block.has_children) {
|
|
400
454
|
mdBlocks.push({
|
|
455
|
+
// @ts-ignore
|
|
401
456
|
type: block.type,
|
|
402
457
|
blockId: block.id,
|
|
403
|
-
parent: await this.BlockToMarkdown(block),
|
|
404
458
|
children: [],
|
|
459
|
+
parent: await this.BlockToMarkdown(block),
|
|
405
460
|
});
|
|
406
461
|
continue;
|
|
407
462
|
}
|
|
408
|
-
const
|
|
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:
|
|
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
|
|
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];
|
|
426
|
-
const customTransformerValue = transformer(block);
|
|
496
|
+
const customTransformerValue = await transformer(block);
|
|
427
497
|
if (typeof customTransformerValue === "string")
|
|
428
498
|
return customTransformerValue;
|
|
429
499
|
}
|
|
430
500
|
switch (type) {
|
|
431
|
-
case
|
|
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
|
|
524
|
+
case BLOCK_DIVIDER:
|
|
455
525
|
return divider();
|
|
456
|
-
case
|
|
526
|
+
case BLOCK_EQUATION:
|
|
457
527
|
return equation(block.equation.expression);
|
|
458
|
-
case
|
|
459
|
-
case
|
|
460
|
-
case
|
|
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 ===
|
|
534
|
+
if (type === BLOCK_PDF)
|
|
465
535
|
blockContent = block.pdf;
|
|
466
|
-
if (type ===
|
|
536
|
+
if (type === BLOCK_FILE)
|
|
467
537
|
blockContent = block.file;
|
|
468
|
-
if (type ===
|
|
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
|
|
492
|
-
case
|
|
493
|
-
case
|
|
494
|
-
case
|
|
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 ===
|
|
568
|
+
if (type === BLOCK_EMBED)
|
|
499
569
|
blockContent = block.embed;
|
|
500
|
-
if (type ===
|
|
570
|
+
if (type === BLOCK_BOOKMARK)
|
|
501
571
|
blockContent = block.bookmark;
|
|
502
|
-
if (type ===
|
|
572
|
+
if (type === BLOCK_LINK_PREVIEW)
|
|
503
573
|
blockContent = block.link_preview;
|
|
504
|
-
if (type ===
|
|
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
|
|
584
|
+
case BLOCK_CHILD_PAGE: {
|
|
515
585
|
const pageTitle = block.child_page.title;
|
|
516
586
|
return heading2(pageTitle);
|
|
517
587
|
}
|
|
518
|
-
case
|
|
588
|
+
case BLOCK_CHILD_DATABASE: {
|
|
519
589
|
const pageTitle = block.child_database.title || `child_database`;
|
|
520
590
|
return heading2(pageTitle);
|
|
521
591
|
}
|
|
522
|
-
case
|
|
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:
|
|
606
|
+
type: BLOCK_PARAGRAPH,
|
|
537
607
|
paragraph: { rich_text: cell },
|
|
538
608
|
}));
|
|
539
609
|
const cellStringArr = await Promise.all(cellStringPromise);
|
|
@@ -616,125 +686,275 @@ class Noblog {
|
|
|
616
686
|
// @ts-ignore
|
|
617
687
|
bucket[to - 1] = bucket[to - 1] + sanno;
|
|
618
688
|
}
|
|
619
|
-
bucket.forEach((x) => (
|
|
689
|
+
bucket.forEach((x) => (renderedData += x));
|
|
620
690
|
}
|
|
621
691
|
}
|
|
622
692
|
switch (type) {
|
|
623
|
-
case
|
|
624
|
-
|
|
693
|
+
case BLOCK_CODE:
|
|
694
|
+
renderedData = codeBlock(renderedData, block[type].language);
|
|
625
695
|
break;
|
|
626
|
-
case
|
|
627
|
-
|
|
696
|
+
case BLOCK_HEADING_1:
|
|
697
|
+
renderedData = heading1(renderedData);
|
|
628
698
|
break;
|
|
629
|
-
case
|
|
630
|
-
|
|
699
|
+
case BLOCK_HEADING_2:
|
|
700
|
+
renderedData = heading2(renderedData);
|
|
631
701
|
break;
|
|
632
|
-
case
|
|
633
|
-
|
|
702
|
+
case BLOCK_HEADING_3:
|
|
703
|
+
renderedData = heading3(renderedData);
|
|
634
704
|
break;
|
|
635
|
-
case
|
|
636
|
-
|
|
705
|
+
case BLOCK_QUOTE:
|
|
706
|
+
renderedData = quote(renderedData);
|
|
637
707
|
break;
|
|
638
|
-
case
|
|
708
|
+
case BLOCK_CALLOUT:
|
|
639
709
|
const { id, has_children } = block;
|
|
640
710
|
let callout_string = "";
|
|
641
711
|
if (!has_children) {
|
|
642
|
-
return callout(
|
|
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 += `${
|
|
647
|
-
|
|
648
|
-
|
|
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
|
|
653
|
-
|
|
721
|
+
case BLOCK_BULLETED_LIST_ITEM:
|
|
722
|
+
renderedData = bullet(renderedData);
|
|
654
723
|
break;
|
|
655
|
-
case
|
|
656
|
-
|
|
724
|
+
case BLOCK_NUMBERED_LIST_ITEM:
|
|
725
|
+
renderedData = bullet(renderedData, block.numbered_list_item.number);
|
|
657
726
|
break;
|
|
658
|
-
case
|
|
659
|
-
|
|
727
|
+
case BLOCK_TO_DO:
|
|
728
|
+
renderedData = todo(renderedData, block.to_do.checked);
|
|
660
729
|
break;
|
|
661
730
|
}
|
|
662
|
-
return
|
|
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
|
-
//
|
|
735
|
+
// Default layout
|
|
685
736
|
const ischild = this.Posts.filter((post) => post.id === page.id).length > 0 ? "" : "../";
|
|
686
|
-
frontmatter +=
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
"
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
"
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
737
|
+
frontmatter += "layout: " + ischild + this.LayoutPath + "\n";
|
|
738
|
+
Object.entries(page.properties).forEach(([key, property]) => {
|
|
739
|
+
switch (property.type) {
|
|
740
|
+
case "title": // Get title
|
|
741
|
+
frontmatter +=
|
|
742
|
+
"title: " +
|
|
743
|
+
JSON.stringify(property.title
|
|
744
|
+
?.map((title) => title.plain_text)
|
|
745
|
+
.reduce((a, b) => a + b)) +
|
|
746
|
+
"\n";
|
|
747
|
+
break;
|
|
748
|
+
case "multi_select": // Get tags
|
|
749
|
+
frontmatter +=
|
|
750
|
+
"tags: " +
|
|
751
|
+
JSON.stringify(property.multi_select.map((tag) => tag.name)) +
|
|
752
|
+
"\n";
|
|
753
|
+
break;
|
|
754
|
+
case "date": // Get date
|
|
755
|
+
frontmatter +=
|
|
756
|
+
"pubDate: " +
|
|
757
|
+
(property.date?.start ?? new Date().toISOString().split("T")[0]) +
|
|
758
|
+
"\n";
|
|
759
|
+
break;
|
|
760
|
+
default: // Customized properties from the template given in the Github repo
|
|
761
|
+
switch (key) {
|
|
762
|
+
case "archived": // Get archived
|
|
763
|
+
if (property.type === "checkbox")
|
|
764
|
+
frontmatter +=
|
|
765
|
+
"archived: " + property.checkbox
|
|
766
|
+
? "true"
|
|
767
|
+
: "false" + "\n";
|
|
768
|
+
break;
|
|
769
|
+
case "description": // Get description
|
|
770
|
+
if (property.type === "rich_text")
|
|
771
|
+
frontmatter +=
|
|
772
|
+
"description: " +
|
|
773
|
+
JSON.stringify(property.rich_text?.[0]?.plain_text ?? "") +
|
|
774
|
+
"\n";
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
});
|
|
712
779
|
return "---\n" + frontmatter + "---\n";
|
|
713
780
|
}
|
|
714
781
|
}
|
|
715
782
|
|
|
783
|
+
function getVersion() {
|
|
784
|
+
try {
|
|
785
|
+
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)));
|
|
786
|
+
const __dirname = path.dirname(__filename);
|
|
787
|
+
const packagePath = path.join(__dirname, "../../package.json");
|
|
788
|
+
const packageJson = JSON.parse(fs$1.readFileSync(packagePath, "utf-8"));
|
|
789
|
+
return packageJson.version;
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
return "unknown";
|
|
793
|
+
}
|
|
794
|
+
}
|
|
716
795
|
function help() {
|
|
717
|
-
console.log(
|
|
718
|
-
|
|
796
|
+
console.log(`
|
|
797
|
+
noblog - Generate static blog content from Notion.so
|
|
798
|
+
|
|
799
|
+
Usage: noblog [command] [options] [SAVE_PATH] [SUB_PATH]
|
|
800
|
+
|
|
801
|
+
Options:
|
|
802
|
+
-v, --verbose Print more messages for debugging
|
|
803
|
+
-h, --help Show help message
|
|
804
|
+
--version Show version information
|
|
805
|
+
--layout PATH Custom layout path (default: ../../layouts/MarkdownPostLayout.astro)
|
|
806
|
+
|
|
807
|
+
Commands:
|
|
808
|
+
help Show this help message
|
|
809
|
+
version Show version information
|
|
810
|
+
generate Generate blog content (default command)
|
|
811
|
+
|
|
812
|
+
Options:
|
|
813
|
+
-v, --verbose Print more messages for debugging
|
|
814
|
+
-h, --help Show help message
|
|
815
|
+
--version Show version information
|
|
816
|
+
|
|
817
|
+
Arguments:
|
|
818
|
+
SAVE_PATH Directory to save main posts (default: ./src/pages/posts/)
|
|
819
|
+
SUB_PATH Subdirectory for nested content (default: nob_children/)
|
|
719
820
|
|
|
720
|
-
|
|
721
|
-
|
|
821
|
+
Layout Options:
|
|
822
|
+
--layout PATH Custom layout path relative to save directory (default: ../../layouts/MarkdownPostLayout.astro)
|
|
823
|
+
|
|
824
|
+
Examples:
|
|
825
|
+
noblog help
|
|
826
|
+
noblog version
|
|
827
|
+
noblog generate
|
|
828
|
+
noblog -v
|
|
722
829
|
noblog src/pages/posts/ nob_children/
|
|
830
|
+
noblog --layout ../../layouts/BlogLayout.astro
|
|
831
|
+
noblog src/posts/ children/ --layout ../../../layouts/CustomLayout.astro -v
|
|
723
832
|
|
|
724
|
-
|
|
725
|
-
|
|
833
|
+
Environment Variables:
|
|
834
|
+
NOTION_API_SECRET Your Notion API secret
|
|
835
|
+
NOBLOG_DATABASE_ID Your Notion database ID
|
|
836
|
+
`);
|
|
837
|
+
}
|
|
838
|
+
function parseArgs(argv) {
|
|
839
|
+
const options = {
|
|
840
|
+
verbose: false,
|
|
841
|
+
help: false,
|
|
842
|
+
version: false,
|
|
843
|
+
savePath: "./src/pages/posts/",
|
|
844
|
+
subPath: "nob_children/",
|
|
845
|
+
layoutPath: "../../layouts/MarkdownPostLayout.astro",
|
|
846
|
+
};
|
|
847
|
+
const positionalArgs = [];
|
|
848
|
+
for (let i = 0; i < argv.length; i++) {
|
|
849
|
+
const arg = argv[i];
|
|
850
|
+
switch (arg) {
|
|
851
|
+
case "-v":
|
|
852
|
+
case "--verbose":
|
|
853
|
+
options.verbose = true;
|
|
854
|
+
break;
|
|
855
|
+
case "-h":
|
|
856
|
+
case "--help":
|
|
857
|
+
case "help":
|
|
858
|
+
options.help = true;
|
|
859
|
+
break;
|
|
860
|
+
case "--version":
|
|
861
|
+
case "version":
|
|
862
|
+
options.version = true;
|
|
863
|
+
break;
|
|
864
|
+
case "--layout":
|
|
865
|
+
if (i + 1 < argv.length && !argv[i + 1].startsWith("-")) {
|
|
866
|
+
options.layoutPath = argv[++i];
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
console.error("Error: --layout requires a path argument");
|
|
870
|
+
help();
|
|
871
|
+
process.exit(1);
|
|
872
|
+
}
|
|
873
|
+
break;
|
|
874
|
+
case "generate":
|
|
875
|
+
// Explicit generate command, skip it
|
|
876
|
+
break;
|
|
877
|
+
default:
|
|
878
|
+
if (arg.startsWith("-")) {
|
|
879
|
+
console.error(`Unknown option: ${arg}`);
|
|
880
|
+
help();
|
|
881
|
+
process.exit(1);
|
|
882
|
+
}
|
|
883
|
+
positionalArgs.push(arg);
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
// Handle positional arguments
|
|
888
|
+
if (positionalArgs.length > 0) {
|
|
889
|
+
options.savePath = positionalArgs[0];
|
|
890
|
+
}
|
|
891
|
+
if (positionalArgs.length > 1) {
|
|
892
|
+
options.subPath = positionalArgs[1];
|
|
893
|
+
}
|
|
894
|
+
if (positionalArgs.length > 2) {
|
|
895
|
+
console.error("Error: Too many arguments.");
|
|
896
|
+
help();
|
|
897
|
+
process.exit(1);
|
|
898
|
+
}
|
|
899
|
+
return options;
|
|
900
|
+
}
|
|
901
|
+
async function generateBlog(options) {
|
|
902
|
+
try {
|
|
903
|
+
if (options.verbose) {
|
|
904
|
+
console.log("Fetching posts from Notion...");
|
|
905
|
+
}
|
|
906
|
+
const pages = await ListPages();
|
|
907
|
+
if (options.verbose) {
|
|
908
|
+
console.log(`Found ${pages.length} pages`);
|
|
909
|
+
console.log(`Save path: ${options.savePath}`);
|
|
910
|
+
console.log(`Sub path: ${options.subPath}`);
|
|
911
|
+
console.log(`Layout path: ${options.layoutPath}`);
|
|
912
|
+
}
|
|
913
|
+
const nob = new Noblog(pages, options.savePath, options.subPath, options.layoutPath);
|
|
914
|
+
await nob.Collect(true);
|
|
915
|
+
console.log(`✅ Successfully generated blog content`);
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
console.error(`❌ Error generating blog content:`);
|
|
919
|
+
if (error instanceof Error) {
|
|
920
|
+
console.error(` ${error.message}`);
|
|
921
|
+
if (options.verbose) {
|
|
922
|
+
console.error(error.stack);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
console.error(` An unknown error occurred`);
|
|
927
|
+
}
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
726
930
|
}
|
|
727
931
|
async function main() {
|
|
728
932
|
const argv = process.argv.slice(2);
|
|
729
|
-
if (argv.length
|
|
730
|
-
|
|
933
|
+
if (argv.length === 0) {
|
|
934
|
+
// Default behavior: generate with default options
|
|
935
|
+
await generateBlog({
|
|
936
|
+
verbose: false,
|
|
937
|
+
help: false,
|
|
938
|
+
version: false,
|
|
939
|
+
savePath: "./src/pages/posts/",
|
|
940
|
+
subPath: "nob_children/",
|
|
941
|
+
layoutPath: "../../layouts/MarkdownPostLayout.astro",
|
|
942
|
+
});
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
const options = parseArgs(argv);
|
|
946
|
+
if (options.help) {
|
|
731
947
|
help();
|
|
948
|
+
return;
|
|
732
949
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
950
|
+
if (options.version) {
|
|
951
|
+
console.log(`noblog v${getVersion()}`);
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
await generateBlog(options);
|
|
738
955
|
}
|
|
739
|
-
main()
|
|
956
|
+
main().catch((error) => {
|
|
957
|
+
console.error(`❌ Unexpected error:`, error);
|
|
958
|
+
process.exit(1);
|
|
959
|
+
});
|
|
740
960
|
//# sourceMappingURL=generate.cjs.map
|