@atikk-co-jp/notion-mcp-server 0.7.0 → 0.8.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.
Files changed (134) hide show
  1. package/README.ja.md +3 -2
  2. package/README.md +3 -2
  3. package/dist/src/converters/__tests__/block-to-markdown.test.js +482 -111
  4. package/dist/src/converters/__tests__/markdown-to-blocks.test.js +116 -13
  5. package/dist/src/converters/__tests__/page-to-markdown.test.js +83 -70
  6. package/dist/src/converters/__tests__/rich-text-to-markdown.test.js +23 -26
  7. package/dist/src/converters/block-to-markdown.d.ts +4 -13
  8. package/dist/src/converters/block-to-markdown.d.ts.map +1 -1
  9. package/dist/src/converters/block-to-markdown.js +117 -120
  10. package/dist/src/converters/index.d.ts +3 -3
  11. package/dist/src/converters/index.d.ts.map +1 -1
  12. package/dist/src/converters/index.js +1 -1
  13. package/dist/src/converters/markdown-to-blocks.d.ts +21 -7
  14. package/dist/src/converters/markdown-to-blocks.d.ts.map +1 -1
  15. package/dist/src/converters/markdown-to-blocks.js +56 -0
  16. package/dist/src/converters/page-to-markdown.d.ts +5 -20
  17. package/dist/src/converters/page-to-markdown.d.ts.map +1 -1
  18. package/dist/src/converters/page-to-markdown.js +47 -37
  19. package/dist/src/converters/rich-text-to-markdown.d.ts +3 -47
  20. package/dist/src/converters/rich-text-to-markdown.d.ts.map +1 -1
  21. package/dist/src/converters/rich-text-to-markdown.js +15 -14
  22. package/dist/src/notion-client.d.ts +5 -177
  23. package/dist/src/notion-client.d.ts.map +1 -1
  24. package/dist/src/notion-client.js +6 -172
  25. package/dist/src/schemas/descriptions/examples.d.ts +14 -0
  26. package/dist/src/schemas/descriptions/examples.d.ts.map +1 -0
  27. package/dist/src/schemas/descriptions/examples.js +87 -0
  28. package/dist/src/schemas/descriptions/fields.d.ts +146 -0
  29. package/dist/src/schemas/descriptions/fields.d.ts.map +1 -0
  30. package/dist/src/schemas/descriptions/fields.js +184 -0
  31. package/dist/src/schemas/descriptions/index.d.ts +3 -0
  32. package/dist/src/schemas/descriptions/index.d.ts.map +1 -0
  33. package/dist/src/schemas/descriptions/index.js +2 -0
  34. package/dist/src/schemas/index.d.ts +1 -5
  35. package/dist/src/schemas/index.d.ts.map +1 -1
  36. package/dist/src/schemas/index.js +2 -10
  37. package/dist/src/tools/__tests__/context-size.test.d.ts +2 -0
  38. package/dist/src/tools/__tests__/context-size.test.d.ts.map +1 -0
  39. package/dist/src/tools/__tests__/context-size.test.js +143 -0
  40. package/dist/src/tools/__tests__/error-handler.test.d.ts +2 -0
  41. package/dist/src/tools/__tests__/error-handler.test.d.ts.map +1 -0
  42. package/dist/src/tools/__tests__/error-handler.test.js +125 -0
  43. package/dist/src/tools/append-block-children.d.ts.map +1 -1
  44. package/dist/src/tools/append-block-children.js +8 -5
  45. package/dist/src/tools/append-blocks-simple.d.ts.map +1 -1
  46. package/dist/src/tools/append-blocks-simple.js +9 -13
  47. package/dist/src/tools/archive-database.d.ts.map +1 -1
  48. package/dist/src/tools/archive-database.js +3 -2
  49. package/dist/src/tools/archive-page.d.ts.map +1 -1
  50. package/dist/src/tools/archive-page.js +2 -1
  51. package/dist/src/tools/create-comment-simple.d.ts.map +1 -1
  52. package/dist/src/tools/create-comment-simple.js +5 -4
  53. package/dist/src/tools/create-comment.d.ts.map +1 -1
  54. package/dist/src/tools/create-comment.js +9 -6
  55. package/dist/src/tools/create-database.d.ts.map +1 -1
  56. package/dist/src/tools/create-database.js +19 -25
  57. package/dist/src/tools/create-page-simple.d.ts +1 -1
  58. package/dist/src/tools/create-page-simple.d.ts.map +1 -1
  59. package/dist/src/tools/create-page-simple.js +26 -27
  60. package/dist/src/tools/create-page.d.ts.map +1 -1
  61. package/dist/src/tools/create-page.js +10 -6
  62. package/dist/src/tools/delete-block.d.ts.map +1 -1
  63. package/dist/src/tools/delete-block.js +2 -1
  64. package/dist/src/tools/get-block-children.d.ts +1 -1
  65. package/dist/src/tools/get-block-children.d.ts.map +1 -1
  66. package/dist/src/tools/get-block-children.js +13 -27
  67. package/dist/src/tools/index.d.ts +2 -2
  68. package/dist/src/tools/index.d.ts.map +1 -1
  69. package/dist/src/tools/index.js +2 -2
  70. package/dist/src/tools/list-comments.d.ts +1 -1
  71. package/dist/src/tools/list-comments.d.ts.map +1 -1
  72. package/dist/src/tools/list-comments.js +11 -10
  73. package/dist/src/tools/list-users.d.ts.map +1 -1
  74. package/dist/src/tools/list-users.js +4 -3
  75. package/dist/src/tools/move-page.d.ts.map +1 -1
  76. package/dist/src/tools/move-page.js +5 -4
  77. package/dist/src/tools/query-data-source.d.ts +1 -1
  78. package/dist/src/tools/query-data-source.d.ts.map +1 -1
  79. package/dist/src/tools/query-data-source.js +23 -30
  80. package/dist/src/tools/retrieve-block.d.ts +1 -1
  81. package/dist/src/tools/retrieve-block.d.ts.map +1 -1
  82. package/dist/src/tools/retrieve-block.js +13 -10
  83. package/dist/src/tools/retrieve-bot-user.js +1 -1
  84. package/dist/src/tools/retrieve-data-source.d.ts +1 -1
  85. package/dist/src/tools/retrieve-data-source.d.ts.map +1 -1
  86. package/dist/src/tools/retrieve-data-source.js +15 -11
  87. package/dist/src/tools/retrieve-database.d.ts +1 -1
  88. package/dist/src/tools/retrieve-database.d.ts.map +1 -1
  89. package/dist/src/tools/retrieve-database.js +11 -6
  90. package/dist/src/tools/retrieve-page-property.d.ts.map +1 -1
  91. package/dist/src/tools/retrieve-page-property.js +6 -5
  92. package/dist/src/tools/retrieve-page.d.ts +1 -1
  93. package/dist/src/tools/retrieve-page.d.ts.map +1 -1
  94. package/dist/src/tools/retrieve-page.js +15 -20
  95. package/dist/src/tools/retrieve-user.d.ts.map +1 -1
  96. package/dist/src/tools/retrieve-user.js +2 -1
  97. package/dist/src/tools/search.d.ts.map +1 -1
  98. package/dist/src/tools/search.js +10 -17
  99. package/dist/src/tools/update-block-simple.d.ts +1 -1
  100. package/dist/src/tools/update-block-simple.d.ts.map +1 -1
  101. package/dist/src/tools/update-block-simple.js +14 -4
  102. package/dist/src/tools/update-block.d.ts.map +1 -1
  103. package/dist/src/tools/update-block.js +8 -5
  104. package/dist/src/tools/update-data-source.d.ts.map +1 -1
  105. package/dist/src/tools/update-data-source.js +7 -7
  106. package/dist/src/tools/update-database.d.ts.map +1 -1
  107. package/dist/src/tools/update-database.js +22 -32
  108. package/dist/src/tools/update-page.d.ts.map +1 -1
  109. package/dist/src/tools/update-page.js +11 -8
  110. package/dist/src/utils/error-handler.d.ts +16 -7
  111. package/dist/src/utils/error-handler.d.ts.map +1 -1
  112. package/dist/src/utils/error-handler.js +44 -17
  113. package/dist/src/utils/index.d.ts +1 -1
  114. package/dist/src/utils/index.d.ts.map +1 -1
  115. package/dist/src/utils/index.js +1 -1
  116. package/package.json +2 -1
  117. package/dist/src/schemas/block.d.ts +0 -3787
  118. package/dist/src/schemas/block.d.ts.map +0 -1
  119. package/dist/src/schemas/block.js +0 -402
  120. package/dist/src/schemas/common.d.ts +0 -638
  121. package/dist/src/schemas/common.d.ts.map +0 -1
  122. package/dist/src/schemas/common.js +0 -163
  123. package/dist/src/schemas/database.d.ts +0 -687
  124. package/dist/src/schemas/database.d.ts.map +0 -1
  125. package/dist/src/schemas/database.js +0 -258
  126. package/dist/src/schemas/filter.d.ts +0 -611
  127. package/dist/src/schemas/filter.d.ts.map +0 -1
  128. package/dist/src/schemas/filter.js +0 -222
  129. package/dist/src/schemas/page.d.ts +0 -2607
  130. package/dist/src/schemas/page.d.ts.map +0 -1
  131. package/dist/src/schemas/page.js +0 -328
  132. package/dist/src/schemas/schemas.test.d.ts +0 -2
  133. package/dist/src/schemas/schemas.test.d.ts.map +0 -1
  134. package/dist/src/schemas/schemas.test.js +0 -418
@@ -1,25 +1,34 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
2
  import { blocksToMarkdown, blocksToMarkdownSync } from '../block-to-markdown.js';
3
+ /**
4
+ * テスト用のブロックデータをBlockObjectResponse[]にキャストするヘルパー
5
+ * SDK の BlockObjectResponse は多くの必須フィールド(id, created_time等)を要求するため、
6
+ * テストでは最小限のデータで unknown 経由でキャストして使用
7
+ */
8
+ const asBlocks = (blocks) => blocks;
3
9
  describe('blocksToMarkdownSync', () => {
4
10
  describe('basic blocks', () => {
5
11
  it('converts paragraph block', () => {
6
- const blocks = [
12
+ const blocks = asBlocks([
7
13
  {
8
14
  type: 'paragraph',
9
15
  paragraph: {
10
- rich_text: [{ type: 'text', text: { content: 'Hello World' } }],
16
+ rich_text: [
17
+ { type: 'text', text: { content: 'Hello World' }, plain_text: 'Hello World' },
18
+ ],
19
+ color: 'default',
11
20
  },
12
21
  },
13
- ];
22
+ ]);
14
23
  expect(blocksToMarkdownSync(blocks)).toBe('Hello World');
15
24
  });
16
25
  it('handles empty paragraph', () => {
17
- const blocks = [
26
+ const blocks = asBlocks([
18
27
  {
19
28
  type: 'paragraph',
20
- paragraph: { rich_text: [] },
29
+ paragraph: { rich_text: [], color: 'default' },
21
30
  },
22
- ];
31
+ ]);
23
32
  expect(blocksToMarkdownSync(blocks)).toBe('');
24
33
  });
25
34
  it('handles empty array', () => {
@@ -31,296 +40,617 @@ describe('blocksToMarkdownSync', () => {
31
40
  });
32
41
  describe('headings', () => {
33
42
  it('converts heading_1', () => {
34
- const blocks = [
43
+ const blocks = asBlocks([
35
44
  {
36
45
  type: 'heading_1',
37
46
  heading_1: {
38
- rich_text: [{ type: 'text', text: { content: 'Heading 1' } }],
47
+ rich_text: [
48
+ {
49
+ type: 'text',
50
+ text: { content: 'Heading 1' },
51
+ plain_text: 'Heading 1',
52
+ annotations: {
53
+ bold: false,
54
+ italic: false,
55
+ strikethrough: false,
56
+ underline: false,
57
+ code: false,
58
+ color: 'default',
59
+ },
60
+ href: null,
61
+ },
62
+ ],
39
63
  },
40
64
  },
41
- ];
65
+ ]);
42
66
  expect(blocksToMarkdownSync(blocks)).toBe('# Heading 1');
43
67
  });
44
68
  it('converts heading_2', () => {
45
- const blocks = [
69
+ const blocks = asBlocks([
46
70
  {
47
71
  type: 'heading_2',
48
72
  heading_2: {
49
- rich_text: [{ type: 'text', text: { content: 'Heading 2' } }],
73
+ rich_text: [
74
+ {
75
+ type: 'text',
76
+ text: { content: 'Heading 2' },
77
+ plain_text: 'Heading 2',
78
+ annotations: {
79
+ bold: false,
80
+ italic: false,
81
+ strikethrough: false,
82
+ underline: false,
83
+ code: false,
84
+ color: 'default',
85
+ },
86
+ href: null,
87
+ },
88
+ ],
50
89
  },
51
90
  },
52
- ];
91
+ ]);
53
92
  expect(blocksToMarkdownSync(blocks)).toBe('## Heading 2');
54
93
  });
55
94
  it('converts heading_3', () => {
56
- const blocks = [
95
+ const blocks = asBlocks([
57
96
  {
58
97
  type: 'heading_3',
59
98
  heading_3: {
60
- rich_text: [{ type: 'text', text: { content: 'Heading 3' } }],
99
+ rich_text: [
100
+ {
101
+ type: 'text',
102
+ text: { content: 'Heading 3' },
103
+ plain_text: 'Heading 3',
104
+ annotations: {
105
+ bold: false,
106
+ italic: false,
107
+ strikethrough: false,
108
+ underline: false,
109
+ code: false,
110
+ color: 'default',
111
+ },
112
+ href: null,
113
+ },
114
+ ],
61
115
  },
62
116
  },
63
- ];
117
+ ]);
64
118
  expect(blocksToMarkdownSync(blocks)).toBe('### Heading 3');
65
119
  });
66
120
  });
67
121
  describe('list items', () => {
68
122
  it('converts bulleted_list_item', () => {
69
- const blocks = [
123
+ const blocks = asBlocks([
70
124
  {
71
125
  type: 'bulleted_list_item',
72
126
  bulleted_list_item: {
73
- rich_text: [{ type: 'text', text: { content: 'Item 1' } }],
127
+ rich_text: [
128
+ {
129
+ type: 'text',
130
+ text: { content: 'Item 1' },
131
+ plain_text: 'Item 1',
132
+ annotations: {
133
+ bold: false,
134
+ italic: false,
135
+ strikethrough: false,
136
+ underline: false,
137
+ code: false,
138
+ color: 'default',
139
+ },
140
+ href: null,
141
+ },
142
+ ],
74
143
  },
75
144
  },
76
145
  {
77
146
  type: 'bulleted_list_item',
78
147
  bulleted_list_item: {
79
- rich_text: [{ type: 'text', text: { content: 'Item 2' } }],
148
+ rich_text: [
149
+ {
150
+ type: 'text',
151
+ text: { content: 'Item 2' },
152
+ plain_text: 'Item 2',
153
+ annotations: {
154
+ bold: false,
155
+ italic: false,
156
+ strikethrough: false,
157
+ underline: false,
158
+ code: false,
159
+ color: 'default',
160
+ },
161
+ href: null,
162
+ },
163
+ ],
80
164
  },
81
165
  },
82
- ];
166
+ ]);
83
167
  expect(blocksToMarkdownSync(blocks)).toBe('- Item 1\n- Item 2');
84
168
  });
85
169
  it('converts numbered_list_item with correct indices', () => {
86
- const blocks = [
170
+ const blocks = asBlocks([
87
171
  {
88
172
  type: 'numbered_list_item',
89
173
  numbered_list_item: {
90
- rich_text: [{ type: 'text', text: { content: 'First' } }],
174
+ rich_text: [
175
+ {
176
+ type: 'text',
177
+ text: { content: 'First' },
178
+ plain_text: 'First',
179
+ annotations: {
180
+ bold: false,
181
+ italic: false,
182
+ strikethrough: false,
183
+ underline: false,
184
+ code: false,
185
+ color: 'default',
186
+ },
187
+ href: null,
188
+ },
189
+ ],
91
190
  },
92
191
  },
93
192
  {
94
193
  type: 'numbered_list_item',
95
194
  numbered_list_item: {
96
- rich_text: [{ type: 'text', text: { content: 'Second' } }],
195
+ rich_text: [
196
+ {
197
+ type: 'text',
198
+ text: { content: 'Second' },
199
+ plain_text: 'Second',
200
+ annotations: {
201
+ bold: false,
202
+ italic: false,
203
+ strikethrough: false,
204
+ underline: false,
205
+ code: false,
206
+ color: 'default',
207
+ },
208
+ href: null,
209
+ },
210
+ ],
97
211
  },
98
212
  },
99
213
  {
100
214
  type: 'numbered_list_item',
101
215
  numbered_list_item: {
102
- rich_text: [{ type: 'text', text: { content: 'Third' } }],
216
+ rich_text: [
217
+ {
218
+ type: 'text',
219
+ text: { content: 'Third' },
220
+ plain_text: 'Third',
221
+ annotations: {
222
+ bold: false,
223
+ italic: false,
224
+ strikethrough: false,
225
+ underline: false,
226
+ code: false,
227
+ color: 'default',
228
+ },
229
+ href: null,
230
+ },
231
+ ],
103
232
  },
104
233
  },
105
- ];
234
+ ]);
106
235
  expect(blocksToMarkdownSync(blocks)).toBe('1. First\n2. Second\n3. Third');
107
236
  });
108
237
  it('resets numbered list index after non-list block', () => {
109
- const blocks = [
238
+ const blocks = asBlocks([
110
239
  {
111
240
  type: 'numbered_list_item',
112
241
  numbered_list_item: {
113
- rich_text: [{ type: 'text', text: { content: 'First' } }],
242
+ rich_text: [
243
+ {
244
+ type: 'text',
245
+ text: { content: 'First' },
246
+ plain_text: 'First',
247
+ annotations: {
248
+ bold: false,
249
+ italic: false,
250
+ strikethrough: false,
251
+ underline: false,
252
+ code: false,
253
+ color: 'default',
254
+ },
255
+ href: null,
256
+ },
257
+ ],
114
258
  },
115
259
  },
116
260
  {
117
261
  type: 'paragraph',
118
262
  paragraph: {
119
- rich_text: [{ type: 'text', text: { content: 'Break' } }],
263
+ rich_text: [
264
+ {
265
+ type: 'text',
266
+ text: { content: 'Break' },
267
+ plain_text: 'Break',
268
+ annotations: {
269
+ bold: false,
270
+ italic: false,
271
+ strikethrough: false,
272
+ underline: false,
273
+ code: false,
274
+ color: 'default',
275
+ },
276
+ href: null,
277
+ },
278
+ ],
120
279
  },
121
280
  },
122
281
  {
123
282
  type: 'numbered_list_item',
124
283
  numbered_list_item: {
125
- rich_text: [{ type: 'text', text: { content: 'New First' } }],
284
+ rich_text: [
285
+ {
286
+ type: 'text',
287
+ text: { content: 'New First' },
288
+ plain_text: 'New First',
289
+ annotations: {
290
+ bold: false,
291
+ italic: false,
292
+ strikethrough: false,
293
+ underline: false,
294
+ code: false,
295
+ color: 'default',
296
+ },
297
+ href: null,
298
+ },
299
+ ],
126
300
  },
127
301
  },
128
- ];
302
+ ]);
129
303
  expect(blocksToMarkdownSync(blocks)).toBe('1. First\nBreak\n1. New First');
130
304
  });
131
305
  });
132
306
  describe('to_do', () => {
133
307
  it('converts unchecked to_do', () => {
134
- const blocks = [
308
+ const blocks = asBlocks([
135
309
  {
136
310
  type: 'to_do',
137
311
  to_do: {
138
- rich_text: [{ type: 'text', text: { content: 'Task' } }],
312
+ rich_text: [
313
+ {
314
+ type: 'text',
315
+ text: { content: 'Task' },
316
+ plain_text: 'Task',
317
+ annotations: {
318
+ bold: false,
319
+ italic: false,
320
+ strikethrough: false,
321
+ underline: false,
322
+ code: false,
323
+ color: 'default',
324
+ },
325
+ href: null,
326
+ },
327
+ ],
139
328
  checked: false,
140
329
  },
141
330
  },
142
- ];
331
+ ]);
143
332
  expect(blocksToMarkdownSync(blocks)).toBe('- [ ] Task');
144
333
  });
145
334
  it('converts checked to_do', () => {
146
- const blocks = [
335
+ const blocks = asBlocks([
147
336
  {
148
337
  type: 'to_do',
149
338
  to_do: {
150
- rich_text: [{ type: 'text', text: { content: 'Done Task' } }],
339
+ rich_text: [
340
+ {
341
+ type: 'text',
342
+ text: { content: 'Done Task' },
343
+ plain_text: 'Done Task',
344
+ annotations: {
345
+ bold: false,
346
+ italic: false,
347
+ strikethrough: false,
348
+ underline: false,
349
+ code: false,
350
+ color: 'default',
351
+ },
352
+ href: null,
353
+ },
354
+ ],
151
355
  checked: true,
152
356
  },
153
357
  },
154
- ];
358
+ ]);
155
359
  expect(blocksToMarkdownSync(blocks)).toBe('- [x] Done Task');
156
360
  });
157
361
  });
158
362
  describe('code block', () => {
159
363
  it('converts code block with language', () => {
160
- const blocks = [
364
+ const blocks = asBlocks([
161
365
  {
162
366
  type: 'code',
163
367
  code: {
164
- rich_text: [{ type: 'text', text: { content: "console.log('hello')" } }],
368
+ rich_text: [
369
+ {
370
+ type: 'text',
371
+ text: { content: "console.log('hello')" },
372
+ plain_text: "console.log('hello')",
373
+ annotations: {
374
+ bold: false,
375
+ italic: false,
376
+ strikethrough: false,
377
+ underline: false,
378
+ code: false,
379
+ color: 'default',
380
+ },
381
+ href: null,
382
+ },
383
+ ],
165
384
  language: 'javascript',
166
385
  },
167
386
  },
168
- ];
387
+ ]);
169
388
  expect(blocksToMarkdownSync(blocks)).toBe("```javascript\nconsole.log('hello')\n```");
170
389
  });
171
390
  it('converts code block without language', () => {
172
- const blocks = [
391
+ const blocks = asBlocks([
173
392
  {
174
393
  type: 'code',
175
394
  code: {
176
- rich_text: [{ type: 'text', text: { content: 'plain code' } }],
395
+ rich_text: [
396
+ {
397
+ type: 'text',
398
+ text: { content: 'plain code' },
399
+ plain_text: 'plain code',
400
+ annotations: {
401
+ bold: false,
402
+ italic: false,
403
+ strikethrough: false,
404
+ underline: false,
405
+ code: false,
406
+ color: 'default',
407
+ },
408
+ href: null,
409
+ },
410
+ ],
411
+ language: '',
177
412
  },
178
413
  },
179
- ];
414
+ ]);
180
415
  expect(blocksToMarkdownSync(blocks)).toBe('```\nplain code\n```');
181
416
  });
182
417
  });
183
418
  describe('quote and callout', () => {
184
419
  it('converts quote', () => {
185
- const blocks = [
420
+ const blocks = asBlocks([
186
421
  {
187
422
  type: 'quote',
188
423
  quote: {
189
- rich_text: [{ type: 'text', text: { content: 'A wise quote' } }],
424
+ rich_text: [
425
+ {
426
+ type: 'text',
427
+ text: { content: 'A wise quote' },
428
+ plain_text: 'A wise quote',
429
+ annotations: {
430
+ bold: false,
431
+ italic: false,
432
+ strikethrough: false,
433
+ underline: false,
434
+ code: false,
435
+ color: 'default',
436
+ },
437
+ href: null,
438
+ },
439
+ ],
190
440
  },
191
441
  },
192
- ];
442
+ ]);
193
443
  expect(blocksToMarkdownSync(blocks)).toBe('> A wise quote');
194
444
  });
195
445
  it('converts multiline quote', () => {
196
- const blocks = [
446
+ const blocks = asBlocks([
197
447
  {
198
448
  type: 'quote',
199
449
  quote: {
200
- rich_text: [{ type: 'text', text: { content: 'Line 1\nLine 2' } }],
450
+ rich_text: [
451
+ {
452
+ type: 'text',
453
+ text: { content: 'Line 1\nLine 2' },
454
+ plain_text: 'Line 1\nLine 2',
455
+ annotations: {
456
+ bold: false,
457
+ italic: false,
458
+ strikethrough: false,
459
+ underline: false,
460
+ code: false,
461
+ color: 'default',
462
+ },
463
+ href: null,
464
+ },
465
+ ],
201
466
  },
202
467
  },
203
- ];
468
+ ]);
204
469
  expect(blocksToMarkdownSync(blocks)).toBe('> Line 1\n> Line 2');
205
470
  });
206
471
  it('converts callout with emoji icon', () => {
207
- const blocks = [
472
+ const blocks = asBlocks([
208
473
  {
209
474
  type: 'callout',
210
475
  callout: {
211
- rich_text: [{ type: 'text', text: { content: 'Important info' } }],
476
+ rich_text: [
477
+ {
478
+ type: 'text',
479
+ text: { content: 'Important info' },
480
+ plain_text: 'Important info',
481
+ annotations: {
482
+ bold: false,
483
+ italic: false,
484
+ strikethrough: false,
485
+ underline: false,
486
+ code: false,
487
+ color: 'default',
488
+ },
489
+ href: null,
490
+ },
491
+ ],
212
492
  icon: { type: 'emoji', emoji: '💡' },
213
493
  },
214
494
  },
215
- ];
495
+ ]);
216
496
  expect(blocksToMarkdownSync(blocks)).toBe('> 💡 **Note:** Important info');
217
497
  });
218
498
  it('converts callout without icon', () => {
219
- const blocks = [
499
+ const blocks = asBlocks([
220
500
  {
221
501
  type: 'callout',
222
502
  callout: {
223
- rich_text: [{ type: 'text', text: { content: 'Info' } }],
503
+ rich_text: [
504
+ {
505
+ type: 'text',
506
+ text: { content: 'Info' },
507
+ plain_text: 'Info',
508
+ annotations: {
509
+ bold: false,
510
+ italic: false,
511
+ strikethrough: false,
512
+ underline: false,
513
+ code: false,
514
+ color: 'default',
515
+ },
516
+ href: null,
517
+ },
518
+ ],
519
+ icon: null,
224
520
  },
225
521
  },
226
- ];
522
+ ]);
227
523
  expect(blocksToMarkdownSync(blocks)).toBe('> **Note:** Info');
228
524
  });
229
525
  });
230
526
  describe('divider', () => {
231
527
  it('converts divider', () => {
232
- const blocks = [{ type: 'divider', divider: {} }];
528
+ const blocks = asBlocks([{ type: 'divider', divider: {} }]);
233
529
  expect(blocksToMarkdownSync(blocks)).toBe('---');
234
530
  });
235
531
  });
236
532
  describe('bookmark and links', () => {
237
533
  it('converts bookmark', () => {
238
- const blocks = [
534
+ const blocks = asBlocks([
239
535
  {
240
536
  type: 'bookmark',
241
537
  bookmark: {
242
538
  url: 'https://example.com',
539
+ caption: [],
243
540
  },
244
541
  },
245
- ];
542
+ ]);
246
543
  expect(blocksToMarkdownSync(blocks)).toBe('[https://example.com](https://example.com)');
247
544
  });
248
545
  it('converts bookmark with caption', () => {
249
- const blocks = [
546
+ const blocks = asBlocks([
250
547
  {
251
548
  type: 'bookmark',
252
549
  bookmark: {
253
550
  url: 'https://example.com',
254
- caption: [{ type: 'text', text: { content: 'Example Site' } }],
551
+ caption: [
552
+ {
553
+ type: 'text',
554
+ text: { content: 'Example Site' },
555
+ plain_text: 'Example Site',
556
+ annotations: {
557
+ bold: false,
558
+ italic: false,
559
+ strikethrough: false,
560
+ underline: false,
561
+ code: false,
562
+ color: 'default',
563
+ },
564
+ href: null,
565
+ },
566
+ ],
255
567
  },
256
568
  },
257
- ];
569
+ ]);
258
570
  expect(blocksToMarkdownSync(blocks)).toBe('[Example Site](https://example.com)');
259
571
  });
260
572
  it('converts link_preview', () => {
261
- const blocks = [
573
+ const blocks = asBlocks([
262
574
  {
263
575
  type: 'link_preview',
264
576
  link_preview: {
265
577
  url: 'https://example.com/preview',
266
578
  },
267
579
  },
268
- ];
580
+ ]);
269
581
  expect(blocksToMarkdownSync(blocks)).toBe('[https://example.com/preview](https://example.com/preview)');
270
582
  });
271
583
  });
272
584
  describe('media blocks', () => {
273
585
  it('converts image with external url', () => {
274
- const blocks = [
586
+ const blocks = asBlocks([
275
587
  {
276
588
  type: 'image',
277
589
  image: {
278
590
  type: 'external',
279
591
  external: { url: 'https://example.com/image.png' },
592
+ caption: [],
280
593
  },
281
594
  },
282
- ];
595
+ ]);
283
596
  expect(blocksToMarkdownSync(blocks)).toBe('![](https://example.com/image.png)');
284
597
  });
285
598
  it('converts image with caption', () => {
286
- const blocks = [
599
+ const blocks = asBlocks([
287
600
  {
288
601
  type: 'image',
289
602
  image: {
290
603
  type: 'external',
291
604
  external: { url: 'https://example.com/image.png' },
292
- caption: [{ type: 'text', text: { content: 'My Image' } }],
605
+ caption: [
606
+ {
607
+ type: 'text',
608
+ text: { content: 'My Image' },
609
+ plain_text: 'My Image',
610
+ annotations: {
611
+ bold: false,
612
+ italic: false,
613
+ strikethrough: false,
614
+ underline: false,
615
+ code: false,
616
+ color: 'default',
617
+ },
618
+ href: null,
619
+ },
620
+ ],
293
621
  },
294
622
  },
295
- ];
623
+ ]);
296
624
  expect(blocksToMarkdownSync(blocks)).toBe('![My Image](https://example.com/image.png)');
297
625
  });
298
626
  it('converts image with file url', () => {
299
- const blocks = [
627
+ const blocks = asBlocks([
300
628
  {
301
629
  type: 'image',
302
630
  image: {
303
631
  type: 'file',
304
632
  file: { url: 'https://s3.amazonaws.com/file.png' },
633
+ caption: [],
305
634
  },
306
635
  },
307
- ];
636
+ ]);
308
637
  expect(blocksToMarkdownSync(blocks)).toBe('![](https://s3.amazonaws.com/file.png)');
309
638
  });
310
639
  it('converts video', () => {
311
- const blocks = [
640
+ const blocks = asBlocks([
312
641
  {
313
642
  type: 'video',
314
643
  video: {
315
644
  type: 'external',
316
645
  external: { url: 'https://youtube.com/watch?v=123' },
646
+ caption: [],
317
647
  },
318
648
  },
319
- ];
649
+ ]);
320
650
  expect(blocksToMarkdownSync(blocks)).toBe('[Video](https://youtube.com/watch?v=123)');
321
651
  });
322
652
  it('converts audio', () => {
323
- const blocks = [
653
+ const blocks = asBlocks([
324
654
  {
325
655
  type: 'audio',
326
656
  audio: {
@@ -328,118 +658,136 @@ describe('blocksToMarkdownSync', () => {
328
658
  external: { url: 'https://example.com/audio.mp3' },
329
659
  },
330
660
  },
331
- ];
661
+ ]);
332
662
  expect(blocksToMarkdownSync(blocks)).toBe('[Audio](https://example.com/audio.mp3)');
333
663
  });
334
664
  it('converts file', () => {
335
- const blocks = [
665
+ const blocks = asBlocks([
336
666
  {
337
667
  type: 'file',
338
668
  file: {
339
669
  type: 'file',
340
670
  file: { url: 'https://example.com/doc.pdf' },
341
671
  name: 'Document',
672
+ caption: [],
342
673
  },
343
674
  },
344
- ];
675
+ ]);
345
676
  expect(blocksToMarkdownSync(blocks)).toBe('[Document](https://example.com/doc.pdf)');
346
677
  });
347
678
  it('converts pdf', () => {
348
- const blocks = [
679
+ const blocks = asBlocks([
349
680
  {
350
681
  type: 'pdf',
351
682
  pdf: {
352
683
  type: 'external',
353
684
  external: { url: 'https://example.com/doc.pdf' },
685
+ caption: [],
354
686
  },
355
687
  },
356
- ];
357
- expect(blocksToMarkdownSync(blocks)).toBe('[File](https://example.com/doc.pdf)');
688
+ ]);
689
+ expect(blocksToMarkdownSync(blocks)).toBe('[PDF](https://example.com/doc.pdf)');
358
690
  });
359
691
  it('converts embed', () => {
360
- const blocks = [
692
+ const blocks = asBlocks([
361
693
  {
362
694
  type: 'embed',
363
695
  embed: {
364
696
  url: 'https://codepen.io/pen/123',
697
+ caption: [],
365
698
  },
366
699
  },
367
- ];
700
+ ]);
368
701
  expect(blocksToMarkdownSync(blocks)).toBe('[Embed](https://codepen.io/pen/123)');
369
702
  });
370
703
  });
371
704
  describe('toggle', () => {
372
705
  it('converts toggle block', () => {
373
- const blocks = [
706
+ const blocks = asBlocks([
374
707
  {
375
708
  type: 'toggle',
376
709
  toggle: {
377
- rich_text: [{ type: 'text', text: { content: 'Click to expand' } }],
710
+ rich_text: [
711
+ {
712
+ type: 'text',
713
+ text: { content: 'Click to expand' },
714
+ plain_text: 'Click to expand',
715
+ annotations: {
716
+ bold: false,
717
+ italic: false,
718
+ strikethrough: false,
719
+ underline: false,
720
+ code: false,
721
+ color: 'default',
722
+ },
723
+ href: null,
724
+ },
725
+ ],
378
726
  },
379
727
  },
380
- ];
728
+ ]);
381
729
  expect(blocksToMarkdownSync(blocks)).toBe('<details>\n<summary>Click to expand</summary>\n</details>');
382
730
  });
383
731
  });
384
732
  describe('special blocks', () => {
385
733
  it('converts table_of_contents', () => {
386
- const blocks = [
734
+ const blocks = asBlocks([
387
735
  {
388
736
  type: 'table_of_contents',
389
- table_of_contents: {},
737
+ table_of_contents: { color: 'default' },
390
738
  },
391
- ];
739
+ ]);
392
740
  expect(blocksToMarkdownSync(blocks)).toBe('[TOC]');
393
741
  });
394
742
  it('converts equation', () => {
395
- const blocks = [
743
+ const blocks = asBlocks([
396
744
  {
397
745
  type: 'equation',
398
746
  equation: {
399
747
  expression: 'E = mc^2',
400
748
  },
401
749
  },
402
- ];
750
+ ]);
403
751
  expect(blocksToMarkdownSync(blocks)).toBe('$$\nE = mc^2\n$$');
404
752
  });
405
753
  it('converts child_page', () => {
406
- const blocks = [
754
+ const blocks = asBlocks([
407
755
  {
408
756
  type: 'child_page',
409
757
  child_page: {
410
758
  title: 'My Subpage',
411
759
  },
412
760
  },
413
- ];
761
+ ]);
414
762
  expect(blocksToMarkdownSync(blocks)).toBe('📄 [My Subpage]');
415
763
  });
416
764
  it('converts child_database', () => {
417
- const blocks = [
765
+ const blocks = asBlocks([
418
766
  {
419
767
  type: 'child_database',
420
768
  child_database: {
421
769
  title: 'My Database',
422
770
  },
423
771
  },
424
- ];
772
+ ]);
425
773
  expect(blocksToMarkdownSync(blocks)).toBe('📊 [My Database]');
426
774
  });
427
775
  });
428
776
  describe('unsupported blocks', () => {
429
777
  it('handles unsupported block type', () => {
430
- const blocks = [
778
+ const blocks = asBlocks([
431
779
  {
432
- type: 'unknown_type',
433
- unknown_type: { some: 'data' },
780
+ type: 'unsupported',
781
+ unsupported: {},
434
782
  },
435
- ];
436
- expect(blocksToMarkdownSync(blocks)).toBe('<!-- Unsupported block type: unknown_type -->');
783
+ ]);
784
+ expect(blocksToMarkdownSync(blocks)).toBe('<!-- Unsupported block type: unsupported -->');
437
785
  });
438
786
  });
439
787
  describe('real world data', () => {
440
788
  it('converts actual Notion block data', () => {
441
789
  // 実際のNotionから取得したデータ形式
442
- const blocks = [
790
+ const blocks = asBlocks([
443
791
  {
444
792
  object: 'block',
445
793
  id: 'f542c96d-5d08-4488-83a0-ec2bb4af3d10',
@@ -541,7 +889,7 @@ describe('blocksToMarkdownSync', () => {
541
889
  color: 'default',
542
890
  },
543
891
  },
544
- ];
892
+ ]);
545
893
  const result = blocksToMarkdownSync(blocks);
546
894
  expect(result).toBe('## 問題\n以下のパッケージで `exports` が必要:\n- `apps/supabase-client/package.json`');
547
895
  });
@@ -549,60 +897,83 @@ describe('blocksToMarkdownSync', () => {
549
897
  });
550
898
  describe('blocksToMarkdown (async)', () => {
551
899
  it('works without fetchChildren option', async () => {
552
- const blocks = [
900
+ const blocks = asBlocks([
553
901
  {
554
902
  type: 'paragraph',
555
903
  paragraph: {
556
- rich_text: [{ type: 'text', text: { content: 'Hello' } }],
904
+ rich_text: [
905
+ {
906
+ type: 'text',
907
+ text: { content: 'Hello' },
908
+ plain_text: 'Hello',
909
+ annotations: {
910
+ bold: false,
911
+ italic: false,
912
+ strikethrough: false,
913
+ underline: false,
914
+ code: false,
915
+ color: 'default',
916
+ },
917
+ href: null,
918
+ },
919
+ ],
557
920
  },
558
921
  },
559
- ];
922
+ ]);
560
923
  const result = await blocksToMarkdown(blocks);
561
924
  expect(result).toBe('Hello');
562
925
  });
563
926
  it('fetches children for nested bulleted_list_item', async () => {
564
- const mockFetchChildren = vi.fn().mockResolvedValue([
927
+ const childBlocks = asBlocks([
565
928
  {
566
929
  type: 'paragraph',
567
930
  paragraph: {
568
- rich_text: [{ type: 'text', text: { content: 'Nested content' } }],
931
+ rich_text: [
932
+ { type: 'text', text: { content: 'Nested content' }, plain_text: 'Nested content' },
933
+ ],
569
934
  },
570
935
  },
571
936
  ]);
572
- const blocks = [
937
+ const mockFetchChildren = vi.fn().mockResolvedValue(childBlocks);
938
+ const blocks = asBlocks([
573
939
  {
574
940
  id: 'parent-id',
575
941
  type: 'bulleted_list_item',
576
942
  has_children: true,
577
943
  bulleted_list_item: {
578
- rich_text: [{ type: 'text', text: { content: 'Parent item' } }],
944
+ rich_text: [
945
+ { type: 'text', text: { content: 'Parent item' }, plain_text: 'Parent item' },
946
+ ],
579
947
  },
580
948
  },
581
- ];
949
+ ]);
582
950
  const result = await blocksToMarkdown(blocks, { fetchChildren: mockFetchChildren });
583
951
  expect(mockFetchChildren).toHaveBeenCalledWith('parent-id');
584
952
  expect(result).toContain('- Parent item');
585
953
  expect(result).toContain('Nested content');
586
954
  });
587
955
  it('handles toggle block with children', async () => {
588
- const mockFetchChildren = vi.fn().mockResolvedValue([
956
+ const childBlocks = asBlocks([
589
957
  {
590
958
  type: 'paragraph',
591
959
  paragraph: {
592
- rich_text: [{ type: 'text', text: { content: 'Toggle content' } }],
960
+ rich_text: [
961
+ { type: 'text', text: { content: 'Toggle content' }, plain_text: 'Toggle content' },
962
+ ],
593
963
  },
594
964
  },
595
965
  ]);
596
- const blocks = [
966
+ const mockFetchChildren = vi.fn().mockResolvedValue(childBlocks);
967
+ const blocks = asBlocks([
597
968
  {
598
969
  id: 'toggle-id',
599
970
  type: 'toggle',
600
971
  has_children: true,
601
972
  toggle: {
602
- rich_text: [{ type: 'text', text: { content: 'Click me' } }],
973
+ rich_text: [{ type: 'text', text: { content: 'Click me' }, plain_text: 'Click me' }],
603
974
  },
604
975
  },
605
- ];
976
+ ]);
606
977
  const result = await blocksToMarkdown(blocks, { fetchChildren: mockFetchChildren });
607
978
  expect(mockFetchChildren).toHaveBeenCalledWith('toggle-id');
608
979
  expect(result).toContain('<summary>Click me</summary>');