From: Artemy Tregubenko Date: Fri, 9 May 2014 16:09:38 +0000 (+0200) Subject: added @ngInject support for inline functions X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=524a8a42a4c8d136a8f33739f8fea58ce78dd92c;p=UglifyJS.git added @ngInject support for inline functions --- diff --git a/lib/compress.js b/lib/compress.js index 7df66938..5d8e6d32 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -224,6 +224,17 @@ merge(Compressor.prototype, { return statements; function process_for_angular(statements) { + function has_inject(comment) { + return /@ngInject/.test(comment.value); + } + function make_arguments_names_list(func) { + return func.argnames.map(function(sym){ + return make_node(AST_String, sym, { value: sym.name }); + }); + } + function make_array(orig, elements) { + return make_node(AST_Array, orig, { elements: elements }); + } function make_injector(func, name) { return make_node(AST_SimpleStatement, func, { body: make_node(AST_Assign, func, { @@ -232,37 +243,56 @@ merge(Compressor.prototype, { expression: make_node(AST_SymbolRef, name, name), property: "$inject" }), - right: make_node(AST_Array, func, { - elements: func.argnames.map(function(sym){ - return make_node(AST_String, sym, { value: sym.name }); - }) - }) + right: make_array(func, make_arguments_names_list(func)) }) }); } + function check_expression(body) { + if (body && body.args) { + // if this is a function call check all of arguments passed + body.args.forEach(function(argument, index, array) { + var comments = argument.start.comments_before; + // if the argument is function preceded by @ngInject + if (argument instanceof AST_Lambda && comments.length && has_inject(comments[0])) { + // replace the function with an array of names of its parameters and function at the end + array[index] = make_array(argument, make_arguments_names_list(argument).concat(argument)); + } + }); + // if this is chained call check previous one recursively + if (body.expression && body.expression.expression) { + check_expression(body.expression.expression); + } + } + } return statements.reduce(function(a, stat){ a.push(stat); - var token = stat.start; - var comments = token.comments_before; - if (comments && comments.length > 0) { - var last = comments.pop(); - if (/@ngInject/.test(last.value)) { - // case 1: defun - if (stat instanceof AST_Defun) { - a.push(make_injector(stat, stat.name)); - } - else if (stat instanceof AST_Definitions) { - stat.definitions.forEach(function(def){ - if (def.value && def.value instanceof AST_Lambda) { - a.push(make_injector(def.value, def.name)); - } - }); - } - else { - compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token); + + if (stat.body && stat.body.args) { + check_expression(stat.body); + } else { + var token = stat.start; + var comments = token.comments_before; + if (comments && comments.length > 0) { + var last = comments.pop(); + if (has_inject(last)) { + // case 1: defun + if (stat instanceof AST_Defun) { + a.push(make_injector(stat, stat.name)); + } + else if (stat instanceof AST_Definitions) { + stat.definitions.forEach(function(def) { + if (def.value && def.value instanceof AST_Lambda) { + a.push(make_injector(def.value, def.name)); + } + }); + } + else { + compressor.warn("Unknown statement marked with @ngInject [{file}:{line},{col}]", token); + } } } } + return a; }, []); } diff --git a/test/compress/angular-inject.js b/test/compress/angular-inject.js new file mode 100644 index 00000000..1459361c --- /dev/null +++ b/test/compress/angular-inject.js @@ -0,0 +1,67 @@ +ng_inject_defun: { + options = { + angular: true + }; + input: { + /*@ngInject*/ + function Controller(dependency) { + return dependency; + } + } + expect: { + function Controller(dependency) { + return dependency; + } + Controller.$inject=['dependency'] + } +} + +ng_inject_assignment: { + options = { + angular: true + }; + input: { + /*@ngInject*/ + var Controller = function(dependency) { + return dependency; + } + } + expect: { + var Controller = function(dependency) { + return dependency; + } + Controller.$inject=['dependency'] + } +} + +ng_inject_inline: { + options = { + angular: true + }; + input: { + angular.module('a'). + factory('b', + /*@ngInject*/ + function(dependency) { + return dependency; + }). + directive('c', + /*@ngInject*/ + function(anotherDependency) { + return anotherDependency; + }) + } + expect: { + angular.module('a'). + factory('b',[ + 'dependency', + function(dependency) { + return dependency; + }]). + directive('c',[ + 'anotherDependency', + function(anotherDependency) { + return anotherDependency; + }]) + } +} \ No newline at end of file