n8n-nodes-notion-advanced 1.2.30-beta → 1.2.31-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.
@@ -22,6 +22,15 @@ interface XMLNode {
22
22
  replacement?: string;
23
23
  listProcessor?: (content: string, blocks: IDataObject[]) => void;
24
24
  }
25
+ interface HierarchyNode {
26
+ block: IDataObject;
27
+ children: HierarchyNode[];
28
+ metadata?: {
29
+ sourcePosition?: number;
30
+ xmlNodeId?: string;
31
+ tagName?: string;
32
+ };
33
+ }
25
34
  export declare class NotionAITool implements INodeType {
26
35
  description: INodeTypeDescription;
27
36
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
@@ -43,6 +52,8 @@ export declare class NotionAITool implements INodeType {
43
52
  }[]): string;
44
53
  static getUtf8BytePosition(str: string, charIndex: number): number;
45
54
  static buildXMLTree(content: string, tagProcessors: any[]): XMLNode[];
55
+ static xmlTreeToHierarchy(nodes: XMLNode[]): HierarchyNode[];
56
+ static hierarchyToNotionBlocks(hierarchy: HierarchyNode[]): IDataObject[];
46
57
  static processXMLTreeDepthFirst(nodes: XMLNode[], blocks: IDataObject[], placeholderCounter: {
47
58
  value: number;
48
59
  }): Map<string, string>;
@@ -54,7 +65,10 @@ export declare class NotionAITool implements INodeType {
54
65
  static cleanupRemainingHtml(content: string, placeholderPrefix?: string): string;
55
66
  static processNestedHtmlInListItem(content: string): string;
56
67
  static convertInlineHtmlToMarkdown(content: string): string;
57
- static processNestedList(listContent: string, listType: 'bulleted_list_item' | 'numbered_list_item', blocks: IDataObject[]): void;
68
+ static buildListHierarchy(listContent: string, listType: 'bulleted_list_item' | 'numbered_list_item', childHierarchyNodes: HierarchyNode[]): HierarchyNode | null;
69
+ static mapChildBlocksToListItems(listContent: string, childBlocks: IDataObject[], childNodes: XMLNode[]): Map<number, IDataObject[]>;
70
+ static processNestedListWithChildBlocks(listContent: string, listType: 'bulleted_list_item' | 'numbered_list_item', blocks: IDataObject[], listItemChildBlocks: Map<number, IDataObject[]>): void;
71
+ static processNestedList(listContent: string, listType: 'bulleted_list_item' | 'numbered_list_item', blocks: IDataObject[], childNodes?: XMLNode[]): void;
58
72
  static extractListItemsWithBranching(content: string): Array<{
59
73
  text: string;
60
74
  children: Array<{
@@ -749,67 +749,55 @@ class NotionAITool {
749
749
  static buildXMLTree(content, tagProcessors) {
750
750
  var _a;
751
751
  const allMatches = [];
752
- // Step 1: Use depth-aware parsing for each tag processor
752
+ // Step 1: Use regex-based parsing to properly extract capture groups, then enhance with depth-aware structure
753
753
  tagProcessors.forEach(({ regex, blockCreator, listProcessor }) => {
754
754
  var _a;
755
- const tagPattern = (_a = regex.source.match(/<(\w+)/)) === null || _a === void 0 ? void 0 : _a[1];
756
- if (!tagPattern)
757
- return;
758
- // Find all opening tags of this type
759
- let pos = 0;
760
- while (pos < content.length) {
761
- const openTagStart = content.indexOf(`<${tagPattern}`, pos);
762
- if (openTagStart === -1)
763
- break;
764
- const openTagEnd = content.indexOf('>', openTagStart);
765
- if (openTagEnd === -1)
766
- break;
767
- // Find matching closing tag using depth tracking
768
- let depth = 1;
769
- let searchPos = openTagEnd + 1;
770
- let closeTagStart = -1;
771
- const openPattern = `<${tagPattern}`;
772
- const closePattern = `</${tagPattern}>`;
773
- while (searchPos < content.length && depth > 0) {
774
- const nextOpen = content.indexOf(openPattern, searchPos);
775
- const nextClose = content.indexOf(closePattern, searchPos);
776
- if (nextClose === -1)
777
- break;
778
- if (nextOpen !== -1 && nextOpen < nextClose) {
779
- // Found nested opening tag
780
- depth++;
781
- searchPos = nextOpen + openPattern.length;
755
+ const globalRegex = new RegExp(regex.source, 'gis');
756
+ let match;
757
+ while ((match = globalRegex.exec(content)) !== null) {
758
+ const fullMatch = match[0];
759
+ const matchStart = match.index;
760
+ const matchEnd = match.index + fullMatch.length;
761
+ // Extract tag name for identification
762
+ const tagPattern = ((_a = regex.source.match(/<(\w+)/)) === null || _a === void 0 ? void 0 : _a[1]) || 'unknown';
763
+ // Extract inner content (between opening and closing tags)
764
+ let innerContent = '';
765
+ try {
766
+ const openTagRegex = new RegExp(`^<${tagPattern}[^>]*>`, 'i');
767
+ const closeTagRegex = new RegExp(`</${tagPattern}>$`, 'i');
768
+ const openMatch = fullMatch.match(openTagRegex);
769
+ const closeMatch = fullMatch.match(closeTagRegex);
770
+ if (openMatch && closeMatch) {
771
+ const openTag = openMatch[0];
772
+ const closeTag = closeMatch[0];
773
+ const startIndex = openTag.length;
774
+ const endIndex = fullMatch.length - closeTag.length;
775
+ innerContent = fullMatch.substring(startIndex, endIndex);
782
776
  }
783
777
  else {
784
- // Found closing tag
785
- depth--;
786
- if (depth === 0) {
787
- closeTagStart = nextClose;
788
- break;
789
- }
790
- searchPos = nextClose + closePattern.length;
778
+ // Fallback for self-closing or malformed tags
779
+ innerContent = fullMatch.replace(/^<[^>]*>/, '').replace(/<\/[^>]*>$/, '');
791
780
  }
792
781
  }
793
- if (closeTagStart !== -1) {
794
- const fullMatch = content.substring(openTagStart, closeTagStart + closePattern.length);
795
- const innerContent = content.substring(openTagEnd + 1, closeTagStart);
796
- const xmlNode = {
797
- id: `${tagPattern}_${openTagStart}_${Date.now()}_${Math.random()}`,
798
- tagName: tagPattern,
799
- start: openTagStart,
800
- end: closeTagStart + closePattern.length,
801
- match: fullMatch,
802
- processor: blockCreator,
803
- groups: [innerContent], // For list processors, group[0] is the inner content
804
- children: [],
805
- depth: 0,
806
- innerContent,
807
- replacement: undefined,
808
- listProcessor
809
- };
810
- allMatches.push(xmlNode);
782
+ catch (error) {
783
+ console.warn(`Error extracting inner content for ${tagPattern}:`, error);
784
+ innerContent = fullMatch;
811
785
  }
812
- pos = openTagEnd + 1;
786
+ const xmlNode = {
787
+ id: `${tagPattern}_${matchStart}_${Date.now()}_${Math.random()}`,
788
+ tagName: tagPattern,
789
+ start: matchStart,
790
+ end: matchEnd,
791
+ match: fullMatch,
792
+ processor: blockCreator,
793
+ groups: match.slice(1), // Proper regex capture groups (excluding full match)
794
+ children: [],
795
+ depth: 0,
796
+ innerContent,
797
+ replacement: undefined,
798
+ listProcessor
799
+ };
800
+ allMatches.push(xmlNode);
813
801
  }
814
802
  });
815
803
  // Step 2: Catch ANY remaining XML/HTML tags that weren't processed by specific processors
@@ -869,92 +857,126 @@ class NotionAITool {
869
857
  }
870
858
  return rootNodes;
871
859
  }
872
- // Process XML tree depth-first (children before parents)
873
- static processXMLTreeDepthFirst(nodes, blocks, placeholderCounter) {
874
- const replacements = new Map();
875
- const processNode = (node) => {
876
- // For lists, use the original match content to preserve structure
877
- // This is the only case where we skip child processing to avoid fragmentation
878
- if (node.listProcessor && (node.tagName === 'ul' || node.tagName === 'ol')) {
879
- try {
880
- // Extract inner content directly from the original match
881
- const tagName = node.tagName.toLowerCase();
860
+ // Convert XML tree to HierarchyNode structure for cleaner processing
861
+ static xmlTreeToHierarchy(nodes) {
862
+ const hierarchyNodes = [];
863
+ const processNode = (xmlNode) => {
864
+ try {
865
+ // Process children first
866
+ const childHierarchyNodes = [];
867
+ for (const child of xmlNode.children) {
868
+ const childHierarchy = processNode(child);
869
+ if (childHierarchy) {
870
+ childHierarchyNodes.push(childHierarchy);
871
+ }
872
+ }
873
+ // For list processors, handle them specially
874
+ if (xmlNode.listProcessor && (xmlNode.tagName === 'ul' || xmlNode.tagName === 'ol')) {
875
+ // Extract inner content
876
+ const tagName = xmlNode.tagName.toLowerCase();
882
877
  const openTagRegex = new RegExp(`^<${tagName}[^>]*>`, 'i');
883
878
  const closeTagRegex = new RegExp(`</${tagName}>$`, 'i');
884
- let innerContent = node.match;
885
- const openMatch = node.match.match(openTagRegex);
886
- const closeMatch = node.match.match(closeTagRegex);
879
+ let innerContent = xmlNode.match;
880
+ const openMatch = xmlNode.match.match(openTagRegex);
881
+ const closeMatch = xmlNode.match.match(closeTagRegex);
887
882
  if (openMatch && closeMatch) {
888
883
  const openTag = openMatch[0];
889
884
  const closeTag = closeMatch[0];
890
885
  const startIndex = openTag.length;
891
- const endIndex = node.match.length - closeTag.length;
892
- innerContent = node.match.substring(startIndex, endIndex);
886
+ const endIndex = xmlNode.match.length - closeTag.length;
887
+ innerContent = xmlNode.match.substring(startIndex, endIndex);
893
888
  }
894
- // Process the list with complete content
895
- node.listProcessor(innerContent, blocks);
896
- return ''; // Remove completely - no placeholder needed
889
+ // Build hierarchy structure for the list
890
+ const listHierarchy = NotionAITool.buildListHierarchy(innerContent, xmlNode.tagName === 'ul' ? 'bulleted_list_item' : 'numbered_list_item', childHierarchyNodes);
891
+ return listHierarchy;
897
892
  }
898
- catch (error) {
899
- console.warn(`Error processing list node ${node.tagName}:`, error);
900
- return ''; // Remove even on error to prevent artifacts
901
- }
902
- }
903
- // For non-list nodes, process children first (normal hierarchical processing)
904
- for (const child of node.children) {
905
- const childReplacement = processNode(child);
906
- replacements.set(child.id, childReplacement);
907
- }
908
- // Extract inner content (content between opening and closing tags)
909
- let innerContent = '';
910
- try {
911
- // More robust inner content extraction
912
- const tagName = node.tagName.toLowerCase();
913
- const openTagRegex = new RegExp(`^<${tagName}[^>]*>`, 'i');
914
- const closeTagRegex = new RegExp(`</${tagName}>$`, 'i');
915
- const openMatch = node.match.match(openTagRegex);
916
- const closeMatch = node.match.match(closeTagRegex);
917
- if (openMatch && closeMatch) {
918
- const openTag = openMatch[0];
919
- const closeTag = closeMatch[0];
920
- const startIndex = openTag.length;
921
- const endIndex = node.match.length - closeTag.length;
922
- innerContent = node.match.substring(startIndex, endIndex);
923
- }
924
- else {
925
- // Fallback for self-closing or malformed tags
926
- innerContent = node.match.replace(/^<[^>]*>/, '').replace(/<\/[^>]*>$/, '');
927
- }
928
- // Replace child nodes in inner content with their processed content
929
- for (const child of node.children) {
930
- const childReplacement = replacements.get(child.id) || '';
931
- if (childReplacement !== undefined && innerContent.includes(child.match)) {
932
- innerContent = innerContent.replace(child.match, childReplacement);
893
+ // For regular nodes, create block and attach children
894
+ const block = xmlNode.processor(...xmlNode.groups);
895
+ if (!block)
896
+ return null;
897
+ const hierarchyNode = {
898
+ block,
899
+ children: childHierarchyNodes,
900
+ metadata: {
901
+ sourcePosition: xmlNode.start,
902
+ xmlNodeId: xmlNode.id,
903
+ tagName: xmlNode.tagName
933
904
  }
934
- }
935
- }
936
- catch (error) {
937
- console.warn(`Error extracting inner content for ${node.tagName}:`, error);
938
- innerContent = node.match;
939
- }
940
- // Process this node with updated inner content
941
- try {
942
- // Use blockCreator to create the block
943
- const block = node.processor(...node.groups);
944
- if (block) {
945
- blocks.push(block);
946
- }
947
- return ''; // Remove completely - no placeholder needed
905
+ };
906
+ return hierarchyNode;
948
907
  }
949
908
  catch (error) {
950
- console.warn(`Error processing XML node ${node.tagName}:`, error);
951
- return ''; // Remove even on error to prevent artifacts
909
+ console.warn(`Error processing XML node ${xmlNode.tagName}:`, error);
910
+ return null;
952
911
  }
953
912
  };
954
913
  // Process all root nodes
955
914
  for (const rootNode of nodes) {
956
- const replacement = processNode(rootNode);
957
- replacements.set(rootNode.id, replacement);
915
+ const hierarchyNode = processNode(rootNode);
916
+ if (hierarchyNode) {
917
+ if (hierarchyNode.block) {
918
+ hierarchyNodes.push(hierarchyNode);
919
+ }
920
+ else if (hierarchyNode.children.length > 0) {
921
+ // If it's a list container, add its children directly
922
+ hierarchyNodes.push(...hierarchyNode.children);
923
+ }
924
+ }
925
+ }
926
+ return hierarchyNodes;
927
+ }
928
+ // Convert HierarchyNode structure to final Notion blocks
929
+ static hierarchyToNotionBlocks(hierarchy) {
930
+ return hierarchy.map(node => {
931
+ const block = { ...node.block };
932
+ if (node.children.length > 0) {
933
+ const blockData = block[block.type];
934
+ if (blockData && typeof blockData === 'object') {
935
+ // Check if this block type can have children
936
+ const childSupportingTypes = ['bulleted_list_item', 'numbered_list_item', 'toggle', 'quote', 'callout'];
937
+ if (childSupportingTypes.includes(block.type)) {
938
+ blockData.children = NotionAITool.hierarchyToNotionBlocks(node.children);
939
+ }
940
+ }
941
+ }
942
+ return block;
943
+ });
944
+ }
945
+ // Process XML tree using the new hierarchy system
946
+ static processXMLTreeDepthFirst(nodes, blocks, placeholderCounter) {
947
+ const replacements = new Map();
948
+ try {
949
+ // Convert XML tree to hierarchy structure
950
+ const hierarchy = NotionAITool.xmlTreeToHierarchy(nodes);
951
+ // Convert hierarchy to final Notion blocks
952
+ const finalBlocks = NotionAITool.hierarchyToNotionBlocks(hierarchy);
953
+ // Add all blocks to the output
954
+ blocks.push(...finalBlocks);
955
+ // Mark all nodes as processed (empty replacement)
956
+ const markProcessed = (nodeList) => {
957
+ nodeList.forEach(node => {
958
+ replacements.set(node.id, '');
959
+ markProcessed(node.children);
960
+ });
961
+ };
962
+ markProcessed(nodes);
963
+ }
964
+ catch (error) {
965
+ console.warn('Error in hierarchy processing, falling back to legacy processing:', error);
966
+ // Fallback to simple processing if hierarchy fails
967
+ nodes.forEach(node => {
968
+ try {
969
+ const block = node.processor(...node.groups);
970
+ if (block) {
971
+ blocks.push(block);
972
+ }
973
+ replacements.set(node.id, '');
974
+ }
975
+ catch (nodeError) {
976
+ console.warn(`Error processing fallback node ${node.tagName}:`, nodeError);
977
+ replacements.set(node.id, '');
978
+ }
979
+ });
958
980
  }
959
981
  return replacements;
960
982
  }
@@ -1499,13 +1521,16 @@ class NotionAITool {
1499
1521
  processed = processed.replace(/\s+/g, ' ').trim();
1500
1522
  return processed;
1501
1523
  }
1502
- // Helper function to process lists using branch-based approach
1503
- // Each <ul> and <ol> represents a new branch that contains children
1504
- static processNestedList(listContent, listType, blocks) {
1524
+ // Build hierarchy structure for lists using HierarchyNode approach
1525
+ static buildListHierarchy(listContent, listType, childHierarchyNodes) {
1505
1526
  try {
1506
- // Process each <li> element as a potential branch point
1527
+ // Process each <li> element and build hierarchy
1507
1528
  const listItems = NotionAITool.extractListItemsWithBranching(listContent);
1508
- for (const item of listItems) {
1529
+ const listItemHierarchyNodes = [];
1530
+ // Map child hierarchy nodes to list items based on position
1531
+ let childNodeIndex = 0;
1532
+ for (let i = 0; i < listItems.length; i++) {
1533
+ const item = listItems[i];
1509
1534
  if (!item.text && !item.children.length)
1510
1535
  continue;
1511
1536
  // Create list item block
@@ -1522,18 +1547,140 @@ class NotionAITool {
1522
1547
  listItemBlock[listType].rich_text = NotionAITool.parseBasicMarkdown(cleanText);
1523
1548
  }
1524
1549
  }
1525
- // Process child branches and add them as nested children
1550
+ // Collect child hierarchy nodes for this list item
1551
+ const itemChildNodes = [];
1552
+ // Add child hierarchy nodes that belong to this list item
1553
+ // For now, distribute them evenly - this could be improved with position mapping
1554
+ const childrenPerItem = Math.floor(childHierarchyNodes.length / listItems.length);
1555
+ const startIndex = i * childrenPerItem;
1556
+ const endIndex = i === listItems.length - 1 ? childHierarchyNodes.length : startIndex + childrenPerItem;
1557
+ for (let j = startIndex; j < endIndex; j++) {
1558
+ if (j < childHierarchyNodes.length) {
1559
+ itemChildNodes.push(childHierarchyNodes[j]);
1560
+ }
1561
+ }
1562
+ // Process nested list children (traditional nested lists)
1526
1563
  if (item.children.length > 0) {
1527
- const childBlocks = [];
1528
1564
  for (const child of item.children) {
1529
1565
  const childListType = child.type === 'ul' ? 'bulleted_list_item' : 'numbered_list_item';
1530
- NotionAITool.processNestedList(child.content, childListType, childBlocks);
1566
+ const childListHierarchy = NotionAITool.buildListHierarchy(child.content, childListType, []);
1567
+ if (childListHierarchy && childListHierarchy.children) {
1568
+ itemChildNodes.push(...childListHierarchy.children);
1569
+ }
1570
+ }
1571
+ }
1572
+ // Create hierarchy node for this list item
1573
+ const listItemHierarchyNode = {
1574
+ block: listItemBlock,
1575
+ children: itemChildNodes,
1576
+ metadata: {
1577
+ sourcePosition: i,
1578
+ tagName: listType
1579
+ }
1580
+ };
1581
+ // Only add if it has content or children
1582
+ const listData = listItemBlock[listType];
1583
+ if ((listData.rich_text && listData.rich_text.length > 0) || itemChildNodes.length > 0) {
1584
+ listItemHierarchyNodes.push(listItemHierarchyNode);
1585
+ }
1586
+ }
1587
+ // Return a container that holds all list items
1588
+ return {
1589
+ block: null, // No container block needed
1590
+ children: listItemHierarchyNodes,
1591
+ metadata: {
1592
+ tagName: listType === 'bulleted_list_item' ? 'ul' : 'ol'
1593
+ }
1594
+ };
1595
+ }
1596
+ catch (error) {
1597
+ console.warn('Error building list hierarchy:', error);
1598
+ // Fallback: create a simple text block
1599
+ return {
1600
+ block: {
1601
+ type: 'paragraph',
1602
+ paragraph: {
1603
+ rich_text: [{ type: 'text', text: { content: 'Error processing list content' } }],
1604
+ },
1605
+ },
1606
+ children: [],
1607
+ metadata: { tagName: 'paragraph' }
1608
+ };
1609
+ }
1610
+ }
1611
+ // Helper function to map child blocks to specific list items (legacy support)
1612
+ static mapChildBlocksToListItems(listContent, childBlocks, childNodes) {
1613
+ const listItemChildBlocks = new Map();
1614
+ // Find all <li> positions in the content
1615
+ const liPositions = [];
1616
+ let pos = 0;
1617
+ while (pos < listContent.length) {
1618
+ const liStart = listContent.indexOf('<li', pos);
1619
+ if (liStart === -1)
1620
+ break;
1621
+ liPositions.push(liStart);
1622
+ pos = liStart + 3;
1623
+ }
1624
+ // Map child nodes to their corresponding list items
1625
+ childNodes.forEach((childNode, index) => {
1626
+ // Find which <li> this child node belongs to
1627
+ let liIndex = -1;
1628
+ for (let i = 0; i < liPositions.length; i++) {
1629
+ const liStart = liPositions[i];
1630
+ const nextLiStart = i + 1 < liPositions.length ? liPositions[i + 1] : listContent.length;
1631
+ if (childNode.start >= liStart && childNode.start < nextLiStart) {
1632
+ liIndex = i;
1633
+ break;
1634
+ }
1635
+ }
1636
+ if (liIndex >= 0 && index < childBlocks.length) {
1637
+ if (!listItemChildBlocks.has(liIndex)) {
1638
+ listItemChildBlocks.set(liIndex, []);
1639
+ }
1640
+ listItemChildBlocks.get(liIndex).push(childBlocks[index]);
1641
+ }
1642
+ });
1643
+ return listItemChildBlocks;
1644
+ }
1645
+ // Enhanced list processor that handles child blocks (legacy support)
1646
+ static processNestedListWithChildBlocks(listContent, listType, blocks, listItemChildBlocks) {
1647
+ try {
1648
+ // Process each <li> element as a potential branch point
1649
+ const listItems = NotionAITool.extractListItemsWithBranching(listContent);
1650
+ for (let i = 0; i < listItems.length; i++) {
1651
+ const item = listItems[i];
1652
+ if (!item.text && !item.children.length)
1653
+ continue;
1654
+ // Create list item block
1655
+ const listItemBlock = {
1656
+ type: listType,
1657
+ [listType]: {
1658
+ rich_text: [],
1659
+ },
1660
+ };
1661
+ // Add parent text if present
1662
+ if (item.text && item.text.trim()) {
1663
+ const cleanText = NotionAITool.processNestedHtmlInListItem(item.text);
1664
+ if (cleanText) {
1665
+ listItemBlock[listType].rich_text = NotionAITool.parseBasicMarkdown(cleanText);
1531
1666
  }
1532
- // Add children to the parent block
1533
- if (childBlocks.length > 0) {
1534
- listItemBlock[listType].children = childBlocks;
1667
+ }
1668
+ // Collect all child blocks
1669
+ const allChildBlocks = [];
1670
+ // Add child blocks from hierarchical processing
1671
+ const childBlocks = listItemChildBlocks.get(i) || [];
1672
+ allChildBlocks.push(...childBlocks);
1673
+ // Process nested list children (traditional nested lists)
1674
+ if (item.children.length > 0) {
1675
+ for (const child of item.children) {
1676
+ const childListType = child.type === 'ul' ? 'bulleted_list_item' : 'numbered_list_item';
1677
+ NotionAITool.processNestedList(child.content, childListType, allChildBlocks);
1535
1678
  }
1536
1679
  }
1680
+ // Add children to the parent block
1681
+ if (allChildBlocks.length > 0) {
1682
+ listItemBlock[listType].children = allChildBlocks;
1683
+ }
1537
1684
  // Only add the block if it has text or children
1538
1685
  const listData = listItemBlock[listType];
1539
1686
  if ((listData.rich_text && listData.rich_text.length > 0) || listData.children) {
@@ -1542,17 +1689,21 @@ class NotionAITool {
1542
1689
  }
1543
1690
  }
1544
1691
  catch (error) {
1545
- console.warn('Error processing nested list:', error);
1692
+ console.warn('Error processing nested list with child blocks:', error);
1546
1693
  // Fallback: create a simple text block with the content
1547
1694
  blocks.push({
1548
1695
  type: 'paragraph',
1549
1696
  paragraph: {
1550
- rich_text: [{ type: 'text', text: { content: 'Error processing list content' } }],
1697
+ rich_text: [{ type: 'text', text: { content: 'Error processing list content with child blocks' } }],
1551
1698
  },
1552
1699
  });
1553
1700
  }
1554
1701
  }
1555
- // Extract list items with proper branching structure - only process top-level <li> tags
1702
+ // Legacy function for backward compatibility
1703
+ static processNestedList(listContent, listType, blocks, childNodes) {
1704
+ NotionAITool.processNestedListWithChildBlocks(listContent, listType, blocks, new Map());
1705
+ }
1706
+ // Extract list items with proper branching structure - simplified for hierarchical processing
1556
1707
  static extractListItemsWithBranching(content) {
1557
1708
  const items = [];
1558
1709
  let pos = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.2.30-beta",
3
+ "version": "1.2.31-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": [