remove_development_transform.coffeesrc/tools/build/ | |
|---|---|
uglify = require 'uglify-js'
MAP = uglify.uglify.MAP
REMOVE_NODE = {}
exports.removeDevelopment = (ast, DEVELOPER_NAMESPACE = 'developer') ->
removalWalker = uglify.uglify.ast_walker()
cleanupWalker = uglify.uglify.ast_walker()
ast = removalWalker.with_walkers | |
| Remove all calls to developer.* | call: (expr, args) ->
[op, upon, fn] = expr
if upon
[key, objectName] = upon
if objectName == DEVELOPER_NAMESPACE
return REMOVE_NODE
['call', removalWalker.walk(expr), MAP(args, removalWalker.walk)] |
| Remove all assignments to developer or developer.* | assign: (_, lvalue, rvalue) ->
if rvalue.length
if rvalue[0] is 'name' and rvalue[1] is DEVELOPER_NAMESPACE
return REMOVE_NODE
if lvalue.length
[op, upon] = lvalue
switch op
when 'dot', 'sub'
[op, [key, objectName], fn] = lvalue
if objectName == DEVELOPER_NAMESPACE
return REMOVE_NODE
when 'name'
if upon == DEVELOPER_NAMESPACE
return REMOVE_NODE
['assign', _, removalWalker.walk(lvalue), removalWalker.walk(rvalue)] |
| Remove all var developer declarations, or assignments of developer to another variable. | var: (defs) ->
defs = defs.filter ([name, val]) -> |
|
| if name is DEVELOPER_NAMESPACE || |
|
| (val && val[0] is 'name' && val[1] is DEVELOPER_NAMESPACE) || |
|
| (val && val[0] in ['dot', 'sub'] && val[1].length && val[1][1] is DEVELOPER_NAMESPACE) |
| Don't allow this statement | false
else |
| Otherwise just pass it through | true
["var", defs]
, ->
removalWalker.walk ast
clean = (statements) ->
return null unless statements?
statements.filter (node) ->
switch node[0] |
| Ensure statements or assignments using developer are removed | when "stat", "assign"
node[node.length - 1] != REMOVE_NODE |
| Ensure now-empty sequences of var statements are removed | when "var"
node[1].length != 0 |
| Ensure returning of developer statements are removed | when "return"
node[1] != REMOVE_NODE
else
true
cleanLambdaBody = (name, args, body) ->
[this[0], name, args, MAP(clean(body), cleanupWalker.walk)]
cleanBlock = (statements) ->
[this[0], MAP(clean(statements), cleanupWalker.walk)]
cleanupWalker.with_walkers
toplevel: (body) -> return ["toplevel", MAP(clean(body), cleanupWalker.walk)]
function: cleanLambdaBody
defun: cleanLambdaBody
block: cleanBlock
splice: cleanBlock
try: (statements, catchBlock, finallyBlock) ->
[@[0], MAP(clean(statements), cleanupWalker.walk),
if catchBlock then [catchBlock[0], MAP(clean(catchBlock[1]), cleanupWalker.walk)] else catchBlock,
if finallyBlock then MAP(clean(finallyBlock), cleanupWalker.walk)]
switch: (expr, body) ->
[@[0], cleanupWalker.walk(expr), MAP(clean(body), (branch) ->
[ (if branch[0] then cleanupWalker.walk(branch[0]) else null), MAP(clean(branch[1]), cleanupWalker.walk) ]
) ]
, ->
cleanupWalker.walk ast
|