Add gfm plugins

This commit is contained in:
Dom Christie 2017-11-10 14:21:46 +00:00
parent 216791b9da
commit 42e4a09b57
16 changed files with 180747 additions and 0 deletions

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# turndown-plugin-gfm
A [Turndown](https://github.com/domchristie/turndown) plugin which adds GitHub Flavored Markdown extensions.
## Installation
npm:
```
npm install turndown-plugin-gfm
```
Browser:
```html
<script src="https://unpkg.com/turndown/dist/turndown.js"></script>
<script src="https://unpkg.com/turndown/dist/turndown-plugin-gfm.js"></script>
```
## Usage
```js
// For Node.js
var TurndownService = require('turndown')
var turndownPluginGfm = require('turndown-plugin-gfm')
var gfm = turndownPluginGfm.gfm
var turndownService = new TurndownService()
turndownService.use(gfm)
var markdown = turndownService.turndown('<strike>Hello world!</strike>')
```
turndown-plugin-gfm is a suite of plugins which can be applied individually. The available plugins are as follows:
- `strikethrough` (for converting `<strike>`, `<s>`, and `<del>` elements)
- `tables`
- `taskListItems`
- `gfm` (which applies all of the above)
So for example, if you only wish to convert tables:
```js
var tables = require('turndown-plugin-gfm').tables
var turndownService = new TurndownService()
turndownService.use(tables)
```
## License
turndown-plugin-gfm is copyright © 2017+ Dom Christie and released under the MIT license.

View File

@ -0,0 +1,8 @@
import config from './rollup.config'
export default config({
output: {
format: 'cjs',
file: 'lib/turndown-plugin-gfm.browser.cjs.js'
}
})

View File

@ -0,0 +1,8 @@
import config from './rollup.config'
export default config({
output: {
format: 'es',
file: 'lib/turndown-plugin-gfm.browser.es.js'
}
})

View File

@ -0,0 +1,8 @@
import config from './rollup.config'
export default config({
output: {
format: 'cjs',
file: 'lib/turndown-plugin-gfm.cjs.js'
}
})

View File

@ -0,0 +1,8 @@
import config from './rollup.config'
export default config({
output: {
format: 'es',
file: 'lib/turndown-plugin-gfm.es.js'
}
})

View File

@ -0,0 +1,8 @@
import config from './rollup.config'
export default config({
output: {
format: 'iife',
file: 'dist/turndown-plugin-gfm.js'
}
})

7
config/rollup.config.js Normal file
View File

@ -0,0 +1,7 @@
export default function (config) {
return {
name: 'turndownPluginGfm',
input: 'src/gfm.js',
output: config.output
}
}

3576
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

39
package.json Normal file
View File

@ -0,0 +1,39 @@
{
"name": "turndown-plugin-gfm",
"description": "Turndown plugin to add GitHub Flavored Markdown extensions.",
"version": "0.0.1",
"author": "Dom Christie",
"devDependencies": {
"browserify": "^14.5.0",
"rollup": "^0.50.0",
"standard": "^10.0.3",
"turndown": "0.0.8",
"turndown-attendant": "0.0.2"
},
"files": [
"lib",
"dist"
],
"jsnext:main": "lib/turndown-plugin-gfm.es.js",
"keywords": [
"turndown",
"turndown-plugin",
"html-to-markdown",
"html",
"markdown",
"github-flavored-markdown",
"gfm"
],
"license": "MIT",
"main": "lib/turndown-plugin-gfm.cjs.js",
"module": "lib/turndown-plugin-gfm.es.js",
"scripts": {
"build": "npm run build-cjs && npm run build-es && npm run build-iife",
"build-cjs": "rollup -c config/rollup.config.cjs.js && rollup -c config/rollup.config.browser.cjs.js",
"build-es": "rollup -c config/rollup.config.es.js && rollup -c config/rollup.config.browser.es.js",
"build-iife": "rollup -c config/rollup.config.iife.js",
"build-test": "browserify test/turndown-plugin-gfm-test.js --outfile test/turndown-plugin-gfm-test.browser.js",
"prepublish": "npm run build",
"test": "npm run build && standard ./src/**/*.js && node test/turndown-plugin-gfm-test.js"
}
}

9
src/gfm.js Normal file
View File

@ -0,0 +1,9 @@
import strikethrough from './strikethrough'
import tables from './tables'
import taskListItems from './task-list-items'
function gfm (turndownService) {
turndownService.use([strikethrough, tables, taskListItems])
}
export { gfm, strikethrough, tables, taskListItems }

8
src/strikethrough.js Normal file
View File

@ -0,0 +1,8 @@
export default function strikethrough (turndownService) {
turndownService.addRule('strikethrough', {
filter: ['del', 's', 'strike'],
replacement: function (content) {
return '~' + content + '~'
}
})
}

55
src/tables.js Normal file
View File

@ -0,0 +1,55 @@
var rules = {}
rules.tableCell = {
filter: ['th', 'td'],
replacement: function (content, node) {
return cell(content, node)
}
}
rules.tableRow = {
filter: 'tr',
replacement: function (content, node) {
var borderCells = ''
var alignMap = { left: ':--', right: '--:', center: ':-:' }
if (node.parentNode.nodeName === 'THEAD') {
for (var i = 0; i < node.childNodes.length; i++) {
var align = node.childNodes[i].attributes.align
var border = '---'
if (align) border = alignMap[align.value] || border
borderCells += cell(border, node.childNodes[i])
}
}
return '\n' + content + (borderCells ? '\n' + borderCells : '')
}
}
rules.table = {
filter: 'table',
replacement: function (content) {
// Ensure there are no blank lines
content = content.replace('\n\n', '\n')
return '\n\n' + content + '\n\n'
}
}
rules.tableSection = {
filter: ['thead', 'tbody', 'tfoot'],
replacement: function (content) {
return content
}
}
function cell (content, node) {
var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node)
var prefix = ' '
if (index === 0) prefix = '| '
return prefix + content + ' |'
}
export default function tables (turndownService) {
for (var key in rules) turndownService.addRule(key, rules[key])
}

10
src/task-list-items.js Normal file
View File

@ -0,0 +1,10 @@
export default function taskListItems (turndownService) {
turndownService.addRule('taskListItems', {
filter: function (node) {
return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
},
replacement: function (content, node) {
return (node.checked ? '[x]' : '[ ]') + ' '
}
})
}

178
test/index.html Normal file
View File

@ -0,0 +1,178 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>turndown test runner</title>
<link rel="stylesheet" href="../node_modules/turndown-attendant/dist/styles.css">
</head>
<body>
<!-- TEST CASES -->
<div class="case" data-name="strike">
<div class="input"><strike>Lorem ipsum</strike></div>
<pre class="expected">~Lorem ipsum~</pre>
</div>
<div class="case" data-name="s">
<div class="input"><s>Lorem ipsum</s></div>
<pre class="expected">~Lorem ipsum~</pre>
</div>
<div class="case" data-name="del">
<div class="input"><del>Lorem ipsum</del></div>
<pre class="expected">~Lorem ipsum~</pre>
</div>
<div class="case" data-name="unchecked inputs">
<div class="input"><ul><li><input type=checkbox>Check Me!</li></ul></div>
<pre class="expected">* [ ] Check Me!</pre>
</div>
<div class="case" data-name="checked inputs">
<div class="input"><ul><li><input type=checkbox checked>Checked!</li></ul></div>
<pre class="expected">* [x] Checked!</pre>
</div>
<div class="case" data-name="basic table">
<div class="input">
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
</tr>
</tbody>
</table>
</div>
<pre class="expected">| Column 1 | Column 2 |
| --- | --- |
| Row 1, Column 1 | Row 1, Column 2 |
| Row 2, Column 1 | Row 2, Column 2 |</pre>
</div>
<div class="case" data-name="cell alignment">
<div class="input">
<table>
<thead>
<tr>
<th align="left">Column 1</th>
<th align="center">Column 2</th>
<th align="right">Column 3</th>
<th align="foo">Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
<td>Row 1, Column 3</td>
<td>Row 1, Column 4</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
<td>Row 2, Column 3</td>
<td>Row 2, Column 4</td>
</tr>
</tbody>
</table>
</div>
<pre class="expected">| Column 1 | Column 2 | Column 3 | Column 4 |
| :-- | :-: | --: | --- |
| Row 1, Column 1 | Row 1, Column 2 | Row 1, Column 3 | Row 1, Column 4 |
| Row 2, Column 1 | Row 2, Column 2 | Row 2, Column 3 | Row 2, Column 4 |</pre>
</div>
<div class="case" data-name="empty cells">
<div class="input">
<table>
<thead>
<tr>
<th align="left">Column 1</th>
<th align="center">Column 2</th>
<th align="right">Column 3</th>
<th align="foo">Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>Row 1, Column 2</td>
<td>Row 1, Column 3</td>
<td>Row 1, Column 4</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td></td>
<td>Row 2, Column 3</td>
<td>Row 2, Column 4</td>
</tr>
<tr>
<td>Row 3, Column 1</td>
<td>Row 3, Column 2</td>
<td></td>
<td>Row 3, Column 4</td>
</tr>
<tr>
<td>Row 4, Column 1</td>
<td>Row 4, Column 2</td>
<td>Row 4, Column 3</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td>Row 5, Column 4</td>
</tr>
</tbody>
</table>
</div>
<pre class="expected">| Column 1 | Column 2 | Column 3 | Column 4 |
| :-- | :-: | --: | --- |
| | Row 1, Column 2 | Row 1, Column 3 | Row 1, Column 4 |
| Row 2, Column 1 | | Row 2, Column 3 | Row 2, Column 4 |
| Row 3, Column 1 | Row 3, Column 2 | | Row 3, Column 4 |
| Row 4, Column 1 | Row 4, Column 2 | Row 4, Column 3 | |
| | | | Row 5, Column 4 |</pre>
</div>
<div class="case" data-name="empty rows">
<div class="input">
<table>
<tbody>
<tr>
<td>Row 1</td>
<td>Row 1</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Row 3</td>
<td>Row 3</td>
</tr>
</tbody>
</table>
</div>
<pre class="expected">| Row 1 | Row 1 |
| Row 3 | Row 3 |</pre>
</div>
<!-- /TEST CASES -->
<script src="turndown-plugin-gfm-test.browser.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
var Attendant = require('turndown-attendant')
var TurndownService = require('../../to-markdown/lib/turndown.cjs')
var gfm = require('../lib/turndown-plugin-gfm.cjs').gfm
var attendant = new Attendant({
file: __dirname + '/index.html',
TurndownService: TurndownService,
beforeEach: function (turndownService) {
turndownService.use(gfm)
}
})
attendant.run()