From 6f11add2edb7544658433840ea31ffd2e874733d Mon Sep 17 00:00:00 2001 From: youdie006 Date: Thu, 27 Aug 2026 09:20:13 +0900 Subject: [PATCH] Fix doc.text() throwing NaN with lineBreak false and underline/strike/link/goTo --- CHANGELOG.md | 1 + lib/mixins/text.js | 10 ++++++++-- tests/unit/text.spec.js | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a26118738..7548a9e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fix bundlers and file tracers packing the ESM copies of the standard font metrics instead of the CommonJS ones the Node build actually loads, which left `Cannot find module` errors for every standard font at runtime, by resolving the internal `#standard-fonts/*` mapping to a single file under all conditions - Fix `doc.file()` throwing when the same in-memory attachment is embedded twice under one name, because the creation and modified dates the deduplication check compares are absent for sources that are not read from disk +- Fix `doc.text()` throwing `unsupported number: NaN` when `lineBreak: false` is combined with `underline`, `strike`, `link` or `goTo`, because the rendered width was computed from the line wrapper's measurements, which are never produced when wrapping is disabled ### [v0.20.1] - 2026-08-23 diff --git a/lib/mixins/text.js b/lib/mixins/text.js index f83d8ba7a..df74a1f86 100644 --- a/lib/mixins/text.js +++ b/lib/mixins/text.js @@ -524,9 +524,15 @@ export default { } // calculate the actual rendered width of the string after word and character spacing + // the wrapper supplies textWidth and wordCount; measure them directly when it did not run + const measuredWidth = + options.textWidth ?? + this.widthOfString(text, options) - characterSpacing * (text.length - 1); + const measuredWordCount = + options.wordCount ?? (text.trim() ? text.trim().split(/\s+/).length : 0); const renderedWidth = - options.textWidth + - wordSpacing * (options.wordCount - 1) + + measuredWidth + + wordSpacing * (measuredWordCount - 1) + characterSpacing * (text.length - 1); // create link annotations if the link option is given diff --git a/tests/unit/text.spec.js b/tests/unit/text.spec.js index 69cdb3b4d..6609ab9be 100644 --- a/tests/unit/text.spec.js +++ b/tests/unit/text.spec.js @@ -201,6 +201,23 @@ Q expect(docData).toContainText({ text: 'text with null x' }); }); + + test.each([ + ['underline', { underline: true }], + ['strike', { strike: true }], + ['link', { link: 'http://example.com/' }], + ['goTo', { goTo: 'anchor' }], + ])('with lineBreak false and %s', (_name, extraOptions) => { + const docData = logData(document); + + document.text('no line break', 50, 50, { + lineBreak: false, + ...extraOptions, + }); + document.end(); + + expect(docData).toContainText({ text: 'no line break' }); + }); }); describe('text with structure parent links', () => {