n8n-nodes-notion-advanced 1.2.20-beta → 1.2.22-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.
@@ -43,10 +43,13 @@ export declare class NotionAITool implements INodeType {
43
43
  }[]): string;
44
44
  static getUtf8BytePosition(str: string, charIndex: number): number;
45
45
  static buildXMLTree(content: string, tagProcessors: any[]): XMLNode[];
46
- static processXMLTreeDepthFirst(nodes: XMLNode[], blocks: IDataObject[], placeholderPrefix: string): Map<string, string>;
46
+ static processXMLTreeDepthFirst(nodes: XMLNode[], blocks: IDataObject[], placeholderCounter: {
47
+ value: number;
48
+ }): Map<string, string>;
47
49
  static applyHierarchicalReplacements(content: string, nodes: XMLNode[], replacements: Map<string, string>): string;
48
50
  static getAllNodesFromTree(nodes: XMLNode[]): XMLNode[];
49
51
  static processXmlTags(content: string, blocks: IDataObject[]): string;
52
+ static decodeHtmlEntities(content: string): string;
50
53
  static cleanupRemainingHtml(content: string, placeholderPrefix?: string): string;
51
54
  static processNestedHtmlInListItem(content: string): string;
52
55
  static convertInlineHtmlToMarkdown(content: string): string;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NotionAITool = void 0;
4
4
  const n8n_workflow_1 = require("n8n-workflow");
5
- const crypto_1 = require("crypto");
6
5
  const NotionUtils_1 = require("./NotionUtils");
7
6
  class NotionAITool {
8
7
  constructor() {
@@ -480,8 +479,8 @@ class NotionAITool {
480
479
  for (let i = 0; i < lines.length; i++) {
481
480
  const line = lines[i];
482
481
  const trimmedLine = line.trim();
483
- // Skip completely empty lines and XML placeholders (now using dynamic prefix check)
484
- if (!trimmedLine || /__XML_[a-f0-9]{8}_\d+__/.test(trimmedLine))
482
+ // Skip completely empty lines and placeholder artifacts
483
+ if (!trimmedLine || /__BLOCK_\d+__/.test(trimmedLine) || /^\d+__$/.test(trimmedLine))
485
484
  continue;
486
485
  // Skip lines that contain XML tag patterns (to prevent double processing)
487
486
  const xmlTagPatterns = [
@@ -789,9 +788,8 @@ class NotionAITool {
789
788
  return rootNodes;
790
789
  }
791
790
  // Process XML tree depth-first (children before parents)
792
- static processXMLTreeDepthFirst(nodes, blocks, placeholderPrefix) {
791
+ static processXMLTreeDepthFirst(nodes, blocks, placeholderCounter) {
793
792
  const replacements = new Map();
794
- let blockCounter = 0;
795
793
  const processNode = (node) => {
796
794
  // First, process all children depth-first
797
795
  for (const child of node.children) {
@@ -835,14 +833,14 @@ class NotionAITool {
835
833
  // Handle special list processors
836
834
  if (node.listProcessor && (node.tagName === 'ul' || node.tagName === 'ol')) {
837
835
  node.listProcessor(innerContent, blocks);
838
- return `${placeholderPrefix}${blockCounter++}__`;
836
+ return `__BLOCK_${placeholderCounter.value++}__`;
839
837
  }
840
838
  // Use blockCreator to create the block
841
839
  const block = node.processor(...node.groups);
842
840
  if (block) {
843
841
  blocks.push(block);
844
842
  }
845
- return `${placeholderPrefix}${blockCounter++}__`;
843
+ return `__BLOCK_${placeholderCounter.value++}__`;
846
844
  }
847
845
  catch (error) {
848
846
  console.warn(`Error processing XML node ${node.tagName}:`, error);
@@ -888,8 +886,10 @@ class NotionAITool {
888
886
  // New hierarchical XML-like tag processing function
889
887
  static processXmlTags(content, blocks) {
890
888
  let processedContent = content;
891
- // Generate unique placeholder prefix to avoid collisions
892
- const placeholderPrefix = `__XML_${(0, crypto_1.randomUUID)().slice(0, 8)}_`;
889
+ // First, decode HTML entities to proper XML tags
890
+ processedContent = NotionAITool.decodeHtmlEntities(processedContent);
891
+ // Use simple sequential placeholder format: __BLOCK_N__
892
+ let placeholderCounter = 1; // Start from 1 for cleaner numbering
893
893
  // Debug mode for development
894
894
  const DEBUG_ORDERING = process.env.NODE_ENV === 'development';
895
895
  // Define all tag processors
@@ -1153,11 +1153,12 @@ class NotionAITool {
1153
1153
  })));
1154
1154
  }
1155
1155
  // Step 2: Process tree depth-first (children before parents)
1156
- const replacements = NotionAITool.processXMLTreeDepthFirst(xmlTree, blocks, placeholderPrefix);
1156
+ const counterRef = { value: 1 };
1157
+ const replacements = NotionAITool.processXMLTreeDepthFirst(xmlTree, blocks, counterRef);
1157
1158
  // Step 3: Apply hierarchical replacements to content
1158
1159
  processedContent = NotionAITool.applyHierarchicalReplacements(processedContent, xmlTree, replacements);
1159
1160
  // Step 4: Clean up any remaining HTML tags
1160
- processedContent = NotionAITool.cleanupRemainingHtml(processedContent, placeholderPrefix);
1161
+ processedContent = NotionAITool.cleanupRemainingHtml(processedContent);
1161
1162
  if (DEBUG_ORDERING) {
1162
1163
  console.log(`Processed ${xmlTree.length} root XML nodes hierarchically, created ${blocks.length} blocks`);
1163
1164
  }
@@ -1180,7 +1181,7 @@ class NotionAITool {
1180
1181
  if (block) {
1181
1182
  blocks.push(block);
1182
1183
  }
1183
- return `${placeholderPrefix}${Math.random()}__`;
1184
+ return `__BLOCK_${placeholderCounter++}__`;
1184
1185
  }
1185
1186
  catch (error) {
1186
1187
  console.warn('Error in fallback processor:', error);
@@ -1205,34 +1206,46 @@ class NotionAITool {
1205
1206
  if (processedMatches.length > 0) {
1206
1207
  processedContent = NotionAITool.optimizedReplace(processedContent, processedMatches);
1207
1208
  }
1208
- processedContent = NotionAITool.cleanupRemainingHtml(processedContent, placeholderPrefix);
1209
+ processedContent = NotionAITool.cleanupRemainingHtml(processedContent);
1209
1210
  }
1210
1211
  return processedContent;
1211
1212
  }
1213
+ // Helper function to decode HTML entities
1214
+ static decodeHtmlEntities(content) {
1215
+ const entityMap = {
1216
+ '&lt;': '<',
1217
+ '&gt;': '>',
1218
+ '&amp;': '&',
1219
+ '&quot;': '"',
1220
+ '&apos;': "'",
1221
+ '&#39;': "'",
1222
+ '&nbsp;': ' ',
1223
+ };
1224
+ let decoded = content;
1225
+ Object.entries(entityMap).forEach(([entity, char]) => {
1226
+ decoded = decoded.replace(new RegExp(entity, 'g'), char);
1227
+ });
1228
+ return decoded;
1229
+ }
1212
1230
  // Cleanup function to remove remaining HTML tags and XML_BLOCK artifacts
1213
1231
  static cleanupRemainingHtml(content, placeholderPrefix) {
1214
1232
  let cleaned = content;
1215
- // Remove XML_BLOCK placeholder artifacts (support both old and new format)
1233
+ // Simplified placeholder cleanup - use one consistent pattern
1216
1234
  if (placeholderPrefix) {
1217
- // More aggressive placeholder cleanup with multiple patterns
1218
- const placeholderPatterns = [
1219
- new RegExp(`${placeholderPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\d+__`, 'g'),
1220
- new RegExp(`_${placeholderPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\d+_`, 'g'),
1221
- new RegExp(`${placeholderPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\d+`, 'g')
1222
- ];
1223
- placeholderPatterns.forEach(pattern => {
1224
- cleaned = cleaned.replace(pattern, '');
1225
- });
1235
+ // Clean up our specific placeholder format: __XML_{uuid8}_{number}__
1236
+ const escapedPrefix = placeholderPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1237
+ const placeholderPattern = new RegExp(`${escapedPrefix}\\d+__`, 'g');
1238
+ cleaned = cleaned.replace(placeholderPattern, '');
1226
1239
  }
1227
1240
  // Comprehensive fallback cleanup for all possible placeholder formats
1228
- const fallbackPatterns = [
1229
- /__XML_BLOCK_\d+__/g,
1230
- /__XML_[a-f0-9]{8}_\d+__/g,
1231
- /_XML_[a-f0-9]{8}_\d+_/g,
1232
- /__XML_[a-f0-9-]+_\d+__/g,
1233
- /_XML_[a-f0-9-]+_\d+_/g
1241
+ const placeholderPatterns = [
1242
+ /__XML_[a-f0-9]{8}_\d+__/g, // Standard format: __XML_abc12345_1__
1243
+ /\b[A-Z]{2}[a-z0-9]{8,12}_+\b/g, // Variations like "MLb82d670450__"
1244
+ /\b[A-Za-z]{2,4}[a-f0-9]{6,12}_+\b/g, // More flexible pattern matching
1245
+ /_[a-f0-9]{8,12}_\d+_*/g, // Underscore variations
1246
+ /[a-f0-9]{8,12}_\d+__/g, // Without prefix
1234
1247
  ];
1235
- fallbackPatterns.forEach(pattern => {
1248
+ placeholderPatterns.forEach(pattern => {
1236
1249
  cleaned = cleaned.replace(pattern, '');
1237
1250
  });
1238
1251
  // Remove entire lines containing XML content to prevent double processing
@@ -1283,20 +1296,6 @@ class NotionAITool {
1283
1296
  cleaned = cleaned.replace(/^\s*[\r\n]/gm, '');
1284
1297
  // Remove multiple consecutive line breaks
1285
1298
  cleaned = cleaned.replace(/\n{3,}/g, '\n\n');
1286
- // Remove lines that contain only XML_BLOCK artifacts (more patterns)
1287
- const artifactPatterns = [
1288
- /^.*__XML_BLOCK_\d+__.*$/gm,
1289
- /^.*__XML_[a-f0-9]{8}_\d+__.*$/gm,
1290
- /^.*_XML_[a-f0-9]{8}_\d+_.*$/gm,
1291
- /^.*__XML_[a-f0-9-]+_\d+__.*$/gm,
1292
- /^.*_XML_[a-f0-9-]+_\d+_.*$/gm
1293
- ];
1294
- artifactPatterns.forEach(pattern => {
1295
- cleaned = cleaned.replace(pattern, '');
1296
- });
1297
- // Final cleanup of any remaining isolated placeholder patterns
1298
- cleaned = cleaned.replace(/\b_+XML_[a-f0-9-]+_\d+_*\b/g, '');
1299
- cleaned = cleaned.replace(/\b_*XML_[a-f0-9-]+_\d+_+\b/g, '');
1300
1299
  return cleaned.trim();
1301
1300
  }
1302
1301
  // Helper function to process nested HTML elements in list items
@@ -1365,12 +1364,12 @@ class NotionAITool {
1365
1364
  // Helper function to convert inline HTML to markdown
1366
1365
  static convertInlineHtmlToMarkdown(content) {
1367
1366
  let processed = content;
1368
- // Convert HTML formatting tags to markdown equivalents
1367
+ // Convert HTML formatting tags to markdown equivalents - process in order to handle nested tags
1369
1368
  const htmlToMarkdown = [
1370
1369
  { regex: /<strong\s*[^>]*>(.*?)<\/strong>/gis, replacement: '**$1**' },
1371
1370
  { regex: /<b\s*[^>]*>(.*?)<\/b>/gis, replacement: '**$1**' },
1372
- { regex: /<em\s*[^>]*>(.*?)<\/em>/gis, replacement: '*$1*' },
1373
- { regex: /<i\s*[^>]*>(.*?)<\/i>/gis, replacement: '*$1*' },
1371
+ { regex: /<em\s*[^>]*>(.*?)<\/em>/gis, replacement: '_$1_' }, // Use underscore to avoid conflicts
1372
+ { regex: /<i\s*[^>]*>(.*?)<\/i>/gis, replacement: '_$1_' }, // Use underscore to avoid conflicts
1374
1373
  { regex: /<code\s*[^>]*>(.*?)<\/code>/gis, replacement: '`$1`' },
1375
1374
  { regex: /<a\s+href="([^"]*)"[^>]*>(.*?)<\/a>/gis, replacement: '[$2]($1)' },
1376
1375
  { regex: /<u\s*[^>]*>(.*?)<\/u>/gis, replacement: '$1' }, // Notion doesn't support underline
@@ -1512,7 +1511,8 @@ class NotionAITool {
1512
1511
  { regex: /\[([^\]]+)\]\(([^)]+)\)/g, type: 'link' }, // [text](url)
1513
1512
  { regex: /\*\*\*([^*]+)\*\*\*/g, type: 'bold_italic' }, // ***bold italic***
1514
1513
  { regex: /\*\*([^*]+)\*\*/g, type: 'bold' }, // **bold**
1515
- { regex: /\*([^*]+)\*/g, type: 'italic' }, // *italic*
1514
+ { regex: /_([^_]+)_/g, type: 'italic' }, // _italic_ (changed from *)
1515
+ { regex: /\*([^*]+)\*/g, type: 'italic' }, // *italic* (keep for backward compatibility)
1516
1516
  { regex: /~~([^~]+)~~/g, type: 'strikethrough' }, // ~~strikethrough~~
1517
1517
  { regex: /`([^`]+)`/g, type: 'code' }, // `code`
1518
1518
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-notion-advanced",
3
- "version": "1.2.20-beta",
3
+ "version": "1.2.22-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": [