Skip to content

Commit 35f7cf4

Browse files
authored
Merge pull request #5 from jsakas/replace-refactor
Replace refactor
2 parents d2d5cc4 + 33e70f1 commit 35f7cf4

File tree

12 files changed

+971
-27
lines changed

12 files changed

+971
-27
lines changed

lib/markdown-to-react-loader.js

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,51 @@ const marked = require('marked');
33
const Prism = require('prismjs');
44
const renderer = new marked.Renderer();
55

6+
const singleReplaceChars = {
7+
'\(': '(',
8+
'\)': ')',
9+
'\{': '{',
10+
'\}': '}',
11+
}
12+
const regexString = `[${Object.keys(singleReplaceChars).join('')}]`;
13+
const regex = new RegExp(regexString, 'gm');
14+
15+
function replaceReact(string) {
16+
return string
17+
.replace(regex, m => singleReplaceChars[m])
18+
.replace(/class="/g, 'className="')
19+
}
20+
21+
const reactSafe = (fn) => {
22+
return function () {
23+
let original = fn.apply(renderer, [...arguments]);
24+
let replaced = replaceReact(original);
25+
return replaced;
26+
}
27+
}
628

7-
renderer.code = function(code, lang) {
29+
function processCodeBlock (code, lang) {
830
let className, highlighter, replaced;
931

1032
// users can easily type in any language they want,
1133
// we don't want the app to blow up in case of bad input.
1234
try {
13-
require(`prismjs/components/prism-${lang}`);
14-
className = `language-${lang}`;
15-
highlighter = Prism.languages[lang];
35+
if (typeof lang === 'undefined') {
36+
className = '';
37+
highlighter = '';
38+
} else {
39+
require(`prismjs/components/prism-${lang}`);
40+
className = `language-${lang}`;
41+
highlighter = Prism.languages[lang];
42+
}
1643
} catch (e) {
17-
console.warn(`Could not find PrismJS language ${lang}`);
44+
console.warn(`Could not find PrismJS language ${lang}`, e);
1845
className = '';
1946
highlighter = '';
2047
}
2148

2249
try {
23-
const wrapped = Prism.highlight(code, highlighter);
50+
const wrapped = Prism.highlight(code, highlighter);
2451
replaced = wrapped.replace(/\n/g, '<br />');
2552
} catch (e) {
2653
console.error(`Failed to highlight syntax for language ${lang}`);
@@ -31,15 +58,46 @@ renderer.code = function(code, lang) {
3158
}
3259

3360
return `
34-
<pre class="${className}">
35-
<code class="${className}">
36-
${replaced}
37-
</code>
38-
</pre>
39-
`;
40-
};
61+
<pre class="${className}">
62+
<code class="${className}">
63+
${replaced}
64+
</code>
65+
</pre>
66+
`;
67+
}
68+
69+
/**
70+
* Block level renderer methods
71+
* https://marked.js.org/#/USING_PRO.md#block-level-renderer-methods
72+
*/
73+
renderer.code = reactSafe(processCodeBlock);
74+
renderer.blockquote = reactSafe(renderer.blockquote);
75+
renderer.paragraph = reactSafe(renderer.paragraph);
76+
renderer.heading = reactSafe(renderer.heading);
77+
renderer.html = renderer.html;
78+
renderer.hr = reactSafe(renderer.hr);
79+
renderer.list = reactSafe(renderer.list);
80+
renderer.listitem = reactSafe(renderer.listitem);
81+
renderer.checkbox = reactSafe(renderer.checkbox);
82+
renderer.paragraph = reactSafe(renderer.paragraph);
83+
renderer.table = reactSafe(renderer.table);
84+
renderer.tablerow = reactSafe(renderer.tablerow);
85+
renderer.tablecell = reactSafe(renderer.tablecell);
4186

42-
const extraExports = extra => {
87+
/**
88+
* Inline level renderer methods
89+
* https://marked.js.org/#/USING_PRO.md#inline-level-renderer-methods
90+
*/
91+
renderer.strong = reactSafe(renderer.strong);
92+
renderer.em = reactSafe(renderer.em);
93+
renderer.codespan = reactSafe(renderer.codespan);
94+
renderer.br = reactSafe(renderer.br);
95+
renderer.del = reactSafe(renderer.del);
96+
renderer.link = reactSafe(renderer.link);
97+
renderer.image = reactSafe(renderer.image);
98+
renderer.text = reactSafe(renderer.text);
99+
100+
function extraExports(extra) {
43101
let ret = '';
44102
for (var key in extra) {
45103
ret += `
@@ -66,18 +124,11 @@ module.exports = function (source, map) {
66124
return acc;
67125
}, {});
68126

69-
const replaced = html
70-
.replace(/class="/g, 'className="')
71-
.replace(/\(/g, '&#40;')
72-
.replace(/\)/g, '&#41;')
73-
.replace(/\{/g, '&#123;')
74-
.replace(/\}/g, '&#125;');
75-
76127
const processed = `
77128
import React, { Fragment } from 'react';
78129
${parsed.attributes.imports ? parsed.attributes.imports : ''}
79130
${extraExports(extra)}
80-
const Markdown = () => (<Fragment>${replaced}</Fragment>);
131+
const Markdown = () => (<Fragment>${html}</Fragment>);
81132
export default Markdown;
82133
`;
83134

test/all.test.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const markdownToReact = require('../lib/markdown-to-react-loader');
44
const pretter = require('prettier');
55

66

7-
const testIO = (inFile, outFile) => {
7+
const expectIO = (inFile, outFile) => {
88
let input = getFileContents(inFile);
99
let output = getFileContents(outFile);
1010

@@ -23,17 +23,33 @@ const getFileContents = file => {
2323
}
2424

2525
test('Compiles hello, world', () => {
26-
testIO('io/simple.md', 'io/simple.js');
26+
expectIO('io/simple.md', 'io/simple.js');
2727
});
2828

2929
test('Compiles file with imports', () => {
30-
testIO('io/imports.md', 'io/imports.js');
30+
expectIO('io/imports.md', 'io/imports.js');
3131
});
3232

3333
test('Compiles file with code block', () => {
34-
testIO('io/codeblock.md', 'io/codeblock.js');
34+
expectIO('io/codeblock.md', 'io/codeblock.js');
3535
});
3636

3737
test('Exports extra front matter as named exports', () => {
38-
testIO('io/data.md', 'io/data.js');
38+
expectIO('io/data.md', 'io/data.js');
39+
});
40+
41+
test('Can work with an async component', () => {
42+
expectIO('io/javascript.md', 'io/javascript.js');
43+
});
44+
45+
test('Properly converts parens & curly brackets', () => {
46+
expectIO('io/replace-chars.md', 'io/replace-chars.js');
47+
});
48+
49+
test('Converts tables and table cells', () => {
50+
expectIO('io/table.md', 'io/table.js');
51+
});
52+
53+
test('Can render everything', () => {
54+
expectIO('io/everything.md', 'io/everything.js');
3955
});

test/io/data-function.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React, { Fragment } from "react";
2+
3+
const module = () => import('my-module');
4+
export { module };
5+
6+
const Markdown = () => (
7+
<Fragment>
8+
<p>Something async</p>
9+
</Fragment>
10+
);
11+
export default Markdown;

test/io/data-function.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
module: () => import('my-module')
3+
---
4+
5+
Something async

0 commit comments

Comments
 (0)