Repository: apostrophecms/sanitize-html
Pull request #684 (2024-12-09 20:06:31)

Bugfix: Setting text with transformTags in cases where the element originally had no text content 
<!-- Please don't delete this template -->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

## Summary

`transformTags` can now set the text content of discarded tags, even if it originally had no text child elements.
Closes https://github.com/apostrophecms/sanitize-html/issues/682
Also added a test case after reading the [bonus line in contributing.md :P](https://github.com/apostrophecms/.github/blob/main/CONTRIBUTING.md#reporting-bugs)

## What are the specific steps to test this change?
See https://github.com/apostrophecms/sanitize-html/issues/682 / newly added test

## What kind of change does this PR introduce?
*(Check at least one)*

- [x] Bug fix
- [ ] New feature
- [ ] Refactor
- [ ] Documentation
- [ ] Build-related changes
- [ ] Other

## Make sure the PR fulfills these requirements:

- [x] It includes a) the existing issue ID being resolved, b) a convincing reason for adding this feature, or c) a clear description of the bug it resolves
- [x] The changelog is updated
- [ ] Related documentation has been updated
- [x] Related tests have been updated

Not sure if it needs a change in documentation.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dcc4944..b64c386 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Changelog
 
+## UNRELEASED
+
+- Fix adding text with `transformTags` in cases where it originally had no text child elements. Thanks to [f0x](https://cthu.lu).
+
 ## 2.13.1 (2024-10-03)
 
 - Fix to allow regex in `allowedClasses` wildcard whitelist. Thanks to `anak-dev`.
diff --git a/index.js b/index.js
index 629cb79..0b458d6 100644
--- a/index.js
+++ b/index.js
@@ -274,6 +274,15 @@ function sanitizeHtml(html, options, _recursing) {
       if (skip) {
         if (options.disallowedTagsMode === 'discard' || options.disallowedTagsMode === 'completelyDiscard') {
           // We want the contents but not this tag
+          if (frame.innerText && !hasText) {
+            const escaped = escapeHtml(frame.innerText);
+            if (options.textFilter) {
+              result += options.textFilter(escaped, name);
+            } else {
+              result += escapeHtml(frame.innerText);
+            }
+            addedText = true;
+          }
           return;
         }
         tempResult = result;


Test patch:
diff --git a/test/test.js b/test/test.js
index cd3dcaf..e039ea1 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1706,6 +1706,18 @@ describe('sanitizeHtml', function() {
       disallowedTagsMode: 'completelyDiscard'
     });
 
+    assert.equal(sanitizedHtml, expectedOutput);
+  });
+  it('should transform text content of tags even if they originally had none', () => {
+    const inputHtml = '<div></div>';
+    const expectedOutput = 'new content';
+    const sanitizedHtml = sanitizeHtml(inputHtml, {
+      allowedTags: [],
+      transformTags: {
+        "div": () => ({text: "new content"})
+      }
+    });
+
     assert.equal(sanitizedHtml, expectedOutput);
   });
 });