@moxn/kb-migrate 0.4.17 → 0.4.18

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.
@@ -187,22 +187,50 @@ async function uploadFileToNotion(client, url, filename, contentType) {
187
187
  /**
188
188
  * Post-process martian output to reconstruct callout blocks.
189
189
  *
190
- * Callouts are stored as blockquotes with an emoji prefix (e.g., `> 💡 tip text`).
191
- * Martian converts these to Notion `quote` blocks with the actual text inside
192
- * `children[].paragraph.rich_text` (not the top-level `rich_text`).
193
- * This function detects the emoji prefix pattern in the first child paragraph
194
- * and converts matching quotes to native Notion `callout` blocks.
190
+ * Callouts may arrive as either:
191
+ * 1. `quote` blocks (when stored with `> ` prefix) — text in children[0].paragraph.rich_text
192
+ * 2. `paragraph` blocks (when stored as plain text) — text in paragraph.rich_text
193
+ *
194
+ * In both cases, if the first text segment starts with an emoji followed by a space,
195
+ * the block is converted to a native Notion `callout` with that emoji as the icon.
195
196
  */
196
197
  function reconstructCallouts(blocks) {
197
198
  const emojiPrefixRe = /^(\p{Emoji_Presentation}|\p{Emoji}\uFE0F?)\s/u;
198
199
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
200
  return blocks.map((block) => {
201
+ // Case 1: paragraph with emoji prefix
202
+ if (block.type === 'paragraph') {
203
+ const richText = block.paragraph?.rich_text;
204
+ if (!richText?.length)
205
+ return block;
206
+ const firstSegment = richText[0];
207
+ if (firstSegment.type !== 'text' || !firstSegment.text?.content)
208
+ return block;
209
+ const match = firstSegment.text.content.match(emojiPrefixRe);
210
+ if (!match)
211
+ return block;
212
+ const emoji = match[1];
213
+ const strippedContent = firstSegment.text.content.slice(match[0].length);
214
+ const calloutRichText = [
215
+ { ...firstSegment, text: { ...firstSegment.text, content: strippedContent } },
216
+ ...richText.slice(1),
217
+ ].filter((rt) => rt.text?.content);
218
+ return {
219
+ object: 'block',
220
+ type: 'callout',
221
+ callout: {
222
+ rich_text: calloutRichText,
223
+ icon: { type: 'emoji', emoji },
224
+ color: 'default',
225
+ },
226
+ };
227
+ }
228
+ // Case 2: quote with emoji prefix in first child paragraph
200
229
  if (block.type !== 'quote')
201
230
  return block;
202
231
  const children = block.quote?.children;
203
232
  if (!children?.length)
204
233
  return block;
205
- // Find the first child paragraph with text
206
234
  const firstChild = children[0];
207
235
  if (firstChild.type !== 'paragraph' || !firstChild.paragraph?.rich_text?.length)
208
236
  return block;
@@ -211,15 +239,13 @@ function reconstructCallouts(blocks) {
211
239
  return block;
212
240
  const match = firstSegment.text.content.match(emojiPrefixRe);
213
241
  if (!match)
214
- return block; // No emoji prefix — keep as regular quote
242
+ return block;
215
243
  const emoji = match[1];
216
244
  const strippedContent = firstSegment.text.content.slice(match[0].length);
217
- // Build the callout's rich_text from the first child paragraph (stripped of emoji)
218
245
  const calloutRichText = [
219
246
  { ...firstSegment, text: { ...firstSegment.text, content: strippedContent } },
220
247
  ...firstChild.paragraph.rich_text.slice(1),
221
248
  ].filter((rt) => rt.text?.content);
222
- // Remaining children become the callout's children
223
249
  const remainingChildren = children.slice(1);
224
250
  return {
225
251
  object: 'block',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxn/kb-migrate",
3
- "version": "0.4.17",
3
+ "version": "0.4.18",
4
4
  "description": "Migration tool for importing documents into Moxn Knowledge Base from local files, Notion, Google Docs, and more",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",