n8n-nodes-notion-advanced 1.2.33-beta → 1.2.34-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.
@@ -1544,7 +1544,6 @@ class NotionAITool {
1544
1544
  }
1545
1545
  // Build hierarchy structure for lists using HierarchyNode approach
1546
1546
  static buildListHierarchy(listContent, listType, childHierarchyNodes) {
1547
- var _a;
1548
1547
  try {
1549
1548
  // Process each <li> element and build hierarchy
1550
1549
  const listItems = NotionAITool.extractListItemsWithBranching(listContent);
@@ -1553,7 +1552,7 @@ class NotionAITool {
1553
1552
  const listItemPositions = NotionAITool.getListItemPositions(listContent);
1554
1553
  for (let i = 0; i < listItems.length; i++) {
1555
1554
  const item = listItems[i];
1556
- if (!item.text && !item.children.length)
1555
+ if (!item.text && !item.children.length && !(item.extractedChildBlocks && item.extractedChildBlocks.length > 0))
1557
1556
  continue;
1558
1557
  // Create list item block
1559
1558
  const listItemBlock = {
@@ -1571,19 +1570,24 @@ class NotionAITool {
1571
1570
  }
1572
1571
  // Collect child hierarchy nodes for this list item based on position mapping
1573
1572
  const itemChildNodes = [];
1574
- // Map child hierarchy nodes that belong to this specific list item
1575
- if (i < listItemPositions.length) {
1576
- const currentItemStart = listItemPositions[i].start;
1577
- const currentItemEnd = listItemPositions[i].end;
1578
- for (const childNode of childHierarchyNodes) {
1579
- const childPosition = (_a = childNode.metadata) === null || _a === void 0 ? void 0 : _a.sourcePosition;
1580
- if (childPosition !== undefined &&
1581
- childPosition >= currentItemStart &&
1582
- childPosition < currentItemEnd) {
1583
- itemChildNodes.push(childNode);
1584
- }
1573
+ // Add extracted child blocks (from XML tags within list items)
1574
+ // These are the primary source for child blocks in list items
1575
+ if (item.extractedChildBlocks && Array.isArray(item.extractedChildBlocks)) {
1576
+ const extractedBlocks = item.extractedChildBlocks;
1577
+ for (const block of extractedBlocks) {
1578
+ itemChildNodes.push({
1579
+ block,
1580
+ children: [],
1581
+ metadata: {
1582
+ sourcePosition: i,
1583
+ tagName: block.type
1584
+ }
1585
+ });
1585
1586
  }
1586
1587
  }
1588
+ // Note: We prioritize extractedChildBlocks over childHierarchyNodes for list items
1589
+ // since list-specific processing in extractListItemsWithBranching is more accurate
1590
+ // for handling child blocks within <li> elements
1587
1591
  // Process nested list children (traditional nested lists)
1588
1592
  if (item.children.length > 0) {
1589
1593
  for (const child of item.children) {
@@ -1603,7 +1607,7 @@ class NotionAITool {
1603
1607
  tagName: listType
1604
1608
  }
1605
1609
  };
1606
- // Only add if it has content or children
1610
+ // Only add if it has content or children (including extracted child blocks)
1607
1611
  const listData = listItemBlock[listType];
1608
1612
  if ((listData.rich_text && listData.rich_text.length > 0) || itemChildNodes.length > 0) {
1609
1613
  listItemHierarchyNodes.push(listItemHierarchyNode);
@@ -1830,8 +1834,9 @@ class NotionAITool {
1830
1834
  continue;
1831
1835
  }
1832
1836
  const item = { text: '', children: [] };
1833
- // STEP 1: Remove child block XML from content to get clean parent text
1837
+ // STEP 1: Extract and convert child block XML to actual blocks before removing from parent text
1834
1838
  let parentTextContent = fullItemContent;
1839
+ const extractedChildBlocks = [];
1835
1840
  // List of XML tags that create child blocks (these should be removed from parent text)
1836
1841
  const childBlockTags = [
1837
1842
  'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
@@ -1839,14 +1844,181 @@ class NotionAITool {
1839
1844
  'todo', 'toggle', 'image', 'embed', 'bookmark',
1840
1845
  'equation', 'divider'
1841
1846
  ];
1842
- // Remove child block XML from parent text
1847
+ // Extract child blocks first, then remove from parent text
1843
1848
  childBlockTags.forEach(tag => {
1844
- // Remove both self-closing and paired tags
1849
+ // Extract and process paired tags first
1850
+ const pairedRegex = new RegExp(`<${tag}[^>]*>(.*?)<\\/${tag}>`, 'gis');
1851
+ let match;
1852
+ while ((match = pairedRegex.exec(parentTextContent)) !== null) {
1853
+ const fullMatch = match[0];
1854
+ const content = match[1];
1855
+ // Create child block based on tag type
1856
+ try {
1857
+ let childBlock = null;
1858
+ switch (tag) {
1859
+ case 'embed':
1860
+ childBlock = {
1861
+ type: 'embed',
1862
+ embed: { url: content.trim() }
1863
+ };
1864
+ break;
1865
+ case 'bookmark':
1866
+ childBlock = {
1867
+ type: 'bookmark',
1868
+ bookmark: { url: content.trim() }
1869
+ };
1870
+ break;
1871
+ case 'p':
1872
+ const markdownContent = NotionAITool.convertInlineHtmlToMarkdown(content.trim());
1873
+ childBlock = {
1874
+ type: 'paragraph',
1875
+ paragraph: { rich_text: NotionAITool.parseBasicMarkdown(markdownContent) }
1876
+ };
1877
+ break;
1878
+ case 'h1':
1879
+ case 'h2':
1880
+ case 'h3':
1881
+ const headingType = `heading_${tag.charAt(1)}`;
1882
+ childBlock = {
1883
+ type: headingType,
1884
+ [headingType]: { rich_text: [{ type: 'text', text: { content: content.trim() } }] }
1885
+ };
1886
+ break;
1887
+ case 'quote':
1888
+ case 'blockquote':
1889
+ childBlock = {
1890
+ type: 'quote',
1891
+ quote: { rich_text: NotionAITool.parseBasicMarkdown(content.trim()) }
1892
+ };
1893
+ break;
1894
+ case 'callout':
1895
+ // Extract type attribute if present
1896
+ const typeMatch = fullMatch.match(/type="([^"]*)"/);
1897
+ const calloutType = typeMatch ? typeMatch[1] : 'info';
1898
+ const emoji = NotionAITool.getCalloutEmoji(calloutType.toLowerCase());
1899
+ const color = NotionAITool.getCalloutColor(calloutType.toLowerCase());
1900
+ childBlock = {
1901
+ type: 'callout',
1902
+ callout: {
1903
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
1904
+ icon: { type: 'emoji', emoji },
1905
+ color: color
1906
+ }
1907
+ };
1908
+ break;
1909
+ case 'code':
1910
+ case 'pre':
1911
+ // Extract language attribute if present
1912
+ const langMatch = fullMatch.match(/language="([^"]*)"/);
1913
+ const language = langMatch ? langMatch[1] : 'plain_text';
1914
+ childBlock = {
1915
+ type: 'code',
1916
+ code: {
1917
+ rich_text: [{ type: 'text', text: { content: content.trim() } }],
1918
+ language: language === 'plain text' ? 'plain_text' : language
1919
+ }
1920
+ };
1921
+ break;
1922
+ case 'todo':
1923
+ // Extract checked attribute if present
1924
+ const checkedMatch = fullMatch.match(/checked="([^"]*)"/);
1925
+ const isChecked = checkedMatch ? checkedMatch[1].toLowerCase() === 'true' : false;
1926
+ childBlock = {
1927
+ type: 'to_do',
1928
+ to_do: {
1929
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
1930
+ checked: isChecked
1931
+ }
1932
+ };
1933
+ break;
1934
+ case 'toggle':
1935
+ childBlock = {
1936
+ type: 'toggle',
1937
+ toggle: {
1938
+ rich_text: NotionAITool.parseBasicMarkdown(content.trim()),
1939
+ children: []
1940
+ }
1941
+ };
1942
+ break;
1943
+ case 'equation':
1944
+ childBlock = {
1945
+ type: 'equation',
1946
+ equation: { expression: content.trim() }
1947
+ };
1948
+ break;
1949
+ case 'image':
1950
+ // Extract src and alt attributes
1951
+ const srcMatch = fullMatch.match(/src="([^"]*)"/);
1952
+ const altMatch = fullMatch.match(/alt="([^"]*)"/);
1953
+ const src = srcMatch ? srcMatch[1] : '';
1954
+ const alt = altMatch ? altMatch[1] : '';
1955
+ const caption = content.trim() || alt;
1956
+ childBlock = {
1957
+ type: 'image',
1958
+ image: {
1959
+ type: 'external',
1960
+ external: { url: src },
1961
+ caption: caption ? NotionAITool.parseBasicMarkdown(caption) : []
1962
+ }
1963
+ };
1964
+ break;
1965
+ case 'divider':
1966
+ childBlock = {
1967
+ type: 'divider',
1968
+ divider: {}
1969
+ };
1970
+ break;
1971
+ }
1972
+ if (childBlock) {
1973
+ extractedChildBlocks.push(childBlock);
1974
+ }
1975
+ }
1976
+ catch (error) {
1977
+ console.warn(`Error creating child block for tag ${tag}:`, error);
1978
+ }
1979
+ }
1980
+ // Handle self-closing tags (mainly for divider, image)
1845
1981
  const selfClosingRegex = new RegExp(`<${tag}[^>]*\\/>`, 'gis');
1846
- const pairedRegex = new RegExp(`<${tag}[^>]*>.*?<\\/${tag}>`, 'gis');
1982
+ let selfMatch;
1983
+ while ((selfMatch = selfClosingRegex.exec(parentTextContent)) !== null) {
1984
+ const fullMatch = selfMatch[0];
1985
+ try {
1986
+ let childBlock = null;
1987
+ if (tag === 'divider') {
1988
+ childBlock = {
1989
+ type: 'divider',
1990
+ divider: {}
1991
+ };
1992
+ }
1993
+ else if (tag === 'image') {
1994
+ // Extract src and alt attributes
1995
+ const srcMatch = fullMatch.match(/src="([^"]*)"/);
1996
+ const altMatch = fullMatch.match(/alt="([^"]*)"/);
1997
+ const src = srcMatch ? srcMatch[1] : '';
1998
+ const alt = altMatch ? altMatch[1] : '';
1999
+ childBlock = {
2000
+ type: 'image',
2001
+ image: {
2002
+ type: 'external',
2003
+ external: { url: src },
2004
+ caption: alt ? NotionAITool.parseBasicMarkdown(alt) : []
2005
+ }
2006
+ };
2007
+ }
2008
+ if (childBlock) {
2009
+ extractedChildBlocks.push(childBlock);
2010
+ }
2011
+ }
2012
+ catch (error) {
2013
+ console.warn(`Error creating self-closing child block for tag ${tag}:`, error);
2014
+ }
2015
+ }
2016
+ // Now remove both paired and self-closing tags from parent text
1847
2017
  parentTextContent = parentTextContent.replace(pairedRegex, '');
1848
2018
  parentTextContent = parentTextContent.replace(selfClosingRegex, '');
1849
2019
  });
2020
+ // Store extracted child blocks in the item for later use
2021
+ item.extractedChildBlocks = extractedChildBlocks;
1850
2022
  // STEP 2: Process the content to separate remaining text from nested lists
1851
2023
  let contentPos = 0;
1852
2024
  let textParts = [];
@@ -1932,8 +2104,8 @@ class NotionAITool {
1932
2104
  item.text = cleanText;
1933
2105
  }
1934
2106
  }
1935
- // Only add items that have either text or children
1936
- if (item.text.trim() || item.children.length > 0) {
2107
+ // Only add items that have either text, children, or extracted child blocks
2108
+ if (item.text.trim() || item.children.length > 0 || (item.extractedChildBlocks && item.extractedChildBlocks.length > 0)) {
1937
2109
  items.push(item);
1938
2110
  }
1939
2111
  pos = liEnd + 5; // Move past </li>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.2.33-beta",
3
+ "version": "1.2.34-beta",
4
4
  "description": "Advanced n8n Notion nodes: Full-featured workflow node + AI Agent Tool for intelligent Notion automation with 25+ block types (BETA)",
5
5
  "scripts": {},
6
6
  "files": [