Skip to content

Instantly share code, notes, and snippets.

@duncanbeevers
Created January 26, 2014 01:58

Revisions

  1. duncanbeevers created this gist Jan 26, 2014.
    97 changes: 97 additions & 0 deletions Compiler.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,97 @@
    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
    16 changes: 16 additions & 0 deletions demo.jade
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    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)
    11 changes: 11 additions & 0 deletions demo.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    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})
    12 changes: 12 additions & 0 deletions main.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    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