Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ function log() {
return this
}

const App = () => md({ h1: 'h2' })`
const App = () => md({
h1: 'h2',
th: ({ children, style }) =>
<th style={{ ...style, fontWeight: 'bold' }}>{children}</th>
})`
# title

This is some text <span style=${{ fontWeight: 'bold' }}> we _here_ </span>
Expand Down Expand Up @@ -43,6 +47,21 @@ This is an H2
## This is an H2

###### This is an H6

Table

| Left-aligned | Center-aligned | Right-aligned |
| :--- | :---: | ---: |
| git status | git status | git status |
| git diff | git diff | git diff |

Table without pipes

Markdown | Less | Pretty
--- | --- | ---
*Still* | \`renders\` | **nicely**
1 | <span style=${{ fontWeight: 'bold' }}>2</span> | 3

`::log()


Expand Down
8 changes: 5 additions & 3 deletions src/babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as babylon from 'babylon'

import commonmark from 'commonmark'
import JSXRenderer from './jsx'

import { replaceTablesWithHTML, replaceTableStubs } from './table'

module.exports = {
visitor: {
Expand Down Expand Up @@ -81,10 +81,12 @@ module.exports = {
}
return arr
}, []).join('')
let parsed = reader.parse(src)
let parsed = reader.parse(replaceTablesWithHTML(src))
let intermediateSrc = writer.render(parsed)
// replace with stubs
let newSrc = intermediateSrc.replace(/spur\-[0-9]+/gm, x => `{${stubCtx[x]}}`)
let newSrc = replaceTableStubs(
intermediateSrc.replace(/spur\-[0-9]+/gm, x => `{${stubCtx[x]}}`)
)
let transformed = babylon.parse(`${tagName}(${
path.node.tag.type === 'CallExpression' ?
code.substring(path.node.tag.arguments[0].start, path.node.tag.arguments[0].end) + ', ' :
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const markdown = (o, fn) => {
'br': 'br', 'a': 'a', 'img': 'img', 'em': 'em', 'strong': 'strong', 'p': 'p',
'h1': 'h1', 'h2': 'h2', 'h3': 'h3', 'h4': 'h4', 'h5': 'h5', 'h6': 'h6',
'code': 'code', 'pre': 'pre', 'hr': 'hr', 'blockquote': 'blockquote',
'ul': 'ul', 'ol': 'ol', 'li': 'li', ...o
'ul': 'ul', 'ol': 'ol', 'li': 'li', 'table': 'table', 'thead': 'thead',
'tbody': 'tbody', 'tr': 'tr', 'td': 'td', 'th': 'th', ...o
})
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/jsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ export default class JSXRenderer extends Renderer {
paragraph(node, entering) {
let grandparent = node.parent.parent
, attrs = this.attrs(node)

if (node.firstChild &&
node.firstChild.literal &&
node.firstChild.literal.match('spur-element-table')) {
return
}
if (grandparent !== null &&
grandparent.type === 'list') {
if (grandparent.listTight) {
Expand Down
10 changes: 10 additions & 0 deletions src/table/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { re, parseTable, parseNpTable } from './parser'
import render from './renderer'

export const replaceTablesWithHTML = src => src
.replace(re.table, (match, ...capture) => render(parseTable(...capture)))
.replace(re.nptable, (match, ...capture) => render(parseNpTable(...capture)))

export const replaceTableStubs = src => src
.replace(/spur\-element\-([a-zA-Z])/gm, (x, element) => `_m_.${element}`)
.replace(/spur\-align\-(left|right|center)/gm, (x, align) => `style={{textAlign: '${align}'}}`)
64 changes: 64 additions & 0 deletions src/table/parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* marked - a markdown parser
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/

export const re = {
nptable: / *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/g,
table: / *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/g
}

export const parseTable = (header, align, cells) => {
const item = {
header: header.replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: align.replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cells.replace(/(?: *\| *)?\n$/, '').split('\n')
}

for (let i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right'
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center'
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left'
} else {
item.align[i] = null
}
}

for (let i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i]
.replace(/^ *\| *| *\| *$/g, '')
.split(/ *\| */)
}

return item
}

export const parseNpTable = (header, align, cells) => {
const item = {
header: header.replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: align.replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cells.replace(/\n$/, '').split('\n')
}

for (let i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right'
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center'
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left'
} else {
item.align[i] = null
}
}

for (let i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i].split(/ *\| */)
}

return item
}
44 changes: 44 additions & 0 deletions src/table/renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Create cell element with alignment
//
// The `align` attribute isn't valid, even though some markdown renderers use it.
// We can't use a style object prior to markdown parsing, and we can't use a
// style string in React. Instead, place a stub for alignment and swap after
// markdown parsing.
const renderCell = (type, align, value) => {
if (align) {
return `<spur-element-${type} spur-align-${align}>${value}</spur-element-${type}>`
} else {
return `<spur-element-${type}>${value}</spur-element-${type}>`
}
}

// Render gfm table markdown to HTML
//
// Use placeholder elements so that we can replace with _m_.element. We can't
// use _m_ directly here, since it isn't a valid HTML tag and will get encoded
// during markdown parsing
export default ({ header, align, cells }) => {
let str = ''

str += '<spur-element-table>'
str += '<spur-element-thead>'
str += '<spur-element-tr>'
str += header.map((value, i) => renderCell('th', align[i], value)).join('')
str += '</spur-element-tr>'
str += '</spur-element-thead>'
str += '<spur-element-tbody>'

for (let i = 0; i < cells.length; i++) {
str += '<spur-element-tr>'
str += cells[i].map((value, j) => renderCell('td', align[j], value)).join('')
str += '</spur-element-tr>'
}

str += '</spur-element-tbody>'
str += '</spur-element-table>'

// Keep table in a separate block from subsequent markdown
str += '\n\n'

return str
}