From 57fd081dc29263db8b70bb50eb91b4b7bec9e082 Mon Sep 17 00:00:00 2001 From: kevin9327 <5299031+kevin9327@users.noreply.github.com> Date: Tue, 29 Sep 2026 06:43:57 +0900 Subject: [PATCH] Keep the space a whitespace-only span puts between two words A text fragment remembers whether space touched its edges, so mergeText can glue the pieces a parser split out of one word and space the rest. A text node that is only whitespace was skipped without a trace, so the fragments on either side of it looked adjacent and were glued. Wikipedia's HTML writes every   as   , and the text around it shares a parent, so the Python article read "Firstappeared", "20February 1991", "Python3.0", and "December1989", 43 blocks in all. A whitespace-only node now marks the text block before it as ending in space, which is what it was on the page. Co-Authored-By: Claude Opus 5.5 --- src/distill.js | 6 ++++++ tests/distill.test.js | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/distill.js b/src/distill.js index d9274c1..71b93c3 100644 --- a/src/distill.js +++ b/src/distill.js @@ -347,6 +347,12 @@ export function distill(html, url = '', { view = null, type = '' } = {}) { // space that was never in the page. if (text) { blocks.push({ type: 'text', text, host: node.parentNode, pre: /^\s/.test(raw), post: /\s$/.test(raw) }); + } else if (raw && blocks.at(-1)?.type === 'text') { + // A node that is only a space still separates the words either side + // of it. Wikipedia writes every   as a span holding nothing + // else, and the fragments around it share a parent, so without this + // an infobox read "Firstappeared" and "20February 1991". + blocks.at(-1).post = true; } return; } diff --git a/tests/distill.test.js b/tests/distill.test.js index d365fda..d73f7fb 100644 --- a/tests/distill.test.js +++ b/tests/distill.test.js @@ -347,6 +347,20 @@ test('an entity does not put spaces inside a word', () => { assert.ok(text.includes('interface & its restraint'), 'a real space was swallowed'); }); +test('a space in an element of its own still separates two words', () => { + // Wikipedia's HTML writes every   as  . + // That span has no text once whitespace is collapsed, and the words either + // side of it were glued: "Firstappeared", "20February 1991". + const p = distill(` + + +
First appeared20 February 1991

ten items

`, 'https://example.test/'); + const text = p.blocks.map((b) => b.text).join('\n'); + assert.ok(text.includes('First appeared'), `words glued:\n${text}`); + assert.ok(text.includes('20 February 1991'), `words glued:\n${text}`); + assert.ok(text.includes('ten items'), `words glued:\n${text}`); +}); + test('an icon button is named by its aria-label, a nameless one is dropped', () => { const blocks = social().blocks; assert.ok(blocks.some((b) => b.type === 'button' && b.text === 'Follow'), 'a labelled button went missing');