Skip to content

Commit ebc69d2

Browse files
authored
Merge pull request #4 from jsakas/extra-data
Export front matter data
2 parents 3741624 + b0f2a12 commit ebc69d2

File tree

14 files changed

+3791
-44
lines changed

14 files changed

+3791
-44
lines changed

README.md

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A Webpack loader for converting Markdown files to React components (JSX).
88

9-
Currently supports ES6 imports and syntax highlighting.
9+
Currently supports imports, syntax highlighting, and extra data.
1010

1111
This loader was built for the purpose of documenting React Components, but can be used for other static documents you want to convert to HTML.
1212

@@ -36,16 +36,24 @@ Note: Requires React 16.2+
3636
# Installation
3737

3838
```
39-
yarn add markdown-to-react-loader
39+
yarn add --dev markdown-to-react-loader
4040
```
41-
Or
4241
```
43-
npm install --save-dev babel-loader @babel/preset-env @babel/preset-react markdown-to-react-loader
42+
npm install --save-dev markdown-to-react-loader
4443
```
4544

4645
# Usage
4746

48-
Update your Webpack config. Because this loader outputs JSX its recommended to use the babel-loader after to compile the ES6 how you want.
47+
Because it outputs ES6 and JSX its recommended to use in conjunction with the babel-loader to compile for your targetted environment.
48+
49+
```
50+
yarn add --dev babel-loader @babel/preset-env @babel/preset-react
51+
```
52+
```
53+
npm install --save-dev babel-loader @babel/preset-env @babel/preset-react
54+
```
55+
56+
Update your Webpack config:
4957

5058
```javascript
5159
{
@@ -54,9 +62,9 @@ Update your Webpack config. Because this loader outputs JSX its recommended to u
5462
use: [
5563
{
5664
loader: 'babel-loader',
57-
options: {
58-
presets: ['@babel/env', '@babel/react']
59-
}
65+
options: {
66+
presets: ['@babel/env', '@babel/react']
67+
}
6068
},
6169
'markdown-to-react-loader',
6270
],
@@ -83,7 +91,7 @@ import HelloWorld from './HelloWorld.md';
8391
ReactDOM.Render(<HelloWorld />, document.getElementById('app'));
8492
```
8593

86-
# Imports
94+
## Imports
8795

8896
You can write ES6 imports inline using front matter.
8997

@@ -103,14 +111,47 @@ Heres a component rendered inline:
103111

104112
```
105113

106-
# Syntax Highlighting
114+
## Syntax Highlighting
107115

108116
Syntax highlighting is done using PrismJS and is picked up automatically by tagging code blocks:
109117

110118
#### CodeSample.md
111119

112-
# Code Sample
120+
# Code Sample
121+
122+
```javascript
123+
console.log('This will be marked for highlighting');
124+
```
125+
126+
## Extra Data
127+
128+
Any front matter that is not under the `imports` key is considered extra data. It is parsed and exported as named exports from the module.
129+
130+
```markdown
131+
---
132+
title: Hello World
133+
slug: /post/1
134+
object:
135+
- foo: bar
136+
- baz: biz
137+
array:
138+
- foo
139+
- bar
140+
---
141+
```
142+
143+
The above front matter is transformed to:
113144

114-
```javascript
115-
console.log('This will be marked for highlighting');
116-
```
145+
```javascript
146+
const title = "Hello World";
147+
export { title };
148+
149+
const slug = "/post/1";
150+
export { slug };
151+
152+
const object = [{ foo: "bar" }, { baz: "biz" }];
153+
export { object };
154+
155+
const array = ["foo", "bar"];
156+
export { array };
157+
```

jest.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
"testEnvironment": "node",
3+
};

lib/markdown-to-react-loader.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,33 @@ renderer.code = function(code, lang) {
3939
`;
4040
};
4141

42+
const extraExports = extra => {
43+
let ret = '';
44+
for (var key in extra) {
45+
ret += `
46+
const ${key} = ${JSON.stringify(extra[key])};
47+
export { ${key} };
48+
`
49+
}
50+
51+
return ret;
52+
}
53+
4254
module.exports = function (source, map) {
4355
const parsed = fm(source);
56+
const attributes = parsed.attributes;
4457
const html = marked(parsed.body, {
4558
renderer: renderer,
4659
xhtml: true,
4760
});
4861

62+
const extra = Object.keys(attributes)
63+
.filter(k => k !== 'imports')
64+
.reduce((acc, cur) => {
65+
acc[cur] = attributes[cur];
66+
return acc;
67+
}, {});
68+
4969
const replaced = html
5070
.replace(/class="/g, 'className="')
5171
.replace(/\(/g, '&#40;')
@@ -56,6 +76,7 @@ module.exports = function (source, map) {
5676
const processed = `
5777
import React, { Fragment } from 'react';
5878
${parsed.attributes.imports ? parsed.attributes.imports : ''}
79+
${extraExports(extra)}
5980
const Markdown = () => (<Fragment>${replaced}</Fragment>);
6081
export default Markdown;
6182
`;

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,12 @@
1313
},
1414
"peerDependencies": {
1515
"react": "^16.2"
16+
},
17+
"devDependencies": {
18+
"jest": "^24.8.0",
19+
"prettier": "^1.18.2"
20+
},
21+
"scripts": {
22+
"test": "jest test"
1623
}
1724
}

test/all.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const markdownToReact = require('../lib/markdown-to-react-loader');
4+
const pretter = require('prettier');
5+
6+
7+
const testIO = (inFile, outFile) => {
8+
let input = getFileContents(inFile);
9+
let output = getFileContents(outFile);
10+
11+
let processed = pretter.format(
12+
markdownToReact(input),
13+
{
14+
parser: 'babel',
15+
}
16+
);
17+
18+
expect(output).toEqual(processed);
19+
}
20+
21+
const getFileContents = file => {
22+
return fs.readFileSync(path.resolve(__dirname, file)).toString('utf-8');
23+
}
24+
25+
test('Compiles hello, world', () => {
26+
testIO('io/simple.md', 'io/simple.js');
27+
});
28+
29+
test('Compiles file with imports', () => {
30+
testIO('io/imports.md', 'io/imports.js');
31+
});
32+
33+
test('Compiles file with code block', () => {
34+
testIO('io/codeblock.md', 'io/codeblock.js');
35+
});
36+
37+
test('Exports extra front matter as named exports', () => {
38+
testIO('io/data.md', 'io/data.js');
39+
});

test/io/codeblock.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React, { Fragment } from "react";
2+
3+
const Markdown = () => (
4+
<Fragment>
5+
<h1 id="code-sample">Code Sample</h1>
6+
7+
<pre className="language-javascript">
8+
<code className="language-javascript">
9+
console<span className="token punctuation">.</span>
10+
<span className="token function">log</span>
11+
<span className="token punctuation">&#40;</span>
12+
<span className="token string">
13+
'This will be marked for highlighting'
14+
</span>
15+
<span className="token punctuation">&#41;</span>
16+
<span className="token punctuation">;</span>
17+
</code>
18+
</pre>
19+
</Fragment>
20+
);
21+
export default Markdown;

test/io/codeblock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Code Sample
2+
3+
```javascript
4+
console.log('This will be marked for highlighting');
5+
```

test/io/data.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React, { Fragment } from "react";
2+
3+
const title = "Hello World";
4+
export { title };
5+
6+
const slug = "/post/1";
7+
export { slug };
8+
9+
const object = [{ foo: "bar" }, { baz: "biz" }];
10+
export { object };
11+
12+
const array = ["foo", "bar"];
13+
export { array };
14+
15+
const Markdown = () => (
16+
<Fragment>
17+
<p>This component comes with data</p>
18+
</Fragment>
19+
);
20+
export default Markdown;

test/io/data.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: Hello World
3+
slug: /post/1
4+
object:
5+
- foo: bar
6+
- baz: biz
7+
array:
8+
- foo
9+
- bar
10+
---
11+
12+
This component comes with data

test/io/imports.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+
import { SomeComponent } from "./SomeComponent";
3+
4+
const Markdown = () => (
5+
<Fragment>
6+
<h1 id="hello-world">Hello, World</h1>
7+
<p>Heres a component rendered inline:</p>
8+
<SomeComponent />
9+
</Fragment>
10+
);
11+
export default Markdown;

0 commit comments

Comments
 (0)