From a9f2e6d83efcb999d726543fdfea59bb6d543b08 Mon Sep 17 00:00:00 2001 From: chee Date: Tue, 29 Jan 2019 11:53:40 +0000 Subject: [PATCH] Add replacements for Polar Bear markup language --- src/bear-style-code-block.js | 21 ++++ src/bear-style-todo.js | 33 +++++++ src/bold.js | 8 ++ src/gfm.js | 15 --- ...de-block.js => github-style-code-block.js} | 10 +- src/github-style-todo.js | 16 +++ src/italic.js | 8 ++ src/line-separator.js | 8 ++ src/mark.js | 8 ++ src/polar-bear.js | 39 ++++++++ src/strikethrough.js | 2 +- src/tables.js | 97 ------------------- src/task-list-items.js | 10 -- src/underline.js | 8 ++ 14 files changed, 155 insertions(+), 128 deletions(-) create mode 100644 src/bear-style-code-block.js create mode 100644 src/bear-style-todo.js create mode 100644 src/bold.js delete mode 100644 src/gfm.js rename src/{highlighted-code-block.js => github-style-code-block.js} (67%) create mode 100644 src/github-style-todo.js create mode 100644 src/italic.js create mode 100644 src/line-separator.js create mode 100644 src/mark.js create mode 100644 src/polar-bear.js delete mode 100644 src/tables.js delete mode 100644 src/task-list-items.js create mode 100644 src/underline.js diff --git a/src/bear-style-code-block.js b/src/bear-style-code-block.js new file mode 100644 index 0000000..cb207e3 --- /dev/null +++ b/src/bear-style-code-block.js @@ -0,0 +1,21 @@ +export default function bearStyleCodeBlock (turndownService) { + turndownService.addRule('bearStyleCodeBlock', { + filter: function (node) { + let child = node.firstChild + return ( + node.nodeName === 'PRE' && + child && + child.nodeName === 'CODE' && + child.classList.contains('code-multiline') + ) + }, + replacement: function (content, node, options) { + let child = node.firstChild + return ( + '\n```' + child.lang + '\n' + + child.textContent + + '\n' + '```\n' + ) + } + }) +} diff --git a/src/bear-style-todo.js b/src/bear-style-todo.js new file mode 100644 index 0000000..cb23a0c --- /dev/null +++ b/src/bear-style-todo.js @@ -0,0 +1,33 @@ +function selectTodoCheckbox (node) { + return node.firstElementChild +} + +function selectTodoText (node) { + return node.firstElementChild && node.firstElementChild.nextElementSibling +} + +export default function todo (turndownService) { + turndownService.addRule('todo', { + filter: function (node) { + var todoCheckboxElement = selectTodoCheckbox(node) + var todoTextElement = selectTodoText(node) + + return node.nodeName === 'LI' && + todoCheckboxElement && + todoTextElement && + todoCheckboxElement.classList.contains('todo-checkbox') && + todoTextElement.classList.contains('todo-text') + }, + replacement: function (content, node) { + var checked = selectTodoCheckbox(node) + .classList + .contains('todo-checked') + + return ( + checked + ? '+ ' + : '- ' + ) + content + } + }) +} diff --git a/src/bold.js b/src/bold.js new file mode 100644 index 0000000..9f9d5e1 --- /dev/null +++ b/src/bold.js @@ -0,0 +1,8 @@ +export default function bold (turndownService) { + turndownService.addRule('bold', { + filter: ['b', 'strong'], + replacement: function (content) { + return '*' + content + '*' + } + }) +} diff --git a/src/gfm.js b/src/gfm.js deleted file mode 100644 index 69d25b4..0000000 --- a/src/gfm.js +++ /dev/null @@ -1,15 +0,0 @@ -import highlightedCodeBlock from './highlighted-code-block' -import strikethrough from './strikethrough' -import tables from './tables' -import taskListItems from './task-list-items' - -function gfm (turndownService) { - turndownService.use([ - highlightedCodeBlock, - strikethrough, - tables, - taskListItems - ]) -} - -export { gfm, highlightedCodeBlock, strikethrough, tables, taskListItems } diff --git a/src/highlighted-code-block.js b/src/github-style-code-block.js similarity index 67% rename from src/highlighted-code-block.js rename to src/github-style-code-block.js index 97052de..287e3b8 100644 --- a/src/highlighted-code-block.js +++ b/src/github-style-code-block.js @@ -1,7 +1,7 @@ var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/ -export default function highlightedCodeBlock (turndownService) { - turndownService.addRule('highlightedCodeBlock', { +export default function githubStyleCodeBlock (turndownService) { + turndownService.addRule('githubStyleCodeBlock', { filter: function (node) { var firstChild = node.firstChild return ( @@ -16,9 +16,9 @@ export default function highlightedCodeBlock (turndownService) { var language = (className.match(highlightRegExp) || [null, ''])[1] return ( - '\n\n' + options.fence + language + '\n' + - node.firstChild.textContent + - '\n' + options.fence + '\n\n' + '\n```' + language + '\n' + + node.firstChild.textContent + + '\n' + '```\n' ) } }) diff --git a/src/github-style-todo.js b/src/github-style-todo.js new file mode 100644 index 0000000..4d1bbe0 --- /dev/null +++ b/src/github-style-todo.js @@ -0,0 +1,16 @@ +export default function todo (turndownService) { + turndownService.addRule('todo', { + filter: function (node) { + return node.nodeName === 'LI' && + node.firstChild && + node.firstChild.type === 'checkbox' + }, + replacement: function (content, node) { + return ( + node.firstChild.checked + ? '+ ' + : '- ' + ) + content + } + }) +} diff --git a/src/italic.js b/src/italic.js new file mode 100644 index 0000000..80cbf3e --- /dev/null +++ b/src/italic.js @@ -0,0 +1,8 @@ +export default function italic (turndownService) { + turndownService.addRule('italic', { + filter: ['i', 'em'], + replacement: function (content) { + return '/' + content + '/' + } + }) +} diff --git a/src/line-separator.js b/src/line-separator.js new file mode 100644 index 0000000..b7b1e04 --- /dev/null +++ b/src/line-separator.js @@ -0,0 +1,8 @@ +export default function lineSeparator (turndownService) { + turndownService.addRule('lineSeparator', { + filter: ['hr'], + replacement: function () { + return '---' + } + }) +} diff --git a/src/mark.js b/src/mark.js new file mode 100644 index 0000000..be79033 --- /dev/null +++ b/src/mark.js @@ -0,0 +1,8 @@ +export default function mark (turndownService) { + turndownService.addRule('mark', { + filter: ['mark'], + replacement: function (content) { + return '::' + content + '::' + } + }) +} diff --git a/src/polar-bear.js b/src/polar-bear.js new file mode 100644 index 0000000..854de7e --- /dev/null +++ b/src/polar-bear.js @@ -0,0 +1,39 @@ +import bearStyleCodeBlock from './bear-style-code-block' +import bearStyleTodo from './bear-style-todo' +import bold from './bold' +import githubStyleCodeBlock from './github-style-code-block' +import githubStyleTodo from './github-style-todo' +import lineSeparator from './line-separator' +import italic from './italic' +import mark from './mark' +import strikethrough from './strikethrough' +import underline from './underline' + +function bear (turndownService) { + turndownService.use([ + bearStyleCodeBlock, + bearStyleTodo, + bold, + githubStyleCodeBlock, + githubStyleTodo, + italic, + lineSeparator, + mark, + strikethrough, + underline + ]) +} + +export { + bear, + bearStyleCodeBlock, + bearStyleTodo, + bold, + githubStyleCodeBlock, + githubStyleTodo, + italic, + lineSeparator, + mark, + strikethrough, + underline +} diff --git a/src/strikethrough.js b/src/strikethrough.js index 5cbe40d..b3d9727 100644 --- a/src/strikethrough.js +++ b/src/strikethrough.js @@ -2,7 +2,7 @@ export default function strikethrough (turndownService) { turndownService.addRule('strikethrough', { filter: ['del', 's', 'strike'], replacement: function (content) { - return '~' + content + '~' + return '-' + content + '-' } }) } diff --git a/src/tables.js b/src/tables.js deleted file mode 100644 index e4fd987..0000000 --- a/src/tables.js +++ /dev/null @@ -1,97 +0,0 @@ -var indexOf = Array.prototype.indexOf -var every = Array.prototype.every -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 (isHeadingRow(node)) { - for (var i = 0; i < node.childNodes.length; i++) { - var border = '---' - var align = ( - node.childNodes[i].getAttribute('align') || '' - ).toLowerCase() - - if (align) border = alignMap[align] || border - - borderCells += cell(border, node.childNodes[i]) - } - } - return '\n' + content + (borderCells ? '\n' + borderCells : '') - } -} - -rules.table = { - // Only convert tables with a heading row. - // Tables with no heading row are kept using `keep` (see below). - filter: function (node) { - return node.nodeName === 'TABLE' && isHeadingRow(node.rows[0]) - }, - - 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 - } -} - -// A tr is a heading row if: -// - the parent is a THEAD -// - or if its the first child of the TABLE or the first TBODY (possibly -// following a blank THEAD) -// - and every cell is a TH -function isHeadingRow (tr) { - var parentNode = tr.parentNode - return ( - parentNode.nodeName === 'THEAD' || - ( - parentNode.firstChild === tr && - (parentNode.nodeName === 'TABLE' || isFirstTbody(parentNode)) && - every.call(tr.childNodes, function (n) { return n.nodeName === 'TH' }) - ) - ) -} - -function isFirstTbody (element) { - var previousSibling = element.previousSibling - return ( - element.nodeName === 'TBODY' && ( - !previousSibling || - ( - previousSibling.nodeName === 'THEAD' && - /^\s*$/i.test(previousSibling.textContent) - ) - ) - ) -} - -function cell (content, node) { - var index = indexOf.call(node.parentNode.childNodes, node) - var prefix = ' ' - if (index === 0) prefix = '| ' - return prefix + content + ' |' -} - -export default function tables (turndownService) { - turndownService.keep(function (node) { - return node.nodeName === 'TABLE' && !isHeadingRow(node.rows[0]) - }) - for (var key in rules) turndownService.addRule(key, rules[key]) -} diff --git a/src/task-list-items.js b/src/task-list-items.js deleted file mode 100644 index 55d4b85..0000000 --- a/src/task-list-items.js +++ /dev/null @@ -1,10 +0,0 @@ -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]' : '[ ]') + ' ' - } - }) -} diff --git a/src/underline.js b/src/underline.js new file mode 100644 index 0000000..bbd5594 --- /dev/null +++ b/src/underline.js @@ -0,0 +1,8 @@ +export default function underline (turndownService) { + turndownService.addRule('underline', { + filter: ['u'], + replacement: function (content) { + return '_' + content + '_' + } + }) +}