From 08f85bd662524ca1d4f8cf9224d925196f7587f2 Mon Sep 17 00:00:00 2001 From: Richard Czechowski Date: Fri, 20 Sep 2024 12:45:14 -0600 Subject: [PATCH 1/2] Add option to keep all attributes as strings When data is coming from user supplied HTML, I would expect all attributes to come in as strings. Instead this library converts boolean strings "true" and "false" to boolean primitives. My use-case is very heavy on custom components, many of which do string operations on the incoming data. For example we have one that passes in a a path to get properties off of an object, that path can be the string literal values "true"/"false". It would be nice to be able to toggle off the feature that converts booleans. --- README.md | 23 +++++++++++++++++++++++ index.compiler.spec.tsx | 27 +++++++++++++++++++++++++++ index.tsx | 23 +++++++++++++++++------ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8f32a817..b1851295 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The most lightweight, customizable React markdown component. - [options.slugify](#optionsslugify) - [options.namedCodesToUnicode](#optionsnamedcodestounicode) - [options.disableParsingRawHTML](#optionsdisableparsingrawhtml) + - [options.convertBooleans](#optionsconvertbooleans) - [Syntax highlighting](#syntax-highlighting) - [Getting the smallest possible bundle size](#getting-the-smallest-possible-bundle-size) - [Usage with Preact](#usage-with-preact) @@ -525,6 +526,28 @@ compiler('This text has html in it but it won't be rendered', { dis This text has <span>html</span> in it but it won't be rendered ``` +#### options.convertBooleans + +By default, boolean attribute values are converted to boolean primitives. To disable this behavior, set convertBooleans to false + +```jsx +const Capitalize = ({ value }: { value: string }) => { + return <>{value.toUpperCase()} +} + + + +; + +// or + +compiler('', { convertBooleans: false, overrides: { Capitalize } }); + +// renders: +<>TRUE + +``` + ### Syntax highlighting When using [fenced code blocks](https://www.markdownguide.org/extended-syntax/#syntax-highlighting) with language annotation, that language will be added to the `` element as `class="lang-${language}"`. For best results, you can use `options.overrides` to provide an appropriate syntax highlighting integration like this one using `highlight.js`: diff --git a/index.compiler.spec.tsx b/index.compiler.spec.tsx index 08d3d39f..183bfc84 100644 --- a/index.compiler.spec.tsx +++ b/index.compiler.spec.tsx @@ -4100,6 +4100,33 @@ describe('footnotes', () => { }) }) +describe('options.convertBooleans', () => { + const Capitalize = ({ value }: { value: string }) => { + return <>{value.toUpperCase()} + } + + it('should convert boolean attribute values to boolean primitives by default', () => { + expect(() => + render( + compiler('', { + overrides: { Capitalize }, + }) + ) + ).toThrowErrorMatchingInlineSnapshot( + `"value.toUpperCase is not a function"` + ) + }) + it('should leave attribute values of true/false as strings when convertBooleans is disabled ', () => { + render( + compiler('', { + convertBooleans: false, + overrides: { Capitalize }, + }) + ) + expect(root.innerHTML).toMatchInlineSnapshot(`"TRUE"`) + }) +}) + describe('options.namedCodesToUnicode', () => { // & > < are already replaced by default const content = diff --git a/index.tsx b/index.tsx index ad34347e..0acbe148 100644 --- a/index.tsx +++ b/index.tsx @@ -734,7 +734,8 @@ function attributeValueToJSXPropValue( tag: MarkdownToJSX.HTMLTags, key: keyof React.AllHTMLAttributes, value: string, - sanitizeUrlFn: MarkdownToJSX.Options['sanitizer'] + sanitizeUrlFn: MarkdownToJSX.Options['sanitizer'], + convertBooleans: boolean ): any { if (key === 'style') { return value.split(/;\s?/).reduce(function (styles, kvPair) { @@ -758,10 +759,12 @@ function attributeValueToJSXPropValue( value = value.slice(1, value.length - 1) } - if (value === 'true') { - return true - } else if (value === 'false') { - return false + if (convertBooleans) { + if (value === 'true') { + return true + } else if (value === 'false') { + return false + } } return value @@ -1147,6 +1150,7 @@ export function compiler( : namedCodesToUnicode options.createElement = options.createElement || React.createElement + options.convertBooleans = options.convertBooleans ?? true // JSX custom pragma // eslint-disable-next-line no-unused-vars @@ -1252,7 +1256,8 @@ export function compiler( tag, key, value, - options.sanitizer + options.sanitizer, + options.convertBooleans )) if ( @@ -2294,6 +2299,12 @@ export namespace MarkdownToJSX { } export type Options = Partial<{ + /** + * Optionally convert boolean string attributes to boolean in JSX. + * Enabled by default + */ + convertBooleans: boolean + /** * Ultimate control over the output of all rendered JSX. */ From 88f5cea532c0473abdeb0cfd46a7153e084f62b3 Mon Sep 17 00:00:00 2001 From: Richard Czechowski Date: Fri, 20 Sep 2024 13:11:51 -0600 Subject: [PATCH 2/2] Add changeset --- .changeset/shaggy-dolls-lay.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/shaggy-dolls-lay.md diff --git a/.changeset/shaggy-dolls-lay.md b/.changeset/shaggy-dolls-lay.md new file mode 100644 index 00000000..cb91c92d --- /dev/null +++ b/.changeset/shaggy-dolls-lay.md @@ -0,0 +1,5 @@ +--- +"markdown-to-jsx": patch +--- + +Add option to keep all attributes as strings