@@ -3,19 +3,20 @@ import { renderToString } from "react-dom/server";
33import * as ReactIs from "react-is" ;
44
55import { TextReducerProps } from "./../../components/TextReducer/TextReducer" ;
6+ import { DecodeHtmlEntitiesOptions , utils } from "./../" ;
67
78export interface ReduceToTextFuncType {
89 (
910 /**
1011 * Component or text to reduce HTML markup content to plain text.
1112 */
1213 input : React . ReactNode | React . ReactNode [ ] | string ,
13- options ?: Pick < TextReducerProps , "maxNodes" | "maxLength" >
14+ options ?: Pick < TextReducerProps , "maxNodes" | "maxLength" | "decodeHtmlEntities" | "decodeHtmlEntitiesOptions" >
1415 ) : string ;
1516}
1617
1718export const reduceToText : ReduceToTextFuncType = ( input , options ) => {
18- const { maxNodes, maxLength } = options || { } ;
19+ const { maxNodes, maxLength, decodeHtmlEntities } = options || { } ;
1920 const content : React . ReactNode | React . ReactNode [ ] = input ;
2021 let nodeCount = 0 ;
2122
@@ -46,6 +47,30 @@ export const reduceToText: ReduceToTextFuncType = (input, options) => {
4647 // Basic HTML cleanup
4748 text = text . replace ( / < [ ^ \s ] [ ^ > ] * > / g, "" ) . replace ( / \n / g, " " ) ;
4849
50+ if ( decodeHtmlEntities ) {
51+ const decodeDefaultOptions = {
52+ isAttributeValue : true ,
53+ strict : true ,
54+ } as DecodeHtmlEntitiesOptions ;
55+ let decodeErrors = 0 ;
56+ // we decode in pieces to some error tolerance even in strict mode
57+ text = text
58+ . split ( " " )
59+ . map ( ( value ) => {
60+ try {
61+ return utils . decodeHtmlEntities ( value , { ...decodeDefaultOptions } ) ;
62+ } catch {
63+ decodeErrors ++ ;
64+ return value ;
65+ }
66+ } )
67+ . join ( " " ) ;
68+ if ( decodeErrors > 0 ) {
69+ // eslint-disable-next-line no-console
70+ console . warn ( `${ decodeErrors } parse error(s) for decodeHtmlEntities, return un-decoded text` , text ) ;
71+ }
72+ }
73+
4974 if ( typeof maxLength === "number" ) {
5075 text = text . slice ( 0 , maxLength ) ;
5176 }
0 commit comments