UNPKG

n8n-nodes-docx-genie

Version:

n8n node package for DOCX document manipulation and processing

276 lines 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DocxFindReplace = void 0; const n8n_workflow_1 = require("n8n-workflow"); class DocxFindReplace { constructor() { this.description = { displayName: 'DOCX Find & Replace', name: 'docxFindReplace', icon: 'file:docx.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operations"].length}} operation(s)', description: 'Find and replace text in DOCX documents with support for regex patterns and multiple operations', defaults: { name: 'DOCX Find & Replace', }, inputs: ["main"], outputs: ["main"], usableAsTool: true, properties: [ { displayName: 'Binary Property', name: 'binaryPropertyName', type: 'string', default: 'data', required: true, description: 'Name of the binary property that contains the DOCX file', placeholder: 'data', }, { displayName: 'Operations', name: 'operations', type: 'fixedCollection', default: { operation: [ { find: '', replace: '', useRegex: false, caseSensitive: true, }, ], }, typeOptions: { multipleValues: true, sortable: true, }, description: 'Find and replace operations to perform on the DOCX document', options: [ { name: 'operation', displayName: 'Operation', values: [ { displayName: 'Case Sensitive', name: 'caseSensitive', type: 'boolean', default: true, description: 'Whether the search should be case sensitive', displayOptions: { hide: { useRegex: [true], }, }, }, { displayName: 'Find', name: 'find', type: 'string', default: '', required: true, description: 'Text or regex pattern to find in the document', placeholder: 'Enter text to find...', }, { displayName: 'Global Replace', name: 'globalReplace', type: 'boolean', default: true, description: 'Whether to replace all occurrences (global flag for regex)', displayOptions: { show: { useRegex: [true], }, }, }, { displayName: 'Replace', name: 'replace', type: 'string', default: '', description: 'Text to replace with (can be empty for deletion)', placeholder: 'Enter replacement text...', }, { displayName: 'Use Regex', name: 'useRegex', type: 'boolean', default: false, description: 'Whether to treat the find text as a regular expression', }, ], }, ], }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add Option', default: {}, options: [ { displayName: 'Output Binary Property Name', name: 'outputBinaryPropertyName', type: 'string', default: 'data', description: 'Name for the output binary property containing the modified DOCX file', }, { displayName: 'Output Filename', name: 'outputFileName', type: 'string', default: '', description: 'Custom filename for the output file (optional)', placeholder: 'modified_document.docx', }, ], }, ], }; } async execute() { const items = this.getInputData(); const returnData = []; let PizZip; try { PizZip = require('pizzip'); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'pizzip package not found. Please install it: npm install pizzip', { level: 'warning' }); } for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { try { const binaryPropertyName = this.getNodeParameter('binaryPropertyName', itemIndex); const operations = this.getNodeParameter('operations', itemIndex); const options = this.getNodeParameter('options', itemIndex, {}); const item = items[itemIndex]; if (!item.binary || !item.binary[binaryPropertyName]) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No binary data found with property name "${binaryPropertyName}"`, { itemIndex }); } const binaryData = item.binary[binaryPropertyName]; if (binaryData.mimeType && !binaryData.mimeType.includes('wordprocessingml')) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid file type. Please provide a DOCX file.', { itemIndex }); } const binaryBuffer = await this.helpers.getBinaryDataBuffer(itemIndex, binaryPropertyName); let zip; try { zip = new PizZip(binaryBuffer); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to read DOCX file. File may be corrupted.', { itemIndex }); } let documentContent; try { const documentXml = zip.files['word/document.xml']; if (!documentXml) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Document content not found in DOCX file', { itemIndex }); } documentContent = documentXml.asText(); } catch (error) { if (error instanceof n8n_workflow_1.NodeOperationError) { throw error; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to extract document content.', { itemIndex }); } let modifiedContent = documentContent; let totalReplacements = 0; for (const operation of operations.operation) { if (!operation.find) { continue; } try { let searchPattern; let replaceText = operation.replace || ''; if (operation.useRegex) { const flags = operation.globalReplace !== false ? 'g' : ''; searchPattern = new RegExp(operation.find, flags); } else { const flags = operation.caseSensitive !== false ? 'g' : 'gi'; const escapedFind = operation.find.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); searchPattern = new RegExp(escapedFind, flags); } const matchesBefore = (modifiedContent.match(searchPattern) || []).length; modifiedContent = modifiedContent.replace(searchPattern, replaceText); const matchesAfter = (modifiedContent.match(searchPattern) || []).length; totalReplacements += matchesBefore - matchesAfter; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid regex pattern: ${operation.find}`, { itemIndex }); } } try { zip.files['word/document.xml'] = { ...zip.files['word/document.xml'], _data: modifiedContent, }; } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to update document content.', { itemIndex }); } let outputBuffer; try { outputBuffer = zip.generate({ type: 'nodebuffer' }); } catch (error) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Failed to generate modified DOCX file.', { itemIndex }); } const outputBinaryPropertyName = options.outputBinaryPropertyName || 'data'; const outputFileName = options.outputFileName || binaryData.fileName || 'modified_document.docx'; const newBinaryData = { data: outputBuffer.toString('base64'), mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', fileName: outputFileName, fileExtension: 'docx', }; const outputItem = { json: { ...item.json, docxFindReplace: { operationsPerformed: operations.operation.length, totalReplacements, originalFileName: binaryData.fileName, outputFileName, processedAt: new Date().toISOString(), }, }, binary: { ...item.binary, [outputBinaryPropertyName]: newBinaryData, }, pairedItem: itemIndex, }; returnData.push(outputItem); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { ...items[itemIndex].json, error: error.message, errorDetails: { itemIndex, operation: 'docxFindReplace', timestamp: new Date().toISOString(), }, }, pairedItem: itemIndex, }); } else { if (error instanceof n8n_workflow_1.NodeOperationError) { throw error; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error.message, { itemIndex }); } } } return [returnData]; } } exports.DocxFindReplace = DocxFindReplace; //# sourceMappingURL=DocxFindReplace.node.js.map