guigrpa / docx-templates

Template-based docx report creation
MIT License
882 stars 145 forks source link

`LINK` command without brackets throws `TypeError: Cannot read properties of undefined (reading 'split')` #378

Open davidjb opened 1 month ago

davidjb commented 1 month ago

A common typo I've encountered from user templates is with the LINK command, where a user misses the brackets in the command's options:

// Was
{{ link {url: 'https://example.com'} }}

// Should be
{{ link ({url: 'https://example.com'}) }}

If the surrounding () happens to be missed, an exception gets thrown when calling createReport:

node_modules/docx-templates/lib/xml.js:90
    var segments = str.split(options.literalXmlDelimiter);
                       ^
TypeError: Cannot read properties of undefined (reading 'split')
    at sanitizeText (node_modules/docx-templates/lib/xml.js:90:24)
    at buildXml (node_modules/docx-templates/lib/xml.js:65:16)
    at node_modules/docx-templates/lib/xml.js:77:20
    at Array.forEach (<anonymous>)
    at buildXml (node_modules/docx-templates/lib/xml.js:76:24)
    at node_modules/docx-templates/lib/xml.js:77:20
    at Array.forEach (<anonymous>)
    at buildXml (node_modules/docx-templates/lib/xml.js:76:24)
    at node_modules/docx-templates/lib/xml.js:77:20
    at Array.forEach (<anonymous>)

This is invalid syntax according the docx-templates docs but it's an easy mistake to overlook and it's a hard failure and even with failFast: false gets thrown separately to other in-document errors. Ideally the failure would be softer, like how missing a mismatched or missing {{ end-for }} command occurs and not throw an unhandled exception, being incorporated into other document errors.

Otherwise, if feasible, avoid requiring the brackets in the syntax would avoid them being forgotten.


When reporting a bug, please provide:

Code:

import { readFile } from 'node:fs/promises';
import { createReport } from 'docx-templates';

createReport({
  cmdDelimiter: ['{{', '}}'],
  failFast: false,
  template: readFile('template.docx'),
});

template.docx:

{{ link {url: 'https://example.com'} }}