|
var proxyIdentCounter = 0; |
|
|
|
// matches ast`anything here` |
|
var IDENTIFIER_NAME = "ast"; |
|
|
|
module.exports = function (babel) { |
|
|
|
var babelParse = require('babel-core').parse; |
|
|
|
// temporary |
|
require('babel-core/register'); |
|
|
|
var cleanAst = require('./cleanAst'); |
|
var t = babel.types; |
|
|
|
return new babel.Transformer("babel-ast-literal", { |
|
TaggedTemplateExpression: function(node, parent){ |
|
|
|
var proxyIdentCache = {}; |
|
function ProxyIdent(originalExpression){ |
|
this.originalExpression = originalExpression; |
|
this.proxyIdent = "__babel_ast_literal_proxyIdent__" + (++proxyIdentCounter); |
|
this.proxyIdentAst = t.identifier(this.proxyIdent); |
|
} |
|
|
|
ProxyIdent.prototype.cache = function(){ |
|
proxyIdentCache[this.proxyIdent] = this; |
|
}; |
|
|
|
if (!t.isIdentifier(node.tag, { name: IDENTIFIER_NAME })) { |
|
return node; |
|
} |
|
|
|
// not all that different from writing a tagged template literal |
|
// function at runtime |
|
// strings[0], expressions[0], ..., expressions[n-1], strings[n] |
|
var expressions = node.quasi.expressions; |
|
var strings = node.quasi.quasis; |
|
|
|
// this is a string of js code to be parsed by babel |
|
var raw = ""; |
|
|
|
var handleString = function(n){ |
|
// should it be .cooked? |
|
// https://github.com/babel/babel/blob/c4a491123e6dfcbc37e970028d9e5c3daa5c5af8/src/acorn/src/expression.js#L515 |
|
raw += n.value.raw; |
|
}; |
|
|
|
var handleExpression = function(n){ |
|
cleanAst(n); |
|
var proxy = new ProxyIdent(n); |
|
proxy.cache(); |
|
raw += proxy.proxyIdent; |
|
}; |
|
|
|
for (var i=0; i<expressions.length; i++) { |
|
handleString(strings[i]); |
|
handleExpression(expressions[i]); |
|
} |
|
|
|
handleString(strings[strings.length - 1]); |
|
var intermediateAst = babelParse('(' + raw + ')').body[0].expression; |
|
delete intermediateAst.parenthesizedExpression; |
|
|
|
// this is the weird part |
|
// we turn the ast for the code "{foo: bar}" |
|
// into the ast for {ObjectExpression: {...}} |
|
// basically it's babel.parse(JSON.stringify(babel.parse(source)) |
|
// but it gets better! we're also on the lookout for our proxy identifiers |
|
// which need to be replaced with their original ast |
|
function astToObjectLiteralAst(n){ |
|
// proxy idents |
|
var isIdent = t.isIdentifier(n) || t.isJSXIdentifier(n); |
|
if (isIdent && proxyIdentCache[n.name]) { |
|
console.error(proxyIdentCache[n.name].originalExpression); |
|
return proxyIdentCache[n.name].originalExpression; |
|
} |
|
|
|
if (typeof n !== "object" || n === null) { |
|
return t.literal(n); |
|
} else if (Array.isArray(n)) { |
|
return t.arrayExpression(n.map(astToObjectLiteralAst)); |
|
} |
|
|
|
return t.objectExpression(Object.keys(n).map(function(key){ |
|
if (key === 'start' || key === 'end') return; |
|
|
|
var value = n[key]; |
|
|
|
return t.property( |
|
'init', |
|
t.identifier(key), |
|
astToObjectLiteralAst(value) |
|
); |
|
}).filter(Boolean)); |
|
} |
|
|
|
return astToObjectLiteralAst(intermediateAst); |
|
} |
|
}); |
|
}; |