added @ngInject support for inline functions

This commit is contained in:
Artemy Tregubenko
2014-05-09 18:09:38 +02:00
parent c3087dd179
commit 524a8a42a4
2 changed files with 120 additions and 23 deletions

View File

@@ -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;
}, []);
}

67
test/compress/angular-inject.js vendored Normal file
View File

@@ -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;
}])
}
}