olov / ng-annotate Goto Github PK
View Code? Open in Web Editor NEWAdd, remove and rebuild AngularJS dependency injection annotations
License: MIT License
Add, remove and rebuild AngularJS dependency injection annotations
License: MIT License
http://angular-ui.github.io/bootstrap/#/modal
$modal.open({
templateUrl: 'components/services/choose.html',
controller: function($scope) {
// ...
},
resolve: {
items: function(MyService) {
// ...
}
}
});
This can be done from a controller or ui-router's onEnter.
It looks like DI variables in invoice methods aren't getting transformed correctly.
The following
var app = angular.bootstrap(document.getElementById('app'), ['app'])
app.invoke(function(Foo) {})
Has no transformation. It should look like this:
var app = angular.bootstrap(document.getElementById('app'), ['app'])
app.invoke([ 'Foo', function(Foo) {} ])
controller is annotated correctly but the directive which is exported from the module is not.
there should be debug.ebDebugTool.$inject = ['$window']
after annotation, but none is present.
code before ng-annotate
var app;
(function (app) {
(function (debug) {
'use strict';
var Ctrl = (function () {
/**
* @ngInject
*/
function Ctrl($scope, $element, $attrs) {
this.$scope = $scope;
this.$element = $element;
this.$attrs = $attrs;
}
return Ctrl;
})();
/**
* @ngdoc directive
* @module lbbw.debug
* @name ebDebugTool
* @restrict E
*
* @description
*
* @usage
* ```html
* <!-- using element directive -->
* <eb-debug-tool></eb-debug-tool>
* ```
*
* @ngInject
*/
debug.ebDebugTool = function ($window) {
var linkFn = function (scope, element, attrs) {
console.log($window);
};
return {
restrict: 'E',
templateUrl: '_debug/debugTool.html',
controller: Ctrl,
controllerAs: 'ctrl',
link: linkFn
};
};
})(app.debug || (app.debug = {}));
var debug = app.debug;
})(app || (app= {}));
after ng-annotate:
var app;
(function (app) {
(function (debug) {
'use strict';
var Ctrl = (function () {
/**
* @ngInject
*/
function Ctrl($scope, $element, $attrs) {
this.$scope = $scope;
this.$element = $element;
this.$attrs = $attrs;
}
Ctrl.$inject = ['$scope','$element','$attrs'];
return Ctrl;
})();
/**
* @ngdoc directive
* @module lbbw.debug
* @name ebDebugTool
* @restrict E
*
* @description
*
* @usage
* ```html
* <!-- using element directive -->
* <eb-debug-tool></eb-debug-tool>
* ```
*
* @ngInject
*/
debug.ebDebugTool = function ($window) {
var linkFn = function (scope, element, attrs) {
console.log($window);
};
return {
restrict: 'E',
templateUrl: '_debug/debugTool.html',
controller: Ctrl,
controllerAs: 'ctrl',
link: linkFn
};
};
})(app.debug || (app.debug = {}));
var debug = app.debug;
})(app || (app= {}));
Is there a config option to use single quotes instead of double quotes?
Is there a way to change a given service name/reference through the examined source? Since AngularJS doesn't support namespacing when injecting instances and functions, I need to pre-process some libraries that conflict with each other.
Can plugins be used to achieve this?
Http interceptors are not annotated :-)
angular.module('myMod', [])
.config(function ($httpProvider) {
var interceptor = function ($rootScope, otherService) {
return {
'request': function (config) {
otherService.doSomething();
return config || $q.when(config);
}
};
};
$httpProvider.interceptors.push(interceptor);
});
It should output :
...
var interceptor = ['$rootScope', 'otherService', function ($rootScope, otherService) {
return {
'request': function (config) {
otherService.doSomething();
return config || $q.when(config);
}
};
}];
$httpProvider.interceptors.push(interceptor);
});
Would it be possible to support the following scenario?
angular.forEach([
"click",
"dblclick",
"mousedown",
"mouseup",
"mouseover",
"mouseout",
"mousemove",
"mouseenter",
"mouseleave",
"keydown",
"keyup",
"keypress",
"submit",
"focus",
"blur",
"copy",
"cut",
"paste"
], function (directiveName) {
angular.module("directives").directive(directiveName, function ($rootScope) {
//...
});
});
Currently, it appears that only a string may be specified as the first parameter to directive
in order for ng-annotate
to annotate it.
Haven't found a workaround for this one so far.
Consider the following (which is real world production code):
var optionsView = function (route) {
return {
template: "<options items='items' on-select='go(item)' chevrons='true'></options>",
//Annotated
controller: function ($scope, $state, navigation) {
}
};
};
var rootViews = {
"mainContainer_root.newsFeed.list": {
templateUrl: "newsFeed/newsFeed.html",
//Not annotated
controller: function ($scope, navigation) {
}
},
"mainContainer_root.settings": optionsView("root.settings")
};
$stateProvider
.state("root", {
abstract: true,
url: "",
views: rootViews
});
As you can see, only the first controller: function ()
gets annotated. The other one doesn't because I'm using a variable instead of directly using $stateProvider
(this is fine, I don't think ng-annotate
should deal with variables).
However, this poses a problem because I need to /*@ngInject */
only the second controller: function ()
; if I also /*@ngInject */
the first one, it gets annotated twice. I don't want developers to be thinking whether they should include /*@ngInject */
in their code, so I run grunt-text-replace
before grunt-ng-annotate
to pre-process some files. With this particular example I have to distinguish between both kind of controller: function ()
uses to only /*@ngInject */
the second one.
Looking at ng-annotate-main.js I found this:
function matchDirectiveReturnObject(node) {
// TODO make these more strict by checking that we're inside an angular module?
// return { .. controller: function($scope, $timeout), ...}
return node.type === "ReturnStatement" &&
node.argument && node.argument.type === "ObjectExpression" &&
matchProp("controller", node.argument.properties);
}
If that check were made, the first controller: function ()
wouldn't be annotated and I could just /*@ngInject */
every use of it in the file.
Or maybe /*@ngInject */
should only work on pieces of code which haven't already been annotated (which would also allow me to /*@ngInject */
every controller: function ()
).
Thanks!
I got a problem when using ng-annotate with the ui-router's controllerProvider in view (have not tested elsewhere). I think it would be useful to implement it in order to fully support ui-router.
Specific code:
.state('location.detail', {
url: "/{detailId:[0-9]+}/{type:location|device}_detail",
views: {
'content@': {
templateUrl: function ($stateParams) {
return 'location/location_detail_' + $stateParams.type + '.tpl.html';
},
controllerProvider: /* @ngInject */ function ($stateParams) {
return $stateParams.type.charAt(0).toUpperCase() + $stateParams.type.slice(1) + 'DetailCtrl';
}
}
}
Thanks!
when this
in provider gets renamed it won't match:
myApp.provider('foo', function() {
var fooProvider = this;
fooProvider.bar = 'aaa';
fooProvider.baz = function bar(bbb) {
bbb.ccc = fooProvider.bar;
}
fooProvider.$get = function (abc) {
...
}
});
This seems to be connected with node.left.object.type === "ThisExpression"
in
https://github.com/olov/ng-annotate/blob/master/ng-annotate-main.js#L26
Don't know if this is relevant: $ npm install -g ng-annotate
works fine, but npm install -g git://github.com/olov/ng-annotate.git#48e7fcb
throws an error:
npm ERR! Error: ENOENT, chmod '/usr/local/lib/node_modules/ng-annotate/build/es5/ng-annotate'
The only difference I can see is npm WARN excluding symbolic link build/defs-config.json -> ../defs-config.json
if I install 48e7fcb
.
(I used 48e7fcb
as it was the commit to the latest published version. The error occurs with other commit hashes, too. Maybe this is a minor problem, but it is problematic if you want to test bleeding edge versions.)
Hi,
firstly, thanks for this awesome tool ! :D
I'm trying to integrate Browserify in my development workflow. It works very well.
Now it's the time to automate some tasks with gulp and ng-annotate, and I have an issue with the minification task.
I structure my code exactly the same way from here : http://benclinkinbeard.com/talks/2014/ng-conf/ (slides 19 to 23)
The problem is that ng-annotate isn't working with this kind of structure, something like this isn't parsed properly :
// modules/app/frontend/login/login-index.js
'use strict';
module.exports = function($scope) {
$scope.name = 'guest';
};
The previous controller is called from here :
// modules/app/frontend/login/index.js
'use strict';
module.exports = angular.module('app.frontend.login', [])
.config(function($stateProvider) {
$stateProvider.state('login', {
url: '/login',
templateUrl: '/frontend/login/login-index.html',
controller: 'LoginCtrl'
});
})
.controller('LoginCtrl', require('./login-index'));
Is there a solution to make ng-annotate understands this kind of line ?
.controller('LoginCtrl', require('./login-index'));
Maybe I'm making something wrong. ^^'
This is great, glad to see such an improvement over ngmin.
One idea I had, which would pretty much allow user-level fixing of any false positives, would be to have a /* @ngNoInject */
annotation, which would disable automatic injection pretty much in the exact situations @ngInject
works.
To be clear: I am not having any issue, and this should be a very low priority enhancement, but it might be a nice feature.
The workaround is admittedly super easy (add an explicit .config
call), I just ran into this while migrating from ngmin and figured I'd submit a ticket.
https://docs.angularjs.org/api/ng/function/angular.module
In this example:
angular.module("foo", ["ngFoo"], function(FooService){
//...
});
The function doesn't get annotated.
Also great work on this project, switching from ngmin cut my compile time in half.
close this ... human error
ng-annotate lacks support for (inline) sourcemaps. Pointed here from gulp-ng-annotate: Kagami/gulp-ng-annotate#3
Nicest solution would be to update inline sourcemaps similar to autoprefixer: https://github.com/ai/autoprefixer#source-map ?
I've got a case where I create multiple directives as a combination of 2 parameters:
['foo', 'bar'].forEach(function (param1) {
['aaa', 'bbb'].forEach(function (param2) {
angular.module('utils')
.directive(param1 + param2, function ($timeout) {
return {
link: function () {},
};
});
});
});
This won't get annotated directly because of https://github.com/olov/ng-annotate/blob/master/ng-annotate-main.js#L221 which states only a node of type Literal
is considered a name and classifies the 2nd argument to get annotated.
BinaryExpression
(or even Identifier
) are not enough.
Off course using:
angular.module('utils').directive(param1 + param2, /*@ngInject*/ function ($timeout) {});
does the job, but I wonder if there is any way this could be omitted?
The only thing that comes to my mind is something like:
angular.module('utils').directive((param1 + param2).toString(), function ($timeout) {});
which makes the first argument possible to distinguish as a string by catching Identifier
with name of toString
.
I know .toString()
is not quite obvious and popular (primarily because it's not necessary when there are 2 strings concatenated to get a string) so I'm not convinced it's the best way such case can be covered.
Do you find it a good enough solution for a PR or should I stay with /*@ngInject*/
.
Or maybe you could think of some other way to support dynamic service names?
The following does not match:
angular
.injector(['fooModule'])
.invoke(function (barServiceInFooModule) {
});
I know it shouldn't be used that much and can be considered a bad practice, but it sometimes can be useful when used with care.
My use case is:
I have to define some callbacks, which will be called much later in config phase.
I have a pretty straight-forward file but the annotations result in Javascript errors.
My test case looks like the following:
angular.module( 'resolveApplicationRoute', [] ).provider( 'resolveApplicationRoute', function resolveApplicationRoute() {
this.configRouteResolve = function() {
return promiseRailsAuth
}
this.$get = promiseRailsAuth
// @ngInject
function promiseRailsAuth( $location, $q, Apis, Omniture, Router, Server, View ) {
console.log( $location, $q, Apis, Omniture, Router, Server, View )
}
} )
I compile this locally and get the following output:
angular.module( 'resolveApplicationRoute', [] ).provider( 'resolveApplicationRoute', function resolveApplicationRoute() {
this.configRouteResolve = function() {
return promiseRailsAuth
}
this.$get = promiseRailsAuth
// @ngInject
function promiseRailsAuth( $location, $q, Apis, Omniture, Router, Server, View ) {
console.log( $location, $q, Apis, Omniture, Router, Server, View )
}
promiseRailsAuth.$inject = ["$location", "$q", "Apis", "Omniture", "Router", "Server", "View"];
} )
;
This results in these console errors, which breaks the application:
We never use the .$inject
pattern in our un-annotated codebase, not sure what the best way to handle that is.
Either I am going mad, or the fn.$injects[...]
syntax generated by ng-annotate is actually supposed to be fn.$inject[...]
.
See: https://docs.angularjs.org/guide/di
So, when annotating something of the form...
/*@ngInject*/
function mainCtrl($scope) {
...
}
...ng-annotate generates...
/*@ngInject*/
function mainCtrl($scope) {
...
}
mainCtrl.$injects["$scope"];
...instead of
/*@ngInject*/
function mainCtrl($scope) {
...
}
mainCtrl.$inject["$scope"];
This is not an issue but just a question, I apologize in advanced if I have overlooked this, such as already in the documentation or reported another 'issue', as I haven't been able to locate anything yet.
Would this library be able to turn the code below into the following output. Basically I'm looking for a tool to assist in preparing my $scope methods and variables before minification with Closure Compiler. Currently I run CC in simple mode but I am looking to run it in advanced mode, which to be expected everything attached to $scope is renamed resulting in a completely broken application. I would like to find a tool that can change everything on $scope from dot notation to bracket notation.
Before ng-annotate:
var ngApp = angular.module('ngApp', []);
ngApp.controller('AController', function($scope) {
$scope.varOne = 'Test';
$scope.methodOne = function() {
};
});
After ng-annotate:
var ngApp = angular.module('ngApp', []);
ngApp.controller('AController', ["$scope", function($scope) {
$scope["varOne"] = "Test";
$scope["methodOne"] = function() {
};
}]);
So far all that I can find regarding AngularJS and minification seems to only speak about DI management, I've yet to see how to handle methods and variables that are tied to the actual HTML view via the $scope.
I've got a testing issue: some lines are added as \n
by ngAnnotate
, while others as \r\n
. Testing always fails on the first one:
--- with_annotations.js
+++ with_annotations.js
@@ -338,79 +338,79 @@
};
// @ngInject
function foo($scope) {
+}
-}
foo.$inject = ["$scope"];
continues
(full diff here)
Is it only failing to me?
We have some coffeescript that looks like this:
class MyThing
open: ->
$modal.open
templateUrl: "path/to/template.html"
controller: "SomeController"
resolve:
collection: (CollectionClass) => CollectionClass.query()
This compiles to something like:
MyThing.prototype.open = function() {
return $modal.open({
templateUrl: "path/to/template.html",
controller: "SomeController",
resolve: {
collection: (function(_this) {
return function(CollectionClass) {
return CollectionClass.query();
};
})(this)
}
});
};
The problem is that the CollectionClass
doesn't get annotated. In this example, coffeescript's "fat arrow" isn't needed. However, the general problem is that you can't use dependency injection on fat arrow anonymous functions.
I am using ng-annotate with the rails gem. I have run into an issue where my testing setup no longer works due to mocha file being modified. I am using mocha 1.17
The incorrect source transformation i have is
hook.run(function(err){
//...
being converted to
hook.run(["err", function(err){
//...
Since I use RequireJS for modules I usually do this:
define(function(require) {
require('app-module')
.controller('SomeCtrl', function($scope) { /* ... */ });
});
It doesn't work with ng-annotate, but it works if I do
define(function(require) {
var module = require('app-module')
module.controller('SomeCtrl', function($scope) { /* ... */ });
});
Can it be possible to support this kind of cases where the module is returned by a function?
Almost identical to @luckylooke's post here gulp-sourcemaps/gulp-sourcemaps#19
I have a gulp workflow that looks something like this
var pl = require('gulp-load-plugins')();
gulp.task('scripts', function() {
return gulp.src(watched.scripts)
.pipe(pl.sourcemaps.init())
.pipe(pl.concat('scripts.js'))
.pipe(pl.ngAnnotate())
.pipe(pl.uglify())
.pipe(pl.sourcemaps.write('.'))
.pipe(gulp.dest('./dist/scripts/'))
.pipe(pl.livereload());
});
In Chrome, the file referenced opposite a console.log() output in the web console is a different file to the one that it should be, and if I click it, I find the cursor at the bottom of that file. So, it doesn't appear to be pointing correctly? I have it working fine without ng-annotate.
ng-annotate: v0.9.9
gulp-ng-annotate: v0.3.0
Notice that the func extendExceptionHandler
gets injection even though it already had it. This causes an error because the 2nd parm was actually a shortened name (which is why i explicitly annotated it).
// already had this
extendExceptionHandler.$inject = ['$delegate', 'exceptionConfig', 'logger'];
/ ng-annotate added this
extendExceptionHandler.$inject = ['$delegate', 'exConfig', 'logger'];
This is the input
(function () {
'use strict';
angular
.module('blocks.exception')
.provider('exceptionConfig', exceptionConfigProvider)
.config(['$provide', exceptionConfig]);
function exceptionConfigProvider () {
this.config = {};
this.$get = function () {
return {
config: this.config
};
};
}
function exceptionConfig ($provide) {
$provide.decorator('$exceptionHandler', extendExceptionHandler);
}
extendExceptionHandler.$inject = ['$delegate', 'exceptionConfig', 'logger'];
function extendExceptionHandler($delegate, exConfig, logger) {
var appErrorPrefix = exConfig.config.appErrorPrefix || '';
return function (exception, cause) {
$delegate(exception, cause);
var errorData = { exception: exception, cause: cause };
var msg = appErrorPrefix + exception.message;
logger.error(msg, errorData);
};
}
})();
and this is the output
(function () {
'use strict';
angular
.module('blocks.exception')
.provider('exceptionConfig', exceptionConfigProvider)
.config(['$provide', exceptionConfig]);
function exceptionConfigProvider () {
this.config = {};
this.$get = function () {
return {
config: this.config
};
};
}
function exceptionConfig ($provide) {
$provide.decorator('$exceptionHandler', extendExceptionHandler);
}
extendExceptionHandler.$inject = ['$delegate', 'exceptionConfig', 'logger'];
function extendExceptionHandler($delegate, exConfig, logger) {
var appErrorPrefix = exConfig.config.appErrorPrefix || '';
return function (exception, cause) {
$delegate(exception, cause);
var errorData = { exception: exception, cause: cause };
var msg = appErrorPrefix + exception.message;
logger.error(msg, errorData);
};
}
extendExceptionHandler.$inject = ['$delegate', 'exConfig', 'logger'];
})();
ng-annotate did a fantastic job of annotating our app (very large and uses lots of different inject scenarios) but missed this one (I did a reduced test case with just the below code):
// declare main app
angular.module('app',[
// declare dependencies
], function($interpolateProvider) {
// change template echo tags due to use of Twig
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});
should become:
// declare main app
angular.module('app',[
// declare dependencies
], ['$interpolateProvider', function($interpolateProvider) {
// change template echo tags due to use of Twig
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
}]);
To fix manually you can add an /*@ngInject*/
comment (or use a separate config function) :
angular.module('app',[
// declare dependencies
], /*@ngInject*/ function($interpolateProvider) {
// change template echo tags due to use of Twig
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});
Hey, me again :)
We've just tested your recent changes (#40) and got another problem related to how CoffeeScript transforms sources.
Here's what happens: http://coffeescript.org/#try:%23%23%23%20%40ngInject%20%23%23%23%0Af%20%3D%20(%24scope)%20-%3E
For functions assignment expression CS generates 3 lines: var declaration, empty line, and the assignment itself. This isn't that stupid as actually CS collects all variables and hoists their declaration to the top of the scope. But in our case it breaks ngAnnotate which sees var
declaration in the next line.
Is it possible you add an option that'll tell ngAnnotate to scan for the first line that matches function assignment and ignore those in between that don't?
Switching from ng-min to ng-annotate breaks our applications. We often use variables in our component names, but ng-annotate doesn't catch them. For instance,
var componentName = 'BrokenCtrl',
module = angular.module('myApp.' + componentName, []);
module.controller(componentName, function ($scope) {
});
Reference point.
btford/ngmin#54 (comment)
Okey, tried to install ng-annotate:
> sudo npm update -g
> rm -fr node_modules/
> npm install ng-annotate
npm http GET https://registry.npmjs.org/ng-annotate
npm http 304 https://registry.npmjs.org/ng-annotate
npm http GET https://registry.npmjs.org/alter
npm http GET https://registry.npmjs.org/optimist
npm http GET https://registry.npmjs.org/simple-fmt
npm http GET https://registry.npmjs.org/ordered-ast-traverse
npm http GET https://registry.npmjs.org/simple-is
npm http GET https://registry.npmjs.org/priorityqueuejs
npm http GET https://registry.npmjs.org/tryor
npm http GET https://registry.npmjs.org/esprima
npm http 304 https://registry.npmjs.org/optimist
npm http 304 https://registry.npmjs.org/alter
npm http 304 https://registry.npmjs.org/simple-fmt
npm http 304 https://registry.npmjs.org/simple-is
npm http 304 https://registry.npmjs.org/ordered-ast-traverse
npm http 304 https://registry.npmjs.org/priorityqueuejs
npm http 304 https://registry.npmjs.org/tryor
npm http 304 https://registry.npmjs.org/esprima
npm http GET https://registry.npmjs.org/ordered-esprima-props
npm http GET https://registry.npmjs.org/stable
npm http 304 https://registry.npmjs.org/ordered-esprima-props
npm http 304 https://registry.npmjs.org/stable
npm ERR! Error: ENOENT, lstat '/home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/optimist/test/parse_modified.js'
npm ERR! If you need help, you may report this log at:
npm ERR! <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR! <[email protected]>
npm ERR! System Linux 3.11.10-7-desktop
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install" "ng-annotate"
npm ERR! cwd /home/kari/work/projects/ruby/external/ngannotate-rails
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.18
npm ERR! path /home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/optimist/test/parse_modified.js
npm ERR! fstream_path /home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/optimist/test/parse_modified.js
npm ERR! fstream_type File
npm ERR! fstream_class FileWriter
npm ERR! code ENOENT
npm ERR! errno 34
npm ERR! fstream_stack /usr/lib64/node_modules/npm/node_modules/fstream/lib/writer.js:284:26
npm ERR! fstream_stack Object.oncomplete (fs.js:107:15)
npm ERR! Error: ENOENT, lstat '/home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/esprima/esprima.js'
npm ERR! If you need help, you may report this log at:
npm ERR! <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR! <[email protected]>
npm ERR! System Linux 3.11.10-7-desktop
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install" "ng-annotate"
npm ERR! cwd /home/kari/work/projects/ruby/external/ngannotate-rails
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.18
npm ERR! path /home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/esprima/esprima.js
npm ERR! fstream_path /home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate/node_modules/esprima/esprima.js
npm ERR! fstream_type File
npm ERR! fstream_class FileWriter
npm ERR! code ENOENT
npm ERR! errno 34
npm ERR! fstream_stack /usr/lib64/node_modules/npm/node_modules/fstream/lib/writer.js:284:26
npm ERR! fstream_stack Object.oncomplete (fs.js:107:15)
npm ERR! error rolling back Error: ENOTEMPTY, rmdir '/home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate'
npm ERR! error rolling back [email protected] { [Error: ENOTEMPTY, rmdir '/home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate']
npm ERR! error rolling back errno: 53,
npm ERR! error rolling back code: 'ENOTEMPTY',
npm ERR! error rolling back path: '/home/kari/work/projects/ruby/external/ngannotate-rails/node_modules/ng-annotate' }
npm ERR! Error: No compatible version found: ordered-esprima-props@'^1.0.0'
npm ERR! Valid install targets:
npm ERR! ["1.0.0"]
npm ERR! at installTargetsError (/usr/lib64/node_modules/npm/lib/cache.js:685:10)
npm ERR! at /usr/lib64/node_modules/npm/lib/cache.js:607:10
npm ERR! at saved (/usr/lib64/node_modules/npm/node_modules/npm-registry-client/lib/get.js:138:7)
npm ERR! at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR! <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR! <[email protected]>
npm ERR! System Linux 3.11.10-7-desktop
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install" "ng-annotate"
npm ERR! cwd /home/kari/work/projects/ruby/external/ngannotate-rails
npm ERR! node -v v0.10.5
npm ERR! npm -v 1.2.18
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! /home/kari/work/projects/ruby/external/ngannotate-rails/npm-debug.log
npm ERR! not ok code 0
Any idea about that? Investigating...
A very common pattern is to create an alias for this
at the beginning of a provider definition (usually named self
) and then use that alias throughout the file.
Currently, ng-annotate
doesn't annotate $get
when set through an alias:
angular.module("providers").provider("myProvider", function () {
var self = this;
//Won't be annotated
self.$get = function ($rootScope) {
//...
};
});
Of course there is an easy workaround:
angular.module("providers").provider("myProvider", function () {
var self = this;
//Will be annotated
this.$get = function ($rootScope) {
//...
};
});
But it would be handy to be able to keep using self
.
I realize that supporting arbitrary alias for this
may increase the complexity of ng-annotate
, so I propose that only self
is supported given that it is the most common alias.
Hi - firstly, thanks for ng-annotate
- great work.
Secondly, per the README
I am requesting support for $injector.instantiate
, or at least raising the issue for debate.
The use case
In my application I am using CoffeeScript classes heavily. Even my service definitions are classes. Using extends
I can define a common base service class, and then use dependency injection to reference the base class in a concrete implementation.
By way of a pared down example:
angular.module('myApp').service 'A', ($injector, BaseServiceClass, AnotherClass) ->
class AService extends BaseServiceClass
constructor: (@$timeout, @$rootScope) ->
do_stuff: ->
return new AnotherClass
$injector.instantiate AService
Leaving out the boilerplate CoffeeScript function definitions for __extends
etc, this translates to:
angular.module('myApp').service('A', function($injector, BaseServiceClass, AnotherClass) {
var AService;
AService = (function(_super) {
__extends(AService, _super);
function AService($timeout, $rootScope) {
this.$timeout = $timeout;
this.$rootScope = $rootScope;
}
AService.prototype.do_stuff = function() {
return new AnotherClass;
};
return AService;
})(BaseServiceClass);
return $injector.instantiate(AService);
});
At this point I fear the title for this issue may be slightly misleading, because what really needs to be supported here is automatic detection of types that are instantiated by $injector.instantiate
. This may be a bridge too far....
I have a workaround, which is to annotate the constructors using block comments. Hence my example becomes:
angular.module('myApp').service 'A', ($injector, BaseServiceClass, AnotherClass) ->
class AService extends BaseServiceClass
###
@ngInject
###
constructor: (@$timeout, @$rootScope) ->
do_stuff: ->
return new AnotherClass
$injector.instantiate AService
Would support for $injector.instantiate
be feasible? Or am I left to annotate my constructors?
Thanks in advance.
Reduced from #62:
Input:
~/projects/ng-annotate % cat tests-issues/issue63.js
function outer() {
return {
controller: MyCtrl,
};
// @ngInject
function MyCtrl(a) {
}
}
Current output:
~/projects/ng-annotate % ./ng-annotate-harmony -a tests-issues/issue63.js
function outer() {
return {
controller: MyCtrl,
};
// @ngInject
function MyCtrl(a) {
}
MyCtrl.$inject = ["a"];
}
Expected output:
~/projects/ng-annotate % ./ng-annotate-harmony -a tests-issues/issue63.js
function outer() {
MyCtrl.$inject = ["a"];
return {
controller: MyCtrl,
};
// @ngInject
function MyCtrl(a) {
}
}
A common pattern a lot of Angular developers I know (myself included) utilise a pattern like this:
function SomeCtrl () {
}
angular
.module('app', [])
.controller('SomeCtrl', SomeCtrl);
Currently, to make this work we have to do:
// @ngInject
function SomeCtrl () {
}
angular
.module('app', [])
.controller('SomeCtrl', SomeCtrl);
What would the implications be for getting this working with ng-annotate
without using an /** @ngInject */
comment? As the method above becomes more popular, I think one of the main downsides to adoption are having to use the comment - is there a way ng-annotate
can lookup the function based on it's name based on the scope?
Hello,
The dependency injection replacement seems to work fine with most of the angular calls, but it's not replacing in providers
example :
angular.module('common').provider("dateService", function($serverDateFormat)
is left as it.
Using ES6 arrow functions causes parse errors in ng-annotate.
Running ng-annotate after transpilation is not possible due to Traceur removing comments, meaning explicit @ngAnnotate
markers go missing.
This works
/* @ngInject */
var f = function($scope) {
return $scope.x = 1;
};
While this doesn't:
var f;
/* @ngInject */
f = function($scope) {
return $scope.x = 1;
};
And consequently nor does this
/* @ngInject */
module.exports = function($scope) {
return $scope.x = 1;
};
We write our code in CoffeeScript and CS doesn't have inline comments. We organize our code with CommonJS (browserify), each controller, directive, etc. in separate file, then require
'd and attached to module. So currently unfortunately we can't make use of ngAnnotate, but we'd love to. If you make it work with function expression that doesn't start with var
that would help.
Similar to the Bootstrap modals, I have custom modal factories that accept a controller within the constructor. Eg:
return new Modal({
container: '.modal-container',
templateUrl: 'example.html',
controller: function ($scope, someService) {
// ...
}
});
This syntax is not currently handled by ng-annotate. In the interim I am able to use the explicit inject notation which works fine:
return new Modal({
container: '.modal-container',
templateUrl: 'example.html',
controller: /* @ngInject */ function ($scope, someService) {
// ...
}
});
Obviously it would be nice if this was handled by default. Not an urgent problem but as per your README you said feel free to open an issue so here I am :)
When a directive uses a controller and that controller needs // @ngInject
syntax it is not being caught when it is defined within the directive closure.
(function () {
'use strict';
angular
.module('app')
.directive('foo', foo);
/**
* @returns {Object} - Directive definition object
*/
function foo() {
return {
restrict: 'EA',
scope: true,
transclude: false,
templateUrl: 'foo.html',
controller: FooCtrl
};
/**
* @ngInject
*/
function FooCtrl($scope) {
var vm = $scope.bar = {
timeFormat: 'H:mma'
};
}
}
}());
Yet this does work when I moved the controller outside the directive.
(function () {
'use strict';
angular
.module('app')
.directive('foo', foo);
/**
* @returns {Object} - Directive definition object
*/
function foo() {
return {
restrict: 'EA',
scope: true,
transclude: false,
templateUrl: 'foo.html',
controller: FooCtrl
};
}
/**
* @ngInject
*/
function FooCtrl($scope) {
var vm = $scope.bar = {
timeFormat: 'H:mma'
};
}
}());
Does ng-annotate support source maps?
I would like to pass an exiting sourcemap (e.g. requireJS or coffeeScript) let ng-annotate alter the code and get out a new sourcemap which I can pass to https://github.com/gruntjs/grunt-contrib-uglify
Angular .config
blocks are not annotated with ng-annotate 0.4.0 which breaks apps using them. E.g. the following is not annotated:
(function () {
'use strict';
angular.module('cbnAnalytics', [
'angulartics',
'cbnAngularticsGoogleAnalytics',
])
.config(function ($analyticsProvider) {
$analyticsProvider.settings.pageTracking.basePath = window.settings.polonaUrl.slice(0, -1);
});
})();
Currently, this:
$urlRouterProvider.otherwise(function ($injector) {
//...
});
is being annotated into:
$urlRouterProvider.otherwise(["$injector", function ($injector) {
//...
}]);
But ui-router
expects a function:
this.otherwise =
function (rule) {
if (isString(rule)) {
var redirect = rule;
rule = function () { return redirect; };
}
else if (!isFunction(rule)) throw new Error("'rule' must be a function");
otherwise = rule;
return this;
};
and already passes $injector
as a parameter to otherwise
:
function update() {
function check(rule) {
var handled = rule($injector, $location);
if (handled) {
if (isString(handled)) $location.replace().url(handled);
return true;
}
return false;
}
var n=rules.length, i;
for (i=0; i<n; i++) {
if (check(rules[i])) return;
}
// always check otherwise last to allow dynamic updates to the set of rules
if (otherwise) check(otherwise);
}
I'm not being able to keep ng-annotate
from annotating this by using:
regexp: /^((?!otherwise).)*$/
I probably misunderstood the regexp
option, though.
Workaround:
var urlRouterProvider = $urlRouterProvider;
urlRouterProvider.otherwise(function ($injector) {
//...
});
You may add this into README.md.
* [Rails](http://rubyonrails.org/): [ngannotate-rails](https://rubygems.org/gems/ngannotate-rails) by [Kari Ikonen](https://github.com/kikonen)
Getting this now...
[boneskull@lectroid:~/projects/beanstalk]$ sudo npm install -g ng-annotate
npm http GET https://registry.npmjs.org/ng-annotate
npm http 304 https://registry.npmjs.org/ng-annotate
npm http GET https://registry.npmjs.org/ast-traverse
npm http GET https://registry.npmjs.org/alter
npm http GET https://registry.npmjs.org/simple-fmt
npm http GET https://registry.npmjs.org/simple-is
npm http GET https://registry.npmjs.org/tryor
npm http GET https://registry.npmjs.org/esprima
npm http GET https://registry.npmjs.org/optimist
npm http 304 https://registry.npmjs.org/simple-is
npm http 304 https://registry.npmjs.org/alter
npm http 304 https://registry.npmjs.org/ast-traverse
npm http 304 https://registry.npmjs.org/tryor
npm http 304 https://registry.npmjs.org/esprima
npm http 304 https://registry.npmjs.org/optimist
npm http 304 https://registry.npmjs.org/simple-fmt
npm http GET https://registry.npmjs.org/stable
npm http GET https://registry.npmjs.org/wordwrap
npm http GET https://registry.npmjs.org/minimist
npm http 304 https://registry.npmjs.org/stable
npm http 304 https://registry.npmjs.org/wordwrap
npm http 304 https://registry.npmjs.org/minimist
npm ERR! Error: ENOENT, chmod '/usr/local/lib/node_modules/ng-annotate/build/es5/ng-annotate'
npm ERR! If you need help, you may report this *entire* log,
npm ERR! including the npm and node versions, at:
npm ERR! <http://github.com/npm/npm/issues>
npm ERR! System Darwin 13.1.0
npm ERR! command "node" "/usr/local/bin/npm" "install" "-g" "ng-annotate"
npm ERR! cwd /Volumes/samara/projects/boneskull/beanstalk
npm ERR! node -v v0.10.26
npm ERR! npm -v 1.4.3
npm ERR! path /usr/local/lib/node_modules/ng-annotate/build/es5/ng-annotate
npm ERR! code ENOENT
npm ERR! errno 34
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! /Volumes/samara/projects/boneskull/beanstalk/npm-debug.log
npm ERR! not ok code 0
Obviously the build isn't happening, so it can't find the file to install.
This is a loose idea but I often add a service to dependencies of another one and then remove its uses but forget to remove the injection. Now, linters often have an option to report unused parameters of functions not only at the end of them, e.g. see:
http://eslint.org/docs/rules/no-unused-vars.html
with {"args": "all"}
but then I'd have lots of false positives since in case of event handlers, replace functions on strings etc. we're sometimes interested in a second parameter but the first still has to be there.
Since ng-annotate already figures out which functions need to be annotated, I wonder if it was possible to pass this info along in some ways so that it'd be possible to check for unused injections in outside projects.
Or maybe ng-annotate could do this checking on its own? It rarely makes sense to inject components that aren't used in the code after all...
Newest ng-annotate
converts this:
notesForCurrentPage = _.filter(notes, function (note) {
return note.page.uid === page.uid;
});
to this:
notesForCurrentPage = _.filter(notes, ["note", function (note) {
return note.page.uid === page.uid;
}]);
This code has nothing to do with Angular and breaks Lo-Dash.
I suspect the annotating algorithm became too aggressive recently.
In order to link states together, it is often useful to have named references to the states.
var state1Config = {
name: 'state1',
url: '/'
controller: function($scope) { ... }
};
var state2Config = {
name: 'state2',
parent: state1Config,
url: '/posts',
controller: function($scope) { ... }
};
$stateProvider.state(state1Config);
$stateProvider.state(state2Config);
How can I help ng-annotate recognize and augment these config objects? By the time the parser reaches the $stateProvider.state
calls, the relevant AssignmentExpression
or VariableDeclaration
has already passed.
ng-annotate 0.9.0 is missing a tag in the repository. All older versions are tagged.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.