diff --git a/README.md b/README.md index 24a1893b..d22431ce 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,69 @@ -# markdown to jsx converter +# markdown to jsx compiler ![build status](https://api.travis-ci.org/yaycmyk/markdown-to-jsx.svg) [![codecov](https://codecov.io/gh/yaycmyk/markdown-to-jsx/branch/master/graph/badge.svg)](https://codecov.io/gh/yaycmyk/markdown-to-jsx) - Enables the safe parsing of markdown into proper React JSX objects, so you don't need to use a pattern like `dangerouslySetInnerHTML` and potentially open your application up to security issues. -The only exception is arbitrary HTML in the markdown (kind of an antipattern), which will still use the unsafe method. +The only exception is arbitrary block-level HTML in the markdown (considered a markdown antipattern), which will still use the unsafe method. + +Uses [remark-parse](https://github.com/wooorm/remark-parse) under the hood to parse markdown into a consistent AST format. The following [remark](https://github.com/wooorm/remark) settings are set by `markdown-to-jsx`: -Uses [remark](https://github.com/wooorm/remark) under the hood to parse markdown into a consistent AST format. +- footnotes: true +- gfm: true +- position: false Requires React >= 0.14. ## Usage -```js -import converter from 'markdown-to-jsx'; -import React from 'react'; -import {render} from 'react-dom'; +The default export function signature: -render(converter('# Hello world!'), document.body); +```js +compiler(markdown: string, options: object?) ``` -[remark options](https://github.com/wooorm/remark#remarkprocessvalue-options-done) can be passed as the second argument: +ES6-style usage: ```js -converter('* abc\n* def\n* ghi', {bullet: '*'}); +import compiler from 'markdown-to-jsx'; +import React from 'react'; +import {render} from 'react-dom'; + +render(compiler('# Hello world!'), document.body); ``` -_Footnotes are enabled by default as of `markdown-to-jsx@2.0.0`._ +Override a particular HTML tag's output: -## Overriding tags and adding props +```jsx +import compiler from 'markdown-to-jsx'; +import React from 'react'; +import {render} from 'react-dom'; -As of `markdown-to-jsx@2.0.0`, it's now possible to selectively override a given HTML tag's JSX representation. This is done through a new third argument to the converter: an object made of keys, each being the lowercase html tag name (p, figure, a, etc.) to be overridden. +// surprise, it's a div instead! +const MyParagraph = ({children, ...props}) => (
` tags with the given component `MyParagraph`, and add the `className` specified in `props`. - Depending on the type of element, there are some props that must be preserved to ensure the markdown is converted as intended. They are: - `a`: `title`, `href` @@ -58,8 +74,4 @@ Depending on the type of element, there are some props that must be preserved to Any conflicts between passed `props` and the specific properties above will be resolved in favor of `markdown-to-jsx`'s code. -## Known Issues - -- remark's handling of arbitrary HTML causes nodes to be split, which causes garbage and malformed HTML - [Bug Ticket](https://github.com/wooorm/remark/issues/124) - MIT diff --git a/index.js b/index.js index ddad369c..f360af16 100644 --- a/index.js +++ b/index.js @@ -399,7 +399,7 @@ function coalesceInlineHTML(ast) { return ast.children.forEach(coalescer); } -export default function markdownToJSX(markdown, options = {}, overrides = {}) { +export default function markdownToJSX(markdown, {overrides = {}} = {}) { let definitions; let footnotes; @@ -550,14 +550,8 @@ export default function markdownToJSX(markdown, options = {}, overrides = {}) { a string`); } - if (getType.call(options) !== '[object Object]') { - throw new Error(`markdown-to-jsx: the second argument must be - undefined or an object literal ({}) containing - valid remark options`); - } - if (getType.call(overrides) !== '[object Object]') { - throw new Error(`markdown-to-jsx: the third argument must be + throw new Error(`markdown-to-jsx: options.overrides (second argument property) must be undefined or an object literal with shape: { htmltagname: { @@ -567,10 +561,12 @@ export default function markdownToJSX(markdown, options = {}, overrides = {}) { }`); } - options.position = options.position || false; - options.footnotes = options.footnotes || true; + const remarkAST = unified().use(parser).parse(markdown, { + footnotes: true, + gfm: true, + position: false, + }); - const remarkAST = unified().use(parser).parse(markdown, options); const extracted = extractDefinitionsFromASTTree(remarkAST, astToJSX); definitions = extracted.definitions; diff --git a/index.spec.js b/index.spec.js index 4edd307f..ca2f0db5 100644 --- a/index.spec.js +++ b/index.spec.js @@ -15,35 +15,13 @@ describe('markdown-to-jsx', () => { expect(() => converter()).toThrow(); expect(() => converter(1)).toThrow(); - expect(() => converter(function(){})).toThrow(); + expect(() => converter(() => {})).toThrow(); expect(() => converter({})).toThrow(); expect(() => converter([])).toThrow(); expect(() => converter(null)).toThrow(); expect(() => converter(true)).toThrow(); }); - it('should throw if not passed an object or undefined (second arg)', () => { - expect(() => converter('')).not.toThrow(); - expect(() => converter('', {})).not.toThrow(); - - expect(() => converter('', 1)).toThrow(); - expect(() => converter('', function(){})).toThrow(); - expect(() => converter('', [])).toThrow(); - expect(() => converter('', null)).toThrow(); - expect(() => converter('', true)).toThrow(); - }); - - it('should throw if not passed an object or undefined (third arg)', () => { - expect(() => converter('', {})).not.toThrow(); - expect(() => converter('', {}, {})).not.toThrow(); - - expect(() => converter('', {}, 1)).toThrow(); - expect(() => converter('', {}, function(){})).toThrow(); - expect(() => converter('', {}, [])).toThrow(); - expect(() => converter('', {}, null)).toThrow(); - expect(() => converter('', {}, true)).toThrow(); - }); - it('should discard the root