Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@duncanbeevers
Created January 26, 2014 01:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duncanbeevers/8626980 to your computer and use it in GitHub Desktop.
Save duncanbeevers/8626980 to your computer and use it in GitHub Desktop.
Jade to React.DOM compiler
isConstant = require('constantinople')
toConstant = require('constantinople').toConstant
Compiler = (node, options) ->
compile: ->
visitTag = (tag) ->
buffer('React.DOM.' + tag.name + '(')
visitAttributes(tag.attrs, tag.attributeBlocks)
visitArgs(tag)
buffer(')')
visitArgs = (node) ->
len = node.block.nodes.length
if node.code || len
buffer(', ')
if node.code
visitCode(node.code)
for node, i in node.block.nodes
visit(node)
if i + 1 < len
buffer(' + ')
visitBlock = (block) ->
len = block.nodes.length
for node, i in block.nodes
visit(node)
if i + 1 < len
buffer(' + \n')
visitAttributes = (attrs, attributeBlocks) ->
if attrs && attrs.length
visited = {}
gatheredClassNames = []
normalized = {}
for attr in attrs
name = attr.name
val = attr.val
if 'class' != name && visited[name]
throw new Error('Duplicate key ' + JSON.stringify(name) + ' is not allowed.')
visited[name] = true
if 'class' == name
gatheredClassNames.push val
else
normalized[name] = val
if visited['class']
constantClassNames = []
dynamicClassNames = []
for className in gatheredClassNames
if isConstant(className)
constantClassNames.push toConstant(className)
else
dynamicClassNames.push className
classNames = []
if constantClassNames.length
classNames.push JSON.stringify(constantClassNames.join(' '))
normalized['class'] = classNames.concat(dynamicClassNames).join(' + " " + ')
pairs = []
for name, val of normalized
pairs.push(JSON.stringify(name) + ':' + val)
buffer('{' + pairs.join(',') + '}')
else
buffer('null')
visitCode = (code) ->
return unless code
buffer(code.val)
visitText = (node) ->
buffer(JSON.stringify(node.val))
visitNodes =
Text: visitText
Tag: visitTag
Block: visitBlock
parts = []
buffer = (str) -> parts.push(str)
visit = (node) -> visitNodes[node.type](node)
visit(node)
toPush = (part) ->
'buf.push(' + JSON.stringify(part)+ ');'
parts.map(toPush).join('\n')
module.exports = Compiler
div.first
.second
a(href="static")
a(href=dynamic)
p Static Content
p= dynamicContent
p
| Text
p
| Multiline Text 1
| Multiline Text 2
ul
li List Item
li= dynamicListItem
div.staticClass1(class="staticClass2")
div.staticClass1(class=dynamicClass2)
React.DOM.div({"class":"first"}) +
React.DOM.div({"class":"second"}) +
React.DOM.a({"href":"static"}) +
React.DOM.a({"href":dynamic}) +
React.DOM.p(null, "Static Content") +
React.DOM.p(null, dynamicContent) +
React.DOM.p(null, "Text") +
React.DOM.p(null, "Multiline Text 1" + "Multiline Text 2") +
React.DOM.ul(null, React.DOM.li(null, "List Item") + React.DOM.li(null, dynamicListItem)) +
React.DOM.div({"class":"staticClass1 staticClass2"}) +
React.DOM.div({"class":"staticClass1" + " " + dynamicClass2})
jade = require('jade')
Compiler = require('./compiler')
module.exports =
compile: (contents, opt={}) ->
contents = String contents # for fs buffers
src = String jade.render contents,
filename: opt.filename
compiler: Compiler
return src
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment