Skip to content

Commit

Permalink
Add option to keep all attributes as strings
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
RichardCzechowski committed Sep 20, 2024
1 parent 3a04b9e commit 08f85bd
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -525,6 +526,28 @@ compiler('This text has <span>html</span> in it but it won't be rendered', { dis
<span>This text has &lt;span&gt;html&lt;/span&gt; in it but it won't be rendered</span>
```
#### 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()}</>
}
<Markdown options={{ convertBooleans: false, overrides: { Capitalize } }}>
<Capitalize value="true" />
</Markdown>;
// or
compiler('<Capitalize value="true" />', { 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 `<code>` 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`:
Expand Down
27 changes: 27 additions & 0 deletions index.compiler.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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('<Capitalize value="true"/>', {
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('<Capitalize value="true"/>', {
convertBooleans: false,
overrides: { Capitalize },
})
)
expect(root.innerHTML).toMatchInlineSnapshot(`"TRUE"`)
})
})

describe('options.namedCodesToUnicode', () => {
// &amp; &gt; &lt; are already replaced by default
const content =
Expand Down
23 changes: 17 additions & 6 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,8 @@ function attributeValueToJSXPropValue(
tag: MarkdownToJSX.HTMLTags,
key: keyof React.AllHTMLAttributes<Element>,
value: string,
sanitizeUrlFn: MarkdownToJSX.Options['sanitizer']
sanitizeUrlFn: MarkdownToJSX.Options['sanitizer'],
convertBooleans: boolean
): any {
if (key === 'style') {
return value.split(/;\s?/).reduce(function (styles, kvPair) {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1252,7 +1256,8 @@ export function compiler(
tag,
key,
value,
options.sanitizer
options.sanitizer,
options.convertBooleans
))

if (
Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit 08f85bd

Please sign in to comment.