Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ng-annotate

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ng-annotate - npm Package Compare versions

Comparing version 0.8.0 to 0.9.0

build/es5/heap.js

166

build/es5/ng-annotate-main.js

@@ -9,3 +9,5 @@ // ng-annotate-main.js

var alter = require("alter");
var traverse = require("ast-traverse");
var traverse = require("ordered-ast-traverse");
var Heap = require("./heap");
var ngInjectComments = require("./nginject-comments");

@@ -17,3 +19,3 @@ var chainedRouteProvider = 1;

function match(node, re) {
function match(node, re, matchPlugins) {
var isMethodCall = (

@@ -26,5 +28,6 @@ node.type === "CallExpression" &&

var matchMethodCalls = (isMethodCall &&
(matchRegular(node, re) || matchNgRoute(node) || matchUiRouter(node)));
(matchRegular(node, re) || matchNgRoute(node) || matchUiRouter(node) || matchHttpProvider(node)));
return matchMethodCalls ||
(matchPlugins && matchPlugins(node)) ||
matchDirectiveReturnObject(node) ||

@@ -35,2 +38,4 @@ matchProviderGet(node);

function matchDirectiveReturnObject(node) {
// TODO make these more strict by checking that we're inside an angular module?
// return { .. controller: function($scope, $timeout), ...}

@@ -44,7 +49,12 @@

function matchProviderGet(node) {
// this.$get = function($scope, $timeout)
// TODO make these more strict by checking that we're inside an angular module?
// (this|self|that).$get = function($scope, $timeout)
// { ... $get: function($scope, $timeout), ...}
return (node.type === "AssignmentExpression" && node.left.type === "MemberExpression" &&
node.left.object.type === "ThisExpression" && node.left.property.name === "$get" && node.right) ||
var memberExpr;
var self;
return (node.type === "AssignmentExpression" && (memberExpr = node.left).type === "MemberExpression" &&
memberExpr.property.name === "$get" &&
((self = memberExpr.object).type === "ThisExpression" || (self.type === "Identifier" && is.someof(self.name, ["self", "that"]))) &&
node.right) ||
(node.type === "ObjectExpression" && matchProp("$get", node.properties));

@@ -105,3 +115,3 @@ }

//
// $urlRouterProvider.when_otherwise_rule(.., function($scope) {})
// $urlRouterProvider.when(.., function($scope) {})

@@ -111,8 +121,13 @@ // we already know that node is a (non-computed) method call

var obj = callee.object; // identifier or expression
var method = callee.property; // identifier
var args = node.arguments;
// special shortcut for $urlRouterProvider.*(.., function($scope) {})
if ((obj.$chained === chainedUrlRouterProvider || (obj.type === "Identifier" && obj.name === "$urlRouterProvider")) && args.length >= 1) {
// special shortcut for $urlRouterProvider.when(.., function($scope) {})
if (obj.$chained === chainedUrlRouterProvider || (obj.type === "Identifier" && obj.name === "$urlRouterProvider")) {
node.$chained = chainedUrlRouterProvider;
return last(args);
if (method.name === "when" && args.length >= 1) {
return last(args);
}
return false;
}

@@ -126,3 +141,2 @@

var method = callee.property; // identifier
if (method.name !== "state") {

@@ -170,2 +184,17 @@ return false;

function matchHttpProvider(node) {
// $httpProvider.interceptors.push(function($scope) {});
// $httpProvider.responseInterceptors.push(function($scope) {});
// we already know that node is a (non-computed) method call
var callee = node.callee;
var obj = callee.object; // identifier or expression
var method = callee.property; // identifier
return (method.name === "push" &&
obj.type === "MemberExpression" && !obj.computed &&
obj.object.name === "$httpProvider" && is.someof(obj.property.name, ["interceptors", "responseInterceptors"]) &&
node.arguments.length >= 1 && node.arguments);
}
function matchRegular(node, re) {

@@ -178,3 +207,3 @@ // we already know that node is a (non-computed) method call

var matchAngularModule = (obj.$chained === chainedRegular || isShortDef(obj, re) || isMediumDef(obj, re) || isLongDef(obj)) &&
is.someof(method.name, ["provider", "value", "constant", "config", "factory", "directive", "filter", "run", "controller", "service", "decorator", "animation"]);
is.someof(method.name, ["provider", "value", "constant", "bootstrap", "config", "factory", "directive", "filter", "run", "controller", "service", "decorator", "animation"]);
if (!matchAngularModule) {

@@ -185,3 +214,3 @@ return false;

if (is.someof(method.name, ["value", "constant"])) {
if (is.someof(method.name, ["value", "constant", "bootstrap"])) {
return false; // affects matchAngularModule because of chaining

@@ -193,3 +222,3 @@ }

args.length === 1 && args[0] :
args.length === 2 && args[0].type === "Literal" && is.string(args[0].value) && args[1]);
args.length === 2 && ((args[0].type === "Literal" && is.string(args[0].value)) || args[0].type === "Identifier") && args[1]);
}

@@ -204,3 +233,3 @@

function isMediumDef(node, re) {
if (node.type === "MemberExpression" && is.object(node.object) && is.object(node.property) && is.string(node.object.name) && is.string(node.property.name)) {
if (node.type === "MemberExpression" && is.string(node.object.name) && is.string(node.property.name)) {
return (!re || re.test(node.object.name + "." + node.property.name));

@@ -293,8 +322,28 @@ }

function replaceRemoveOrInsertArrayForTarget(target, ctx) {
var mode = ctx.mode;
var fragments = ctx.fragments;
var quot = ctx.quot;
if (mode === "rebuild" && isAnnotatedArray(target)) {
replaceArray(target, fragments, quot);
} else if (mode === "remove" && isAnnotatedArray(target)) {
removeArray(target, fragments);
} else if (is.someof(mode, ["add", "rebuild"]) && isFunctionExpressionWithArgs(target)) {
insertArray(target, fragments, quot);
} else {
return false;
}
return true;
}
function isAnnotatedArray(node) {
return node.type === "ArrayExpression" && node.elements.length >= 1 && last(node.elements).type === "FunctionExpression";
}
function isFunctionWithArgs(node) {
function isFunctionExpressionWithArgs(node) {
return node.type === "FunctionExpression" && node.params.length >= 1;
}
function isFunctionDeclarationWithArgs(node) {
return node.type === "FunctionDeclaration" && node.params.length >= 1;
}

@@ -312,10 +361,75 @@ module.exports = function ngAnnotate(src, options) {

var re = (options.regexp && new RegExp(options.regexp));
var ast = esprima(src, {
range: true,
var ast;
try {
ast = esprima(src, {
range: true,
comment: true,
});
} catch(e) {
return {
errors: ["error: couldn't process source due to parse error", e.message],
};
}
// Fix Program node range (https://code.google.com/p/esprima/issues/detail?id=541)
ast.range[0] = 0;
// append a dummy-node to ast to catch any remaining triggers
ast.body.push({
type: "DebuggerStatement",
range: [ast.range[1], ast.range[1]],
});
// detach comments from ast
// [{type: "Block"|"Line", value: str, range: [from,to]}, ..]
var comments = ast.comments;
ast.comments = null;
// all source modifications are built up as operations in the
// fragments array, later sent to alter in one shot
var fragments = [];
traverse(ast, {post: function(node) {
var targets = match(node, re);
// triggers contains functions to trigger when traverse hits the
// first node at (or after) a certain pos
var triggers = new Heap();
var ctx = {
mode: mode,
quot: quot,
src: src,
comments: comments,
fragments: fragments,
triggers: triggers,
isFunctionExpressionWithArgs: isFunctionExpressionWithArgs,
isFunctionDeclarationWithArgs: isFunctionDeclarationWithArgs,
isAnnotatedArray: isAnnotatedArray,
replaceRemoveOrInsertArrayForTarget: replaceRemoveOrInsertArrayForTarget,
stringify: stringify,
};
var plugins = options.plugin || [];
function matchPlugins(node, isMethodCall) {
for (var i = 0; i < plugins.length; i++) {
var res = plugins[i].match(node, isMethodCall);
if (res) {
return res;
}
}
return false;
}
var matchPluginsOrNull = (plugins.length === 0 ? null : matchPlugins);
ngInjectComments.init(ctx);
plugins.forEach(function(plugin) {
plugin.init(ctx);
});
traverse(ast, {pre: function(node) {
var pos = node.range[0];
while (pos >= triggers.pos) {
var trigger = triggers.getAndRemoveNext();
trigger.fn.call(null, node, trigger.ctx);
}
}, post: function(node) {
var targets = match(node, re, matchPluginsOrNull);
if (!targets) {

@@ -328,11 +442,5 @@ return;

// TODO add something to know that node has been altered so it won't happen again
for (var i = 0; i < targets.length; i++) {
var target = targets[i];
if (mode === "rebuild" && isAnnotatedArray(target)) {
replaceArray(target, fragments, quot);
} else if (mode === "remove" && isAnnotatedArray(target)) {
removeArray(target, fragments);
} else if (is.someof(mode, ["add", "rebuild"]) && isFunctionWithArgs(target)) {
insertArray(target, fragments, quot);
}
replaceRemoveOrInsertArrayForTarget(targets[i], ctx);
}

@@ -339,0 +447,0 @@ }});

@@ -10,3 +10,3 @@ // ng-annotate.js

var ngAnnotate = require("./ng-annotate-main");
var version = "0.8.0";
var version = "0.9.0";
var optimist = require("optimist")

@@ -30,2 +30,5 @@ .usage("ng-annotate v" + version + "\n\nUsage: ng-annotate OPTIONS file.js")

describe: "detect short form myMod.controller(...) iff myMod matches regexp",
})
.options("plugin", {
describe: "use plugin with path (experimental)",
});

@@ -73,8 +76,24 @@

["add", "remove", "regexp", "single_quotes"].forEach(addOption);
["add", "remove", "regexp", "single_quotes", "plugin"].forEach(addOption);
if (config.plugin) {
if (!Array.isArray(config.plugin)) {
config.plugin = [config.plugin];
}
config.plugin = config.plugin.map(function(path) {
var absPath = tryor(fs.realpathSync.bind(fs, path), null);
if (!absPath) {
exit(fmt('error: plugin file not found {0}', path));
}
// the require below may throw an exception on parse-error
// that is fine because it gives the user the line info
return require(absPath);
});
}
var ret = ngAnnotate(src, config);
if (ret.errors) {
exit(ret.errors.join("\n"));
process.stderr.write(ret.errors.join("\n") + "\n");
process.exit(1);
}

@@ -81,0 +100,0 @@

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, function($scope, $timeout) {});
angular.module("MyMod").controller(ctrlName, function($scope, $timeout) {});
// object property

@@ -76,2 +80,5 @@ var myObj = {};

};
self.$get = function($scope) {};
that.$get = function($scope) {};
ignore.$get = function($scope) {};
});

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(function($scope) { a });
$httpProvider.responseInterceptors.push(function($scope) { a }, function(a, b) { b }, function() { c });
var interceptor = /*@ngInject*/ function($scope) { a };
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,34 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", function($match) { a; });
$urlRouterProvider.otherwise("", function($location) { a; });
$urlRouterProvider.rule(function($location) { a; });
$urlRouterProvider.anythingreally(function($location) { a; }).chained(function($location) { a; });
$urlRouterProvider.when("/", function($match) { a; });
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", function($location) { a; });
// explicit annotations
var x = /* @ngInject */ function($scope) {
};
var obj = {};
obj.bar = /*@ngInject*/ function($scope) {};
obj = {
controller: /*@ngInject*/ function($scope) {},
};
// @ngInject
function foo($scope) {
}
// @ngInject
// otherstuff
function Foo($scope) {
}
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, ['$scope', '$timeout', function($scope, $timeout) {}]);
angular.module("MyMod").controller(ctrlName, ['$scope', '$timeout', function($scope, $timeout) {}]);
// object property

@@ -76,2 +80,5 @@ var myObj = {};

}];
self.$get = ['$scope', function($scope) {}];
that.$get = ['$scope', function($scope) {}];
ignore.$get = function($scope) {};
}]);

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(['$scope', function($scope) { a }]);
$httpProvider.responseInterceptors.push(['$scope', function($scope) { a }], ['a', 'b', function(a, b) { b }], function() { c });
var interceptor = /*@ngInject*/ ['$scope', function($scope) { a }];
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,38 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", ['$match', function($match) { a; }]);
$urlRouterProvider.otherwise("", ['$location', function($location) { a; }]);
$urlRouterProvider.rule(['$location', function($location) { a; }]);
$urlRouterProvider.anythingreally(['$location', function($location) { a; }]).chained(['$location', function($location) { a; }]);
$urlRouterProvider.when("/", ['$match', function($match) { a; }]);
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", ['$location', function($location) { a; }]);
// explicit annotations
var x = /* @ngInject */ ['$scope', function($scope) {
}];
var obj = {};
obj.bar = /*@ngInject*/ ['$scope', function($scope) {}];
obj = {
controller: /*@ngInject*/ ['$scope', function($scope) {}],
};
// @ngInject
function foo($scope) {
}
foo.$injects = ['$scope'];
// @ngInject
// otherstuff
function Foo($scope) {
}
Foo.$injects = ['$scope'];
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
foo.$injects = ['$scope'];
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}
foo.$injects = ['$scope'];

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, ["$scope", "$timeout", function($scope, $timeout) {}]);
angular.module("MyMod").controller(ctrlName, ["$scope", "$timeout", function($scope, $timeout) {}]);
// object property

@@ -76,2 +80,5 @@ var myObj = {};

}];
self.$get = ["$scope", function($scope) {}];
that.$get = ["$scope", function($scope) {}];
ignore.$get = function($scope) {};
}]);

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(["$scope", function($scope) { a }]);
$httpProvider.responseInterceptors.push(["$scope", function($scope) { a }], ["a", "b", function(a, b) { b }], function() { c });
var interceptor = /*@ngInject*/ ["$scope", function($scope) { a }];
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,38 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", ["$match", function($match) { a; }]);
$urlRouterProvider.otherwise("", ["$location", function($location) { a; }]);
$urlRouterProvider.rule(["$location", function($location) { a; }]);
$urlRouterProvider.anythingreally(["$location", function($location) { a; }]).chained(["$location", function($location) { a; }]);
$urlRouterProvider.when("/", ["$match", function($match) { a; }]);
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", ["$location", function($location) { a; }]);
// explicit annotations
var x = /* @ngInject */ ["$scope", function($scope) {
}];
var obj = {};
obj.bar = /*@ngInject*/ ["$scope", function($scope) {}];
obj = {
controller: /*@ngInject*/ ["$scope", function($scope) {}],
};
// @ngInject
function foo($scope) {
}
foo.$injects = ["$scope"];
// @ngInject
// otherstuff
function Foo($scope) {
}
Foo.$injects = ["$scope"];
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
foo.$injects = ["$scope"];
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}
foo.$injects = ["$scope"];

@@ -0,1 +1,13 @@

## v0.9.0 2014-05-13
* explicit annotations using /* @ngInject */
* --plugin option to load user plugins (experimental, 0.9.x may change API)
* match $httpProvider.interceptors.push(function($scope) {})
* match $httpProvider.responseInterceptors.push(function($scope) {})
* match self and that as aliases to this for this.$get = function($scope){}
* match .controller(name, ..) in addition to .controller("name", ..)
* bugfix ui-router declarations
* bugfix angular.module("MyMod").bootstrap(e, [], {}) disrupting chaining
* even faster (~6% faster annotating angular.js)
* add error array to API return object
## v0.8.0 2014-05-09

@@ -2,0 +14,0 @@ * ngRoute support: $routeProvider.when("path", { .. })

@@ -9,3 +9,5 @@ // ng-annotate-main.js

const alter = require("alter");
const traverse = require("ast-traverse");
const traverse = require("ordered-ast-traverse");
const Heap = require("./heap");
const ngInjectComments = require("./nginject-comments");

@@ -17,3 +19,3 @@ const chainedRouteProvider = 1;

function match(node, re) {
function match(node, re, matchPlugins) {
const isMethodCall = (

@@ -26,5 +28,6 @@ node.type === "CallExpression" &&

const matchMethodCalls = (isMethodCall &&
(matchRegular(node, re) || matchNgRoute(node) || matchUiRouter(node)));
(matchRegular(node, re) || matchNgRoute(node) || matchUiRouter(node) || matchHttpProvider(node)));
return matchMethodCalls ||
(matchPlugins && matchPlugins(node)) ||
matchDirectiveReturnObject(node) ||

@@ -35,2 +38,4 @@ matchProviderGet(node);

function matchDirectiveReturnObject(node) {
// TODO make these more strict by checking that we're inside an angular module?
// return { .. controller: function($scope, $timeout), ...}

@@ -44,7 +49,12 @@

function matchProviderGet(node) {
// this.$get = function($scope, $timeout)
// TODO make these more strict by checking that we're inside an angular module?
// (this|self|that).$get = function($scope, $timeout)
// { ... $get: function($scope, $timeout), ...}
return (node.type === "AssignmentExpression" && node.left.type === "MemberExpression" &&
node.left.object.type === "ThisExpression" && node.left.property.name === "$get" && node.right) ||
let memberExpr;
let self;
return (node.type === "AssignmentExpression" && (memberExpr = node.left).type === "MemberExpression" &&
memberExpr.property.name === "$get" &&
((self = memberExpr.object).type === "ThisExpression" || (self.type === "Identifier" && is.someof(self.name, ["self", "that"]))) &&
node.right) ||
(node.type === "ObjectExpression" && matchProp("$get", node.properties));

@@ -105,3 +115,3 @@ }

//
// $urlRouterProvider.when_otherwise_rule(.., function($scope) {})
// $urlRouterProvider.when(.., function($scope) {})

@@ -111,8 +121,13 @@ // we already know that node is a (non-computed) method call

const obj = callee.object; // identifier or expression
const method = callee.property; // identifier
const args = node.arguments;
// special shortcut for $urlRouterProvider.*(.., function($scope) {})
if ((obj.$chained === chainedUrlRouterProvider || (obj.type === "Identifier" && obj.name === "$urlRouterProvider")) && args.length >= 1) {
// special shortcut for $urlRouterProvider.when(.., function($scope) {})
if (obj.$chained === chainedUrlRouterProvider || (obj.type === "Identifier" && obj.name === "$urlRouterProvider")) {
node.$chained = chainedUrlRouterProvider;
return last(args);
if (method.name === "when" && args.length >= 1) {
return last(args);
}
return false;
}

@@ -126,3 +141,2 @@

const method = callee.property; // identifier
if (method.name !== "state") {

@@ -170,2 +184,17 @@ return false;

function matchHttpProvider(node) {
// $httpProvider.interceptors.push(function($scope) {});
// $httpProvider.responseInterceptors.push(function($scope) {});
// we already know that node is a (non-computed) method call
const callee = node.callee;
const obj = callee.object; // identifier or expression
const method = callee.property; // identifier
return (method.name === "push" &&
obj.type === "MemberExpression" && !obj.computed &&
obj.object.name === "$httpProvider" && is.someof(obj.property.name, ["interceptors", "responseInterceptors"]) &&
node.arguments.length >= 1 && node.arguments);
}
function matchRegular(node, re) {

@@ -178,3 +207,3 @@ // we already know that node is a (non-computed) method call

const matchAngularModule = (obj.$chained === chainedRegular || isShortDef(obj, re) || isMediumDef(obj, re) || isLongDef(obj)) &&
is.someof(method.name, ["provider", "value", "constant", "config", "factory", "directive", "filter", "run", "controller", "service", "decorator", "animation"]);
is.someof(method.name, ["provider", "value", "constant", "bootstrap", "config", "factory", "directive", "filter", "run", "controller", "service", "decorator", "animation"]);
if (!matchAngularModule) {

@@ -185,3 +214,3 @@ return false;

if (is.someof(method.name, ["value", "constant"])) {
if (is.someof(method.name, ["value", "constant", "bootstrap"])) {
return false; // affects matchAngularModule because of chaining

@@ -193,3 +222,3 @@ }

args.length === 1 && args[0] :
args.length === 2 && args[0].type === "Literal" && is.string(args[0].value) && args[1]);
args.length === 2 && ((args[0].type === "Literal" && is.string(args[0].value)) || args[0].type === "Identifier") && args[1]);
}

@@ -204,3 +233,3 @@

function isMediumDef(node, re) {
if (node.type === "MemberExpression" && is.object(node.object) && is.object(node.property) && is.string(node.object.name) && is.string(node.property.name)) {
if (node.type === "MemberExpression" && is.string(node.object.name) && is.string(node.property.name)) {
return (!re || re.test(node.object.name + "." + node.property.name));

@@ -293,8 +322,28 @@ }

function replaceRemoveOrInsertArrayForTarget(target, ctx) {
const mode = ctx.mode;
const fragments = ctx.fragments;
const quot = ctx.quot;
if (mode === "rebuild" && isAnnotatedArray(target)) {
replaceArray(target, fragments, quot);
} else if (mode === "remove" && isAnnotatedArray(target)) {
removeArray(target, fragments);
} else if (is.someof(mode, ["add", "rebuild"]) && isFunctionExpressionWithArgs(target)) {
insertArray(target, fragments, quot);
} else {
return false;
}
return true;
}
function isAnnotatedArray(node) {
return node.type === "ArrayExpression" && node.elements.length >= 1 && last(node.elements).type === "FunctionExpression";
}
function isFunctionWithArgs(node) {
function isFunctionExpressionWithArgs(node) {
return node.type === "FunctionExpression" && node.params.length >= 1;
}
function isFunctionDeclarationWithArgs(node) {
return node.type === "FunctionDeclaration" && node.params.length >= 1;
}

@@ -312,10 +361,75 @@ module.exports = function ngAnnotate(src, options) {

const re = (options.regexp && new RegExp(options.regexp));
const ast = esprima(src, {
range: true,
let ast;
try {
ast = esprima(src, {
range: true,
comment: true,
});
} catch(e) {
return {
errors: ["error: couldn't process source due to parse error", e.message],
};
}
// Fix Program node range (https://code.google.com/p/esprima/issues/detail?id=541)
ast.range[0] = 0;
// append a dummy-node to ast to catch any remaining triggers
ast.body.push({
type: "DebuggerStatement",
range: [ast.range[1], ast.range[1]],
});
// detach comments from ast
// [{type: "Block"|"Line", value: str, range: [from,to]}, ..]
const comments = ast.comments;
ast.comments = null;
// all source modifications are built up as operations in the
// fragments array, later sent to alter in one shot
const fragments = [];
traverse(ast, {post: function(node) {
let targets = match(node, re);
// triggers contains functions to trigger when traverse hits the
// first node at (or after) a certain pos
const triggers = new Heap();
const ctx = {
mode: mode,
quot: quot,
src: src,
comments: comments,
fragments: fragments,
triggers: triggers,
isFunctionExpressionWithArgs: isFunctionExpressionWithArgs,
isFunctionDeclarationWithArgs: isFunctionDeclarationWithArgs,
isAnnotatedArray: isAnnotatedArray,
replaceRemoveOrInsertArrayForTarget: replaceRemoveOrInsertArrayForTarget,
stringify: stringify,
};
const plugins = options.plugin || [];
function matchPlugins(node, isMethodCall) {
for (let i = 0; i < plugins.length; i++) {
const res = plugins[i].match(node, isMethodCall);
if (res) {
return res;
}
}
return false;
}
const matchPluginsOrNull = (plugins.length === 0 ? null : matchPlugins);
ngInjectComments.init(ctx);
plugins.forEach(function(plugin) {
plugin.init(ctx);
});
traverse(ast, {pre: function(node) {
const pos = node.range[0];
while (pos >= triggers.pos) {
const trigger = triggers.getAndRemoveNext();
trigger.fn.call(null, node, trigger.ctx);
}
}, post: function(node) {
let targets = match(node, re, matchPluginsOrNull);
if (!targets) {

@@ -328,11 +442,5 @@ return;

// TODO add something to know that node has been altered so it won't happen again
for (let i = 0; i < targets.length; i++) {
const target = targets[i];
if (mode === "rebuild" && isAnnotatedArray(target)) {
replaceArray(target, fragments, quot);
} else if (mode === "remove" && isAnnotatedArray(target)) {
removeArray(target, fragments);
} else if (is.someof(mode, ["add", "rebuild"]) && isFunctionWithArgs(target)) {
insertArray(target, fragments, quot);
}
replaceRemoveOrInsertArrayForTarget(targets[i], ctx);
}

@@ -339,0 +447,0 @@ }});

@@ -29,2 +29,5 @@ // ng-annotate.js

describe: "detect short form myMod.controller(...) iff myMod matches regexp",
})
.options("plugin", {
describe: "use plugin with path (experimental)",
});

@@ -72,8 +75,24 @@

["add", "remove", "regexp", "single_quotes"].forEach(addOption);
["add", "remove", "regexp", "single_quotes", "plugin"].forEach(addOption);
if (config.plugin) {
if (!Array.isArray(config.plugin)) {
config.plugin = [config.plugin];
}
config.plugin = config.plugin.map(function(path) {
const absPath = tryor(fs.realpathSync.bind(fs, path), null);
if (!absPath) {
exit(fmt('error: plugin file not found {0}', path));
}
// the require below may throw an exception on parse-error
// that is fine because it gives the user the line info
return require(absPath);
});
}
const ret = ngAnnotate(src, config);
if (ret.errors) {
exit(ret.errors.join("\n"));
process.stderr.write(ret.errors.join("\n") + "\n");
process.exit(1);
}

@@ -80,0 +99,0 @@

7

package.json
{
"name": "ng-annotate",
"version": "0.8.0",
"version": "0.9.0",
"description": "add, remove and rebuild angularjs dependency injection annotations",

@@ -11,3 +11,2 @@ "main": "build/es5/ng-annotate-main.js",

"dependencies": {
"ast-traverse": "~0.1.1",
"alter": "~0.2.0",

@@ -18,3 +17,5 @@ "simple-fmt": "~0.1.0",

"esprima": "~1.2.0",
"optimist": "~0.6.1"
"optimist": "~0.6.1",
"ordered-ast-traverse": "~0.1.0",
"priorityqueuejs": "~0.2.0"
},

@@ -21,0 +22,0 @@ "devDependencies": {

@@ -35,3 +35,6 @@ # ng-annotate

Use the `--plugin` option to load user plugins (experimental, 0.9.x may change API). See
[plugin-example.js](plugin-example.js) for more info.
## Tools support

@@ -79,4 +82,8 @@ * [Grunt](http://gruntjs.com/): [grunt-ng-annotate](https://npmjs.org/package/grunt-ng-annotate)

`angular.module("MyMod").controller(name, ..)` where name is a variable rather than a
string literal is also supported.
ng-annotate understands `this.$get = function($scope) ..` and
`{.., $get: function($scope) ..}` inside a `provider`.
`{.., $get: function($scope) ..}` inside a `provider`. `self` and `that` can be used as
aliases for `this`.

@@ -91,2 +98,5 @@ ng-annotate understands `return {.., controller: function($scope) ..}` inside a

ng-annotate understands `$httpProvider.interceptors.push(function($scope) ..)` and
`$httpProvider.responseInterceptors.push(function($scope) ..)`.
ng-annotate understands [ui-router](https://github.com/angular-ui/ui-router) (`$stateProvider` and

@@ -98,3 +108,40 @@ `$urlRouterProvider`).

## Issues
## Explicit annotations
You can prepend a function expression with `/* @ngInject */` to explicitly state that this
function should get annotated. ng-annotate will leave the comment intact and will thus still
be able to also remove or rewrite such annotations. Use `/* @ngInject */` as an occasional
workaround when ng-annotate doesn't support your code style but feel free to open an issue
also.
var x = /* @ngInject */ function($scope) {};
obj = {controller: /*@ngInject*/ function($scope) {}};
obj.bar = /*@ngInject*/ function($scope) {};
=>
var x = /* @ngInject */ ["$scope", function($scope) {}];
obj = {controller: /*@ngInject*/ ["$scope", function($scope) {}]};
obj.bar = /*@ngInject*/ ["$scope", function($scope) {}];
`/* @ngInject */` can also be prepended to a function statement or a single variable declaration
(where its initializer is a function expression). It will then attach an `$injects` array to
the function.
// @ngInject
function Foo($scope) {}
// @ngInject
var foo = function($scope) {}
=>
// @ngInject
function Foo($scope) {}
Foo.$injects = ["$scope"];
// @ngInject
var foo = function($scope) {}
foo.$injects = ["$scope"];
## Issues and compatibility
If ng-annotate does not handle a construct you're using, if there's a bug or if you have a feature

@@ -120,6 +167,9 @@ request then please [file an issue](https://github.com/olov/ng-annotate/issues?state=open).

## Library (API)
ng-annotate can be used as a library. See `ng-annotate.js` for further info about
ng-annotate can be used as a library. See [ng-annotate.js](ng-annotate.js) for further info about
options and return value.
var ngAnnotate = require("ng-annotate");
var transformedSource = ngAnnotate(src, {add: true}).src;
var somePlugin = require("./some/path/some-plugin");
var res = ngAnnotate(src, {add: true, plugin: [somePlugin]})
var errorstringArray = res.errors;
var transformedSource = res.src;

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, function($scope, $timeout) {});
angular.module("MyMod").controller(ctrlName, function($scope, $timeout) {});
// object property

@@ -76,2 +80,5 @@ var myObj = {};

};
self.$get = function($scope) {};
that.$get = function($scope) {};
ignore.$get = function($scope) {};
});

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(function($scope) { a });
$httpProvider.responseInterceptors.push(function($scope) { a }, function(a, b) { b }, function() { c });
var interceptor = /*@ngInject*/ function($scope) { a };
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,34 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", function($match) { a; });
$urlRouterProvider.otherwise("", function($location) { a; });
$urlRouterProvider.rule(function($location) { a; });
$urlRouterProvider.anythingreally(function($location) { a; }).chained(function($location) { a; });
$urlRouterProvider.when("/", function($match) { a; });
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", function($location) { a; });
// explicit annotations
var x = /* @ngInject */ function($scope) {
};
var obj = {};
obj.bar = /*@ngInject*/ function($scope) {};
obj = {
controller: /*@ngInject*/ function($scope) {},
};
// @ngInject
function foo($scope) {
}
// @ngInject
// otherstuff
function Foo($scope) {
}
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, ['$scope', '$timeout', function($scope, $timeout) {}]);
angular.module("MyMod").controller(ctrlName, ['$scope', '$timeout', function($scope, $timeout) {}]);
// object property

@@ -76,2 +80,5 @@ var myObj = {};

}];
self.$get = ['$scope', function($scope) {}];
that.$get = ['$scope', function($scope) {}];
ignore.$get = function($scope) {};
}]);

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(['$scope', function($scope) { a }]);
$httpProvider.responseInterceptors.push(['$scope', function($scope) { a }], ['a', 'b', function(a, b) { b }], function() { c });
var interceptor = /*@ngInject*/ ['$scope', function($scope) { a }];
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,38 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", ['$match', function($match) { a; }]);
$urlRouterProvider.otherwise("", ['$location', function($location) { a; }]);
$urlRouterProvider.rule(['$location', function($location) { a; }]);
$urlRouterProvider.anythingreally(['$location', function($location) { a; }]).chained(['$location', function($location) { a; }]);
$urlRouterProvider.when("/", ['$match', function($match) { a; }]);
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", ['$location', function($location) { a; }]);
// explicit annotations
var x = /* @ngInject */ ['$scope', function($scope) {
}];
var obj = {};
obj.bar = /*@ngInject*/ ['$scope', function($scope) {}];
obj = {
controller: /*@ngInject*/ ['$scope', function($scope) {}],
};
// @ngInject
function foo($scope) {
}
foo.$injects = ['$scope'];
// @ngInject
// otherstuff
function Foo($scope) {
}
Foo.$injects = ['$scope'];
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
foo.$injects = ['$scope'];
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}
foo.$injects = ['$scope'];

@@ -25,2 +25,6 @@ "use strict";

// variable instead of string as first argument
myMod.controller(ctrlName, ["$scope", "$timeout", function($scope, $timeout) {}]);
angular.module("MyMod").controller(ctrlName, ["$scope", "$timeout", function($scope, $timeout) {}]);
// object property

@@ -76,2 +80,5 @@ var myObj = {};

}];
self.$get = ["$scope", function($scope) {}];
that.$get = ["$scope", function($scope) {}];
ignore.$get = function($scope) {};
}]);

@@ -128,2 +135,3 @@ myMod.provider("foo", function() {

.constant("foo", "bar")
.bootstrap(element, [], {})
.factory("foo", function() {

@@ -152,2 +160,9 @@ b;

// $httpProvider
$httpProvider.interceptors.push(["$scope", function($scope) { a }]);
$httpProvider.responseInterceptors.push(["$scope", function($scope) { a }], ["a", "b", function(a, b) { b }], function() { c });
var interceptor = /*@ngInject*/ ["$scope", function($scope) { a }];
$httpProvider.interceptors.push(interceptor);
// $routeProvider

@@ -231,5 +246,38 @@ $routeProvider.when("path", {

});
$urlRouterProvider.when("", ["$match", function($match) { a; }]);
$urlRouterProvider.otherwise("", ["$location", function($location) { a; }]);
$urlRouterProvider.rule(["$location", function($location) { a; }]);
$urlRouterProvider.anythingreally(["$location", function($location) { a; }]).chained(["$location", function($location) { a; }]);
$urlRouterProvider.when("/", ["$match", function($match) { a; }]);
$urlRouterProvider.otherwise("", function(a) { a; });
$urlRouterProvider.rule(function(a) { a; }).anything().when("/", ["$location", function($location) { a; }]);
// explicit annotations
var x = /* @ngInject */ ["$scope", function($scope) {
}];
var obj = {};
obj.bar = /*@ngInject*/ ["$scope", function($scope) {}];
obj = {
controller: /*@ngInject*/ ["$scope", function($scope) {}],
};
// @ngInject
function foo($scope) {
}
foo.$injects = ["$scope"];
// @ngInject
// otherstuff
function Foo($scope) {
}
Foo.$injects = ["$scope"];
// @ngInject
// has trailing semicolon
var foo = function($scope) {
};
foo.$injects = ["$scope"];
// @ngInject
// lacks trailing semicolon
var foo = function($scope) {
}
foo.$injects = ["$scope"];

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc