10000 Remove pragmas, rely on identifier instead by phpnode · Pull Request #2 · threepointone/markdown-in-js · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Remove pragmas, rely on identifier instead #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 21, 2016
Merged
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
8000 Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
markdown-in-js
---

zero-overhead markdown in your react components
zero-overhead markdown in your react components

usage
---

add `'markdown-in-js/babel'` to the `plugins` field of your babel config

```jsx
import markdown /* or `md` */ from 'markdown-in-js'
```jsx
import markdown from 'markdown-in-js'
// or
// var markdown = require('markdown-in-js')
// (You can use any identifier)

const App = () => markdown`
## This is some content.
You can write _markdown_ as you'd like.
## This is some content.
You can write _markdown_ as you'd like.

${ <span> interpolate more <Content/> </span> }

you can <i>inline *html*</i> or even <OtherComponents/>, wow

<div style=${{ fontWeight: 'bold' }}
className=${'some more styles'}
<div style=${{ fontWeight: 'bold' }}
className=${'some more styles'}
>
interpolate attributes as expected
</div>
`
```

- gets compiled to react elements via a babel plugin
- preserves interpolations
- preserves interpolations
- built with [commonmark](https://github.com/jgm/commonmark.js)
- optionally add [prismjs](http://prismjs.com/) for syntax highlighting of code blocks
- optionally add [prismjs](http://prismjs.com/) for syntax highlighting of code blocks

custom components
---

You can use custom components for markdown primitives like so -
You can use custom components for markdown primitives like so -
```jsx
import md from 'markdown-in-js'
import { MyHeading, MyLink } from './path/to/components'
Expand All @@ -46,24 +49,18 @@ const App = () => md({ h1: MyHeading, a: MyLink })`
`
```

pragma
running examples
---

To use a differently named function / variable, you can override the markdown pragma -
```jsx
// @markdown myMd
let myMd = require('markdown-in-js')({ h1: customHeader })
// ...
mMyd`# custom title`
```

Before running the examples for the first time you'll need to `npm run self-link`.
After that you can start webpack with `npm start`.

todo
---

- optionally no-wrap paragraphs
- optionally no-wrap paragraphs
- optionally return array of elements
- instructions for in-editor syntax highlighting
- precompile code blocks
- instructions for in-editor syntax highlighting
- precompile code blocks
- commonmark options
- tests!
6 changes: 3 additions & 3 deletions examples/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react'
import { render } from 'react-dom'

import md from '../src'
import md from 'markdown-in-js'

function log() {
console.log(this) //eslint-disable-line
return this
return this
}

const App = () => md({ h1: 'h2' })`
# title

This is some text <span style=${{ fontWeight: 'bold' }}> we _here_ </span>

This is more text. And some more. And more.
This is more text. And some more. And more.
\`\`\`jsx
let x = alpha
function xyz(){
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"babel.js"
],
"scripts": {
"self-link": "ln -s ../ ./node_modules/markdown-in-js",
"start": "webpack-dev-server --config examples/webpack.js",
"build": "babel src -d lib",
"prepublish": "npm run build"
Expand Down
135 changes: 91 additions & 44 deletions src/babel.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,105 @@
import { name as packageName } from '../package.json'

import * as babylon from 'babylon'

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

let CUSTOM_PRAGMA = ''

module.exports = {
visitor: {
Program(path) {
let possibles = path.parent.comments.map(x => x.value.trim()).filter(x => x.indexOf('@markdown') === 0)
if(possibles.length > 0) {
CUSTOM_PRAGMA = possibles[possibles.length -1].split(' ')[1]
}
else {
CUSTOM_PRAGMA = ''
}
},
TaggedTemplateExpression(path) {

let code = path.hub.file.code
let tagName = path.node.tag.name
if(path.node.tag.type === 'CallExpression') {
tagName = path.node.tag.callee.name
}
Program: {
enter(path) {
let libName
path.traverse({
ImportDeclaration(path) {
if (path.node.source.value === packageName) {
const specifiers = path.get('specifiers')
for (const specifier of specifiers) {
if (specifier.isImportDefaultSpecifier()) {
libName = specifier.node.local.name
break
}
else if (specifier.isImportSpecifier() && specifier.node.imported.name === 'default') {
libName = specifier.node.local.name
break
}
}
}
},
CallExpression(path) {
if (!path.get('callee').isIdentifier() || path.node.callee.name !== 'require') {
return
}
const args = path.get('arguments')
const arg = args[0]
if (!arg || !arg.isStringLiteral() || arg.node.value !== packageName) {
return
}
const parent = path.parentPath()
if (parent.isVariableDeclarator()) {
const id = parent.get('id')
if (id.isIdentifier()) {
libName = id.name
}
}
else if (parent.isAssignmentExpression()) {
const id = parent.get('left')
if (id.isIdentifier()) {
libName = id.name
}
}
}
})


if((CUSTOM_PRAGMA && tagName === CUSTOM_PRAGMA) || (!CUSTOM_PRAGMA && (tagName === 'markdown' || tagName === 'md'))) {
let reader = new commonmark.Parser()
let writer = new JSXRenderer()
let stubs = path.node.quasi.expressions.map(x => code.substring(x.start, x.end))
let stubCtx = stubs.reduce((o, stub, i) => (o['spur-' + i] = stub, o), {})
let ctr = 0
let strs = path.node.quasi.quasis.map(x => x.value.cooked)
let src = strs.reduce((arr, str, i) => {
arr.push(str)
if(i !== stubs.length) {
arr.push('spur-'+ctr++)
if (!libName) {
// the module is not required in this file.
return
}

path.traverse({
TaggedTemplateExpression(path) {

let code = path.hub.file.code
let tagName = path.node.tag.name
if(path.node.tag.type === 'CallExpression') {
tagName = path.node.tag.callee.name
}

if(tagName === libName) {
let reader = new commonmark.Parser()
let writer = new JSXRenderer()
let stubs = path.node.quasi.expressions.map(x => code.substring(x.start, x.end))
let stubCtx = stubs.reduce((o, stub, i) => (o['spur-' + i] = stub, o), {})
let ctr = 0
let strs = path.node.quasi.quasis.map(x => x.value.cooked)
let src = strs.reduce((arr, str, i) => {
arr.push(str)
if(i !== stubs.length) {
arr.push('spur-'+ctr++)
}
return arr
}, []).join('')
let parsed = reader.parse(src)
6D4E let intermediateSrc = writer.render(parsed)
// replace with stubs
let newSrc = 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) + ', ' :
''
}_m_ => <div className='_markdown_'>${newSrc}</div>)`, { plugins: [
'jsx', 'flow', 'doExpressions', 'objectRestSpread', 'decorators', 'classProperties',
'exportExtensions', 'asyncGenerators', 'functionBind', 'functionSent', 'dynamicImport' ]
})
path.replaceWith(transformed.program.body[0])
}
}
return arr
}, []).join('')
let parsed = reader.parse(src)
let intermediateSrc = writer.render(parsed)
// replace with stubs
let newSrc = 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) + ', ' :
''
}_m_ => <div className='_markdown_'>${newSrc}</div>)`, { plugins: [
'jsx', 'flow', 'doExpressions', 'objectRestSpread', 'decorators', 'classProperties',
'exportExtensions', 'asyncGenerators', 'functionBind', 'functionSent', 'dynamicImport' ]
})
path.replaceWith(transformed.program.body[0])
})
}
}
}

}
}

0