n8n-nodes-docx-filler 1.0.0 → 1.1.0
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.
- package/README.md +20 -7
- package/dist/DocxFiller/DocxFiller.node.js +84 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ n8n community node to automatically fill DOCX documents (French DC1, DC2, AE adm
|
|
|
14
14
|
- Automatic field detection (SIRET, TVA, email, address, etc.)
|
|
15
15
|
- Checkbox state copying
|
|
16
16
|
- Compatible with n8n AI Agents (`usableAsTool: true`)
|
|
17
|
+
- **Multiple input formats**: file path, binary property, or base64
|
|
17
18
|
|
|
18
19
|
## Installation
|
|
19
20
|
|
|
@@ -46,8 +47,8 @@ Fills a template document with data extracted from a source document.
|
|
|
46
47
|
|
|
47
48
|
| Parameter | Description |
|
|
48
49
|
|-----------|-------------|
|
|
49
|
-
| `sourceDocument` | Document containing company data
|
|
50
|
-
| `templateDocument` | Empty template to fill
|
|
50
|
+
| `sourceDocument` | Document containing company data |
|
|
51
|
+
| `templateDocument` | Empty template to fill |
|
|
51
52
|
| `outputProperty` | Binary property name for output (default: "data") |
|
|
52
53
|
|
|
53
54
|
### Extract Data
|
|
@@ -56,7 +57,7 @@ Extracts company data from a filled document.
|
|
|
56
57
|
|
|
57
58
|
| Parameter | Description |
|
|
58
59
|
|-----------|-------------|
|
|
59
|
-
| `document` | Document to analyze
|
|
60
|
+
| `document` | Document to analyze |
|
|
60
61
|
|
|
61
62
|
### Analyze
|
|
62
63
|
|
|
@@ -66,6 +67,16 @@ Analyzes document structure for debugging.
|
|
|
66
67
|
|-----------|-------------|
|
|
67
68
|
| `document` | Document to analyze |
|
|
68
69
|
|
|
70
|
+
### Input Formats
|
|
71
|
+
|
|
72
|
+
All document parameters accept **3 input formats** (auto-detected):
|
|
73
|
+
|
|
74
|
+
| Format | Example | Use Case |
|
|
75
|
+
|--------|---------|----------|
|
|
76
|
+
| **File path** | `/home/node/shared_docs/doc.docx` | AI Agents, direct file access |
|
|
77
|
+
| **Binary property** | `data` | Standard n8n workflow |
|
|
78
|
+
| **Base64** | `UEsDBBQAAAAI...` | Inline data |
|
|
79
|
+
|
|
69
80
|
## Supported Fields
|
|
70
81
|
|
|
71
82
|
The node automatically recognizes these fields in French administrative documents:
|
|
@@ -82,19 +93,21 @@ The node automatically recognizes these fields in French administrative document
|
|
|
82
93
|
|
|
83
94
|
## Usage with AI Agent
|
|
84
95
|
|
|
85
|
-
This node is compatible with n8n AI Agents.
|
|
96
|
+
This node is compatible with n8n AI Agents. You can pass **file paths directly** - no need for binary data handling.
|
|
86
97
|
|
|
87
98
|
**Example agent prompt:**
|
|
88
99
|
```
|
|
89
100
|
You have access to the DOCX Filler tool to fill documents.
|
|
90
101
|
|
|
91
102
|
Use the "fill" operation with:
|
|
92
|
-
- sourceDocument:
|
|
93
|
-
- templateDocument:
|
|
103
|
+
- sourceDocument: /home/node/shared_docs/company_data.docx
|
|
104
|
+
- templateDocument: /home/node/shared_docs/template_DC2.docx
|
|
94
105
|
|
|
95
106
|
Execute directly without asking for confirmation.
|
|
96
107
|
```
|
|
97
108
|
|
|
109
|
+
> **Note**: When using file paths in Docker, ensure the directory is mounted and accessible from the container.
|
|
110
|
+
|
|
98
111
|
## Example Workflow
|
|
99
112
|
|
|
100
113
|
```
|
|
@@ -115,7 +128,7 @@ cd n8n-nodes-docx-filler
|
|
|
115
128
|
# Install dependencies
|
|
116
129
|
npm install
|
|
117
130
|
|
|
118
|
-
# Build
|
|
131
|
+
# Build & | package.json Version 1.0.0 → 1.1.0
|
|
119
132
|
npm run build
|
|
120
133
|
|
|
121
134
|
# Watch mode
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -6,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
39
|
exports.DocxFiller = void 0;
|
|
7
40
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
8
41
|
const pizzip_1 = __importDefault(require("pizzip"));
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
9
43
|
// Labels spécifiques à rechercher dans les documents DC/AE
|
|
10
44
|
const LABEL_PATTERNS = [
|
|
11
45
|
['siret', ['numéro siret', 'n° siret', 'siret']],
|
|
@@ -224,6 +258,48 @@ function escapeXml(text) {
|
|
|
224
258
|
.replace(/"/g, '"')
|
|
225
259
|
.replace(/'/g, ''');
|
|
226
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Détecte le type d'entrée et retourne le buffer du document
|
|
263
|
+
* Supporte : chemin de fichier, nom de propriété binaire, ou base64
|
|
264
|
+
*/
|
|
265
|
+
async function getDocumentBuffer(context, itemIndex, input, items) {
|
|
266
|
+
// 1. Vérifier si c'est un chemin de fichier (commence par / ou contient .docx)
|
|
267
|
+
const looksLikePath = input.startsWith('/') ||
|
|
268
|
+
input.startsWith('./') ||
|
|
269
|
+
input.startsWith('../') ||
|
|
270
|
+
/^[a-zA-Z]:\\/.test(input) || // Windows path
|
|
271
|
+
(input.includes('.docx') && !input.includes(' ') && input.length < 500);
|
|
272
|
+
if (looksLikePath) {
|
|
273
|
+
// Tenter de lire le fichier depuis le système de fichiers
|
|
274
|
+
try {
|
|
275
|
+
if (fs.existsSync(input)) {
|
|
276
|
+
return fs.readFileSync(input);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Si la lecture échoue, continuer avec les autres méthodes
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// 2. Vérifier si c'est un nom de propriété binaire
|
|
284
|
+
if (items[itemIndex].binary && items[itemIndex].binary[input]) {
|
|
285
|
+
return await context.helpers.getBinaryDataBuffer(itemIndex, input);
|
|
286
|
+
}
|
|
287
|
+
// 3. Vérifier si c'est du base64 valide (longueur raisonnable et caractères valides)
|
|
288
|
+
const base64Regex = /^[A-Za-z0-9+/]+=*$/;
|
|
289
|
+
if (input.length > 100 && base64Regex.test(input.replace(/\s/g, ''))) {
|
|
290
|
+
const buffer = Buffer.from(input, 'base64');
|
|
291
|
+
// Vérifier que c'est bien un ZIP (DOCX = ZIP)
|
|
292
|
+
if (buffer.length > 4 && buffer[0] === 0x50 && buffer[1] === 0x4B) {
|
|
293
|
+
return buffer;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// 4. Si rien n'a fonctionné, donner un message d'erreur clair
|
|
297
|
+
throw new Error(`Impossible de charger le document "${input.substring(0, 50)}..."\n` +
|
|
298
|
+
`Formats acceptés:\n` +
|
|
299
|
+
`- Chemin de fichier: /path/to/document.docx\n` +
|
|
300
|
+
`- Propriété binaire: data (si le fichier est attaché en binaire)\n` +
|
|
301
|
+
`- Base64: contenu encodé en base64`);
|
|
302
|
+
}
|
|
227
303
|
class DocxFiller {
|
|
228
304
|
constructor() {
|
|
229
305
|
this.description = {
|
|
@@ -281,7 +357,7 @@ class DocxFiller {
|
|
|
281
357
|
operation: ['fill'],
|
|
282
358
|
},
|
|
283
359
|
},
|
|
284
|
-
description: 'Document source contenant les données entreprise (binary property name ou base64)',
|
|
360
|
+
description: 'Document source contenant les données entreprise (chemin fichier, binary property name, ou base64)',
|
|
285
361
|
},
|
|
286
362
|
{
|
|
287
363
|
displayName: 'Template Document',
|
|
@@ -294,7 +370,7 @@ class DocxFiller {
|
|
|
294
370
|
operation: ['fill'],
|
|
295
371
|
},
|
|
296
372
|
},
|
|
297
|
-
description: 'Document template vide à remplir (binary property name ou base64)',
|
|
373
|
+
description: 'Document template vide à remplir (chemin fichier, binary property name, ou base64)',
|
|
298
374
|
},
|
|
299
375
|
{
|
|
300
376
|
displayName: 'Output Property',
|
|
@@ -320,7 +396,7 @@ class DocxFiller {
|
|
|
320
396
|
operation: ['extract', 'analyze'],
|
|
321
397
|
},
|
|
322
398
|
},
|
|
323
|
-
description: 'Document à analyser (binary property name ou base64)',
|
|
399
|
+
description: 'Document à analyser (chemin fichier, binary property name, ou base64)',
|
|
324
400
|
},
|
|
325
401
|
],
|
|
326
402
|
};
|
|
@@ -336,25 +412,9 @@ class DocxFiller {
|
|
|
336
412
|
const sourceDocParam = this.getNodeParameter('sourceDocument', i);
|
|
337
413
|
const templateDocParam = this.getNodeParameter('templateDocument', i);
|
|
338
414
|
const outputProperty = this.getNodeParameter('outputProperty', i);
|
|
339
|
-
// Charger les documents (depuis binary ou base64)
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// Source document
|
|
343
|
-
if (items[i].binary && items[i].binary[sourceDocParam]) {
|
|
344
|
-
sourceBuffer = await this.helpers.getBinaryDataBuffer(i, sourceDocParam);
|
|
345
|
-
}
|
|
346
|
-
else {
|
|
347
|
-
// Assume base64
|
|
348
|
-
sourceBuffer = Buffer.from(sourceDocParam, 'base64');
|
|
349
|
-
}
|
|
350
|
-
// Template document
|
|
351
|
-
if (items[i].binary && items[i].binary[templateDocParam]) {
|
|
352
|
-
templateBuffer = await this.helpers.getBinaryDataBuffer(i, templateDocParam);
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
// Assume base64
|
|
356
|
-
templateBuffer = Buffer.from(templateDocParam, 'base64');
|
|
357
|
-
}
|
|
415
|
+
// Charger les documents (depuis chemin, binary ou base64)
|
|
416
|
+
const sourceBuffer = await getDocumentBuffer(this, i, sourceDocParam, items);
|
|
417
|
+
const templateBuffer = await getDocumentBuffer(this, i, templateDocParam, items);
|
|
358
418
|
// Charger les DOCX avec PizZip
|
|
359
419
|
const sourceZip = new pizzip_1.default(sourceBuffer);
|
|
360
420
|
const templateZip = new pizzip_1.default(templateBuffer);
|
|
@@ -392,13 +452,7 @@ class DocxFiller {
|
|
|
392
452
|
}
|
|
393
453
|
else if (operation === 'extract') {
|
|
394
454
|
const documentParam = this.getNodeParameter('document', i);
|
|
395
|
-
|
|
396
|
-
if (items[i].binary && items[i].binary[documentParam]) {
|
|
397
|
-
docBuffer = await this.helpers.getBinaryDataBuffer(i, documentParam);
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
docBuffer = Buffer.from(documentParam, 'base64');
|
|
401
|
-
}
|
|
455
|
+
const docBuffer = await getDocumentBuffer(this, i, documentParam, items);
|
|
402
456
|
const zip = new pizzip_1.default(docBuffer);
|
|
403
457
|
const xml = ((_c = zip.file('word/document.xml')) === null || _c === void 0 ? void 0 : _c.asText()) || '';
|
|
404
458
|
const paragraphs = extractParagraphs(xml);
|
|
@@ -423,13 +477,7 @@ class DocxFiller {
|
|
|
423
477
|
}
|
|
424
478
|
else if (operation === 'analyze') {
|
|
425
479
|
const documentParam = this.getNodeParameter('document', i);
|
|
426
|
-
|
|
427
|
-
if (items[i].binary && items[i].binary[documentParam]) {
|
|
428
|
-
docBuffer = await this.helpers.getBinaryDataBuffer(i, documentParam);
|
|
429
|
-
}
|
|
430
|
-
else {
|
|
431
|
-
docBuffer = Buffer.from(documentParam, 'base64');
|
|
432
|
-
}
|
|
480
|
+
const docBuffer = await getDocumentBuffer(this, i, documentParam, items);
|
|
433
481
|
const zip = new pizzip_1.default(docBuffer);
|
|
434
482
|
const xml = ((_d = zip.file('word/document.xml')) === null || _d === void 0 ? void 0 : _d.asText()) || '';
|
|
435
483
|
const paragraphs = extractParagraphs(xml);
|
package/package.json
CHANGED