Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
feat: splitting out our current markdown engine to a new package (#514)
Browse files Browse the repository at this point in the history
  • Loading branch information
erunion authored Mar 10, 2020
1 parent 5907499 commit 087374d
Show file tree
Hide file tree
Showing 29 changed files with 9,241 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/markdown-magic/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/node_modules
coverage
7 changes: 7 additions & 0 deletions packages/markdown-magic/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": [
"@readme/eslint-config",
"@readme/eslint-config/react"
],
"root": true
}
2 changes: 2 additions & 0 deletions packages/markdown-magic/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
coverage
7 changes: 7 additions & 0 deletions packages/markdown-magic/.jsinspectrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"threshold": 40,
"identifiers": true,
"ignore": "test",
"reporter": "default",
"suppress": 100
}
Empty file.
2 changes: 2 additions & 0 deletions packages/markdown-magic/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
coverage
dist
5 changes: 5 additions & 0 deletions packages/markdown-magic/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"singleQuote": true,
"trailingComma": "es5"
}
39 changes: 39 additions & 0 deletions packages/markdown-magic/GlossaryItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const React = require('react');
const PropTypes = require('prop-types');

const GlossaryTermsContext = require('./contexts/GlossaryTerms');

// https://github.com/readmeio/api-explorer/blob/0dedafcf71102feedaa4145040d3f57d79d95752/packages/api-explorer/src/lib/replace-vars.js#L8
function GlossaryItem({ term, terms }) {
const foundTerm = terms.find(i => term === i.term);

if (!foundTerm) return null;

return (
<span className="glossary-tooltip" v={foundTerm.term}>
<span className="glossary-item highlight">{foundTerm.term}</span>
<span className="tooltip-content">
<span className="tooltip-content-body">
- <strong className="term">{foundTerm.term}</strong> - {foundTerm.definition}
</span>
</span>
</span>
);
}

GlossaryItem.propTypes = {
term: PropTypes.string.isRequired,
terms: PropTypes.arrayOf(
PropTypes.shape({
definition: PropTypes.string.isRequired,
term: PropTypes.string.isRequired,
})
).isRequired,
};

// eslint-disable-next-line react/display-name
module.exports = props => (
<GlossaryTermsContext.Consumer>{terms => <GlossaryItem {...props} terms={terms} />}</GlossaryTermsContext.Consumer>
);

module.exports.GlossaryItem = GlossaryItem;
13 changes: 13 additions & 0 deletions packages/markdown-magic/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2018, Dom Harrington <dom@harrington-mail.com>

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
22 changes: 22 additions & 0 deletions packages/markdown-magic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# @readme/markdown

ReadMe's React-based Markdown parser

[![Build](https://github.com/readmeio/api-explorer/workflows/CI/badge.svg)](https://github.com/readmeio/api-explorer/tree/master/packages/markdown)

[![](https://d3vv6lp55qjaqc.cloudfront.net/items/1M3C3j0I0s0j3T362344/Untitled-2.png)](https://readme.io)

## Installation

```
npm install --save @readme/markdown
```

## Usage

## Credits
[Dom Harrington](https://github.com/domharrington/)

## License

ISC
3 changes: 3 additions & 0 deletions packages/markdown-magic/__tests__/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@readme/eslint-config/testing"
}
17 changes: 17 additions & 0 deletions packages/markdown-magic/__tests__/GlossaryItem.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const React = require('react');
const { shallow } = require('enzyme');

const { GlossaryItem } = require('../GlossaryItem.jsx');

test('should output a glossary item if the term exists', () => {
const term = 'acme';
const definition = 'This is a definition';
const glossaryItem = shallow(<GlossaryItem term={term} terms={[{ term, definition }]} />);

expect(glossaryItem.find('.glossary-item.highlight').text()).toBe(term);
expect(glossaryItem.find('.tooltip-content-body').text()).toBe(`- ${term} - ${definition}`);
});

test('should output nothing if the term does not exist', () => {
expect(shallow(<GlossaryItem term="something" terms={[]} />).html()).toBeNull();
});
100 changes: 100 additions & 0 deletions packages/markdown-magic/__tests__/__snapshots__/index.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`anchor target: should allow _blank if using HTML 1`] = `"<p><a href=\\"https://example.com\\" target=\\"_blank\\">test</a></p>"`;
exports[`anchor target: should default to _self 1`] = `"<p><a href=\\"https://example.com\\" target=\\"_self\\">test</a></p>"`;
exports[`anchors 1`] = `
"<p><a href=\\"http://example.com\\" target=\\"_self\\">link</a><br/>
<a href=\\"\\" target=\\"_self\\">xss</a><br/>
<a href=\\"/docs/slug\\" target=\\"_self\\" class=\\"doc-link\\" data-sidebar=\\"slug\\">doc</a><br/>
<a href=\\"/reference-link/slug\\" target=\\"_self\\">ref</a><br/>
<a href=\\"/changelog/slug\\" target=\\"_self\\">blog</a><br/>
<a href=\\"/changelog/slug\\" target=\\"_self\\">changelog</a><br/>
<a href=\\"/page/slug\\" target=\\"_self\\">page</a><br/>
</p>"
`;
exports[`anchors with baseUrl 1`] = `
"<p><a href=\\"/child/v1.0/docs/slug\\" target=\\"_self\\" class=\\"doc-link\\" data-sidebar=\\"slug\\">doc</a><br>
<a href=\\"/child/v1.0/reference-link/slug\\" target=\\"_self\\">ref</a><br>
<a href=\\"/child/v1.0/changelog/slug\\" target=\\"_self\\">blog</a><br>
<a href=\\"/child/v1.0/changelog/slug\\" target=\\"_self\\">changelog</a><br>
<a href=\\"/child/v1.0/page/slug\\" target=\\"_self\\">page</a><br>
</p>"
`;
exports[`check list items 1`] = `
"<ul>
<li><input type=\\"checkbox\\" disabled=\\"\\"/> checklistitem1</li>
<li><input type=\\"checkbox\\" checked=\\"\\" disabled=\\"\\"/> checklistitem1</li>
</ul>"
`;
exports[`code samples 1`] = `
"<pre><code class=\\"lang-javascript\\"><span class=\\"cm-s-neo\\"><span class=\\"cm-keyword\\">var</span> <span class=\\"cm-def\\">a</span> <span class=\\"cm-operator\\">=</span> <span class=\\"cm-number\\">1</span>;
</span></code></pre>
<pre><code><span class=\\"cm-s-neo\\">code-without-language
</span></code></pre>"
`;
exports[`emojis 1`] = `
"<p><img src=\\"/img/emojis/joy.png\\" alt=\\":joy:\\" title=\\":joy:\\" class=\\"emoji\\" align=\\"absmiddle\\" height=\\"20\\" width=\\"20\\"/><br/>
<i class=\\"fa fa-lock\\"></i><br/>
:unknown-emoji:<br/>
</p>"
`;
exports[`glossary 1`] = `"<p></p>"`;
exports[`headings 1`] = `
"<h1 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h1\\"></div>h1<a class=\\"fa fa-anchor\\" href=\\"#section-h1\\"></a></h1>
<h2 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h2\\"></div>h2<a class=\\"fa fa-anchor\\" href=\\"#section-h2\\"></a></h2>
<h3 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h3\\"></div>h3<a class=\\"fa fa-anchor\\" href=\\"#section-h3\\"></a></h3>
<h4 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h4\\"></div>h4<a class=\\"fa fa-anchor\\" href=\\"#section-h4\\"></a></h4>
<h5 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h5\\"></div>h5<a class=\\"fa fa-anchor\\" href=\\"#section-h5\\"></a></h5>
<h6 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-h6\\"></div>h6<a class=\\"fa fa-anchor\\" href=\\"#section-h6\\"></a></h6>
<h1 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-code\\"></div><code><span class=\\"cm-s-neo\\">code</span></code><a class=\\"fa fa-anchor\\" href=\\"#section-code\\"></a></h1>
<h1 class=\\"header-scroll\\"><div class=\\"anchor waypoint\\" id=\\"section-heading-with-some-more-content\\"></div>heading with some more CONTENT<a class=\\"fa fa-anchor\\" href=\\"#section-heading-with-some-more-content\\"></a></h1>"
`;
exports[`image 1`] = `"<p><img src=\\"http://example.com/image.png\\" alt=\\"Image\\"/></p>"`;
exports[`list items 1`] = `
"<ul>
<li>listitem1</li>
</ul>"
`;
exports[`should strip out inputs 1`] = `""`;
exports[`tables 1`] = `
"
<div class=\\"marked-table\\"><table><thead><tr><th>Tables</th><th style=\\"text-align:center\\">Are</th><th style=\\"text-align:right\\">Cool</th></tr></thead><tbody><tr><td>col 3 is</td><td style=\\"text-align:center\\">right-aligned</td><td style=\\"text-align:right\\">$1600</td></tr><tr><td>col 2 is</td><td style=\\"text-align:center\\">centered</td><td style=\\"text-align:right\\">$12</td></tr><tr><td>zebra stripes</td><td style=\\"text-align:center\\">are neat</td><td style=\\"text-align:right\\">$1</td></tr></tbody></table></div>"
`;
exports[`variables 1`] = `"<p><span>APIKEY</span></p>"`;
98 changes: 98 additions & 0 deletions packages/markdown-magic/__tests__/gemoji-parser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const unified = require('unified');
const remarkParse = require('remark-parse');
const parser = require('../gemoji-parser');

test('should output an image node for a known emoji', () => {
const emoji = 'joy';
const markdown = `This is a gemoji :${emoji}:.`;
const ast = {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{ type: 'text', value: 'This is a gemoji ' },
{
type: 'image',
title: `:${emoji}:`,
alt: `:${emoji}:`,
url: `/img/emojis/${emoji}.png`,
data: {
hProperties: {
className: 'emoji',
align: 'absmiddle',
height: '20',
width: '20',
},
},
},
{ type: 'text', value: '.' },
],
},
],
};

expect(
unified()
.use(remarkParse)
.use(parser)
.data('settings', { position: false })
.parse(markdown)
).toStrictEqual(ast);
});

test('should output an <i> for a font awesome icon', () => {
const emoji = 'fa-lock';
const markdown = `This is a gemoji :${emoji}:.`;
const ast = {
type: 'root',
children: [
{
type: 'paragraph',
children: [
{ type: 'text', value: 'This is a gemoji ' },
{
type: 'i',
data: {
hName: 'i',
hProperties: {
className: ['fa', emoji],
},
},
},
{ type: 'text', value: '.' },
],
},
],
};

expect(
unified()
.use(remarkParse)
.use(parser)
.data('settings', { position: false })
.parse(markdown)
).toStrictEqual(ast);
});

test('should output nothing for unknown emojis', () => {
const emoji = 'unknown-emoji';
const markdown = `This is a gemoji :${emoji}:.`;
const ast = {
type: 'root',
children: [
{
type: 'paragraph',
children: [{ type: 'text', value: markdown }],
},
],
};

expect(
unified()
.use(remarkParse)
.use(parser)
.data('settings', { position: false })
.parse(markdown)
).toStrictEqual(ast);
});
Loading

0 comments on commit 087374d

Please sign in to comment.