Created
December 13, 2013 00:12
-
-
Save cameronism/7937945 to your computer and use it in GitHub Desktop.
Uglify files and inline keys in gettext calls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var UglifyJS = require("uglify-js"); | |
| var fs = require('fs'); | |
| var defineName = 'define', | |
| getTextModule = 'shared/gettext', | |
| currentGetTextName, | |
| stringDefinitions, | |
| placeholders, | |
| stringKeys, | |
| moduleName; | |
| function getStringNode(node) { | |
| if (node instanceof UglifyJS.AST_String) { | |
| return node; | |
| } | |
| var value = node.name && stringDefinitions[node.name]; | |
| if (value) { | |
| return value; | |
| } | |
| console.error(JSON.stringify(node, null, 2)); | |
| throw new Error("Unknown string type"); | |
| } | |
| function resetState() { | |
| moduleName = currentGetTextName = null; | |
| stringDefinitions = {}; | |
| placeholders = []; | |
| stringKeys = []; | |
| } | |
| function getPlaceholderString(node) { | |
| var placeholder = new UglifyJS.AST_String({ value: 'KEY PLACEHOLDER' }); | |
| placeholders.push(placeholder); | |
| stringKeys.push({ node: node, module: moduleName }); | |
| return placeholder; | |
| } | |
| function before(node, descend) { | |
| if (node instanceof UglifyJS.AST_Call && | |
| node.expression.name == defineName && | |
| node.args.length >= 2) { | |
| var defineStarted = false, | |
| previousModuleName = moduleName, | |
| localModuleName, | |
| previousGetTextName = currentGetTextName, | |
| dependencies, | |
| names; | |
| if (node.args.length >= 3 && | |
| node.args[0] instanceof UglifyJS.AST_String && | |
| node.args[1] instanceof UglifyJS.AST_Array && | |
| node.args[2] instanceof UglifyJS.AST_Function) { | |
| localModuleName = node.args[0].value; | |
| dependencies = node.args[1].elements; | |
| names = node.args[2].argnames; | |
| } else if (node.args[0] instanceof UglifyJS.AST_Array && | |
| node.args[1] instanceof UglifyJS.AST_Function) { | |
| dependencies = node.args[0].elements; | |
| names = node.args[1].argnames; | |
| } | |
| if (dependencies && names) { | |
| for (var i = 0; i < dependencies.length; i++) { | |
| if (dependencies[i] instanceof UglifyJS.AST_String && | |
| dependencies[i].value.toLowerCase() == getTextModule && | |
| names.length > i) { | |
| currentGetTextName = names[i].name; | |
| defineStarted = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (defineStarted) { | |
| if (localModuleName) { | |
| moduleName = localModuleName; | |
| } | |
| descend(node, this); | |
| currentGetTextName = previousGetTextName; | |
| if (localModuleName) { | |
| moduleName = previousModuleName; | |
| } | |
| return node; | |
| } | |
| } | |
| else if (node instanceof UglifyJS.AST_VarDef && | |
| node.value && | |
| node.value instanceof UglifyJS.AST_String) { | |
| // TODO support shadowing | |
| stringDefinitions[node.name.name] = node.value; | |
| descend(node, this); | |
| return node; | |
| } | |
| } | |
| function after(node) { | |
| if (node instanceof UglifyJS.AST_Call && | |
| node.args.length > 0 && | |
| node.expression.name && | |
| node.expression.name == currentGetTextName) { | |
| var stringNode = getStringNode(node.args[0]), | |
| placeholder = getPlaceholderString(stringNode); | |
| node.args.unshift(placeholder); | |
| return node; | |
| } | |
| } | |
| var getTextWalker = new UglifyJS.TreeTransformer(before, after); | |
| function processFileSync(file, keyCreator, astPrintOptions) { | |
| resetState(); | |
| var code = fs.readFileSync(file); | |
| var ast = UglifyJS.parse(String(code), { filename: file, toplevel: null }); | |
| ast = ast.transform(getTextWalker); | |
| var keys = keyCreator(file, stringKeys); | |
| placeholders.forEach(function(placeholder, ix) { | |
| placeholder.value = keys[ix]; | |
| }); | |
| // compressor needs figure_out_scope too | |
| ast.figure_out_scope(); | |
| var compressor = UglifyJS.Compressor({ pure_getters: true }) | |
| ast = ast.transform(compressor); | |
| // need to figure out scope again so mangler works optimally | |
| ast.figure_out_scope(); | |
| ast.compute_char_frequency(); | |
| ast.mangle_names(); | |
| return ast.print_to_string(astPrintOptions || {}); | |
| } | |
| var argv, | |
| exampleKeyCreator; | |
| // process files specified on command line if run directly | |
| if (require.main === module) { | |
| argv = process.argv.slice(2); | |
| exampleKeyCreator = function(filename, nodes) { | |
| return nodes.map(function(node) { | |
| return 'success - ' + (node.module || filename) + ' - ' + node.node.value; | |
| }); | |
| } | |
| if (argv.length == 0) { | |
| argv = ['something.js']; | |
| } | |
| argv.forEach(function(file) { | |
| console.log('// ' + file); | |
| console.log(processFileSync(file, exampleKeyCreator, { beautify: true })); | |
| }); | |
| } | |
| module.exports.processFileSync = processFileSync; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment