├── .travis.yml ├── README.md ├── bin └── ngmin ├── main.js ├── package.json └── test ├── chain.js ├── directive.js ├── loader.js ├── reference.js ├── route-provider.js ├── simple.js └── util.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.11' -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngmin (deprecated) 2 | [![Build Status](https://travis-ci.org/btford/ngmin.png?branch=master)](https://travis-ci.org/btford/ngmin) 3 | 4 | **Note:** this module is deprecated in favor of [ng-annotate](https://github.com/olov/ng-annotate). I do not plan to actively maintain this code. 5 | 6 | ngmin is an AngularJS application pre-minifier. The goal is ultimately to use this alongside yeoman and grunt to make developing and building Angular apps fast, easy, and fun. 7 | 8 | ## tl;dr 9 | Turns this 10 | 11 | ```javascript 12 | angular.module('whatever').controller('MyCtrl', function ($scope, $http) { ... }); 13 | ``` 14 | 15 | into 16 | 17 | ```javascript 18 | angular.module('whatever').controller('MyCtrl', ['$scope', '$http', function ($scope, $http) { ... }]); 19 | ``` 20 | 21 | so that minifiers can handle AngularJS's DI annotations and you can save a few keystrokes. 22 | 23 | ## Installation 24 | Install via npm: 25 | ```bash 26 | npm install -g ngmin 27 | ``` 28 | 29 | ## Build Systems 30 | 31 | - [grunt-ngmin](https://github.com/btford/grunt-ngmin) 32 | - [gulp-ngmin](https://github.com/sindresorhus/gulp-ngmin) 33 | - [broccoli-ng-min](https://github.com/jakswa/broccoli-ng-min) 34 | 35 | ## Asset Pipelines 36 | 37 | ### Ruby on Rails 38 | 39 | `ngmin` is available for Rails via [`ngmin-rails`](http://rubygems.org/gems/ngmin-rails). 40 | 41 | ### Clojure Ring 42 | 43 | `ngmin` is available for Clojure Ring via [`optimus-angular`](https://github.com/magnars/optimus-angular) as an [`Optimus`](https://github.com/magnars/optimus) asset middleware. 44 | 45 | ## CLI Usage 46 | 47 | Ideally, you should concat all of your files, then run `ngmin` once on the concatenated file. 48 | 49 | ```bash 50 | ngmin somefile.js somefile.annotate.js 51 | ``` 52 | 53 | From here, the annotated file(s) to a minifier. 54 | 55 | `ngmin` also accepts stdio. The following is the same as above: 56 | 57 | ```bash 58 | ngmin < somefile.js > somefile.annotate.js 59 | ``` 60 | 61 | ### Dynamic Mode 62 | `ngmin` now has a dynamic mode that you can enable with the `-d` or `--dynamic` flag: 63 | 64 | ```shell 65 | ngmin -d < code.js 66 | ``` 67 | 68 | It runs your program in node with a patched version of Angular to try to detect places to annotate. 69 | This feature is new and might have rough edges. 70 | 71 | See [ngmin-dynamic](https://github.com/btford/ngmin-dynamic) for more. 72 | 73 | ## Conventions 74 | `ngmin` does not currently attempt to be fully generalized, and might not work if you're too clever. If you follow these conventions, which are the same as what the AngularJS Yeoman generator defaults, you should be fine. 75 | 76 | ### Module Declaration 77 | 78 | ```javascript 79 | // like this 80 | angular.module('myModuleName', ['dependOnThisModule']); 81 | ``` 82 | 83 | ### Controller Declaration 84 | 85 | ```javascript 86 | // like this 87 | angular.module('myModuleName').controller('MyCtrl', function ($scope) { 88 | // ... 89 | }); 90 | ``` 91 | 92 | ### Service Declaration 93 | This should work for all injectable APIs. 94 | 95 | ```javascript 96 | // like this 97 | angular.module('myModuleName').service('myService', function ($scope) { 98 | // ... 99 | }); 100 | ``` 101 | 102 | ### Chaining 103 | You can chain methods like this, and `ngmin` should still work fine: 104 | 105 | ```javascript 106 | // like this 107 | angular.module('myModuleName'). 108 | service('myFirstService', function ($scope) { 109 | // ... 110 | }). 111 | service('mySecondService', function ($scope) { 112 | // ... 113 | }); 114 | ``` 115 | 116 | This works with all injectable APIs. 117 | 118 | ### References 119 | This is not the preferred way of dealing with modules, and thus support for it isn't completely comprehensive. Something like this will work: 120 | ```javascript 121 | var myMod = angular.module('myMod', []); 122 | myMod.service('myService', function ($scope) { 123 | // ... 124 | }); 125 | ``` 126 | 127 | But something like this will probably fail spectacularly: 128 | ```javascript 129 | var myMod = angular.module('myMod', []); 130 | var mod1, mod2, mod3; 131 | mod1 = myMod; 132 | mod3 = (function () { 133 | return mod2 = mod1; 134 | }()); 135 | mod3.service('myService', function ($scope) { 136 | // ... 137 | }); 138 | ``` 139 | 140 | Please don't write code like the second example. :) 141 | 142 | ## Conceptual Overview 143 | AngularJS's DI system inspects function parameters to determine what to inject: 144 | ```javascript 145 | // angular knows to inject "myService" based on the parameter in "myFactory" 146 | someModule.factory('myFactory', function (myService) { 147 | // ... 148 | }); 149 | ``` 150 | AngularJS does this for `Module#controller`, `Module#service`, `Module#factory`, etc. Check out the [developer guide on DI](http://docs.angularjs.org/guide/di) for more info. 151 | 152 | JavaScript minifiers rename function parameters. The code above, when minified, might look like this: 153 | ```javascript 154 | // the "myService" parameter has been renamed to "a" to save precious bytes 155 | someModule.factory('myFactory', function (a) { 156 | // ... 157 | }); 158 | ``` 159 | 160 | To overcome this, AngularJS has a "minifier-safe inline" notation (see [Inline Annotation](http://docs.angularjs.org/guide/di) in the docs) that annotates `angular.controller`, `angular.service`, `angular.factory` with an array of dependencies' names as strings: 161 | ```javascript 162 | // angular knows to inject "myService" based on the parameter in "myFactory" 163 | someModule.factory('myFactory', ['myService', function (myService) { 164 | // ... 165 | }]); 166 | ``` 167 | 168 | So with this notation, when minified, still includes the correct dependency names even if the function arguments are re-written: 169 | ```javascript 170 | someModule.factory('myFactory', ['myService', function (a) { 171 | // minified variable "a" will represent "myService" 172 | // ... 173 | }]); 174 | ``` 175 | 176 | Writing the "minifier-safe" version by hand is kind of annoying because you have to keep both the array of dependency names and function parameters in sync. 177 | 178 | ## License 179 | MIT 180 | -------------------------------------------------------------------------------- /bin/ngmin: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var program = require('commander'), 4 | fs = require('fs'), 5 | ngmin = require('../main'); 6 | 7 | program 8 | .version(require('../package.json').version) 9 | .usage(' ') 10 | .option('-d, --dynamic', 'Use dynamic mode') 11 | .parse(process.argv); 12 | 13 | if (program.args.length !== 0 && program.args.length !== 2) { 14 | console.error('ngmin should be called with an input and output file, or no arguments if using stdio'); 15 | process.exit(1); 16 | } 17 | 18 | if (program.args.length === 2) { 19 | var infile = program.args[0]; 20 | var outfile = program.args[1]; 21 | 22 | try { 23 | var content = fs.readFileSync(infile, 'utf-8'); 24 | } catch (e) { 25 | console.error('Error opening: ' + infile); 26 | process.exit(1); 27 | } 28 | var generatedCode = ngmin.annotate(content, program); 29 | 30 | try { 31 | fs.writeFileSync(outfile, generatedCode); 32 | } catch (e) { 33 | console.error('Error writing to: ' + outfile); 34 | process.exit(1); 35 | } 36 | 37 | } else { 38 | // else use stdio 39 | var buffer = ''; 40 | 41 | process.stdin.setEncoding('utf8'); 42 | process.stdin.resume(); 43 | 44 | process.stdin.on('data', function (chunk) { 45 | buffer += chunk; 46 | }); 47 | 48 | process.stdin.on('end', function() { 49 | process.stdout.write(ngmin.annotate(buffer, program)); 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | 2 | var esprima = require('esprima'), 3 | escodegen = require('escodegen'), 4 | dynamic = require('ngmin-dynamic'), 5 | astral = require('astral')(); 6 | 7 | // register angular annotator in astral 8 | require('astral-angular-annotate')(astral); 9 | 10 | var annotate = exports.annotate = function (inputCode, options) { 11 | 12 | if (options && options.dynamic) { 13 | return dynamic(inputCode); 14 | } 15 | 16 | var ast = esprima.parse(inputCode, { 17 | tolerant: true, 18 | comment: true, 19 | range: true, 20 | tokens: true 21 | }); 22 | // TODO: unstable API, see https://github.com/Constellation/escodegen/issues/10 23 | ast = escodegen.attachComments(ast, ast.comments, ast.tokens); 24 | 25 | astral.run(ast); 26 | 27 | var generatedCode = escodegen.generate(ast, { 28 | format: { 29 | indent: { 30 | style: ' ' 31 | } 32 | }, 33 | comment: true 34 | }); 35 | 36 | return generatedCode; 37 | }; 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngmin", 3 | "description": "AngularJS Minifier", 4 | "version": "0.5.0", 5 | "author": "Brian Ford", 6 | "license": "MIT", 7 | "main": "main.js", 8 | "dependencies": { 9 | "astral": "~0.1.0", 10 | "astral-angular-annotate": "~0.0.1", 11 | "escodegen": "~0.0.15", 12 | "esprima": "~1.0.2", 13 | "commander": "~1.1.1", 14 | "clone": "~0.1.6", 15 | "ngmin-dynamic": "~0.0.1" 16 | }, 17 | "devDependencies": { 18 | "should": "~1.2.1", 19 | "mocha": "~1.5.0", 20 | "fn-body": "0.0.1", 21 | "normalize-fn": "0.0.1" 22 | }, 23 | "keywords": [ 24 | "angularjs", 25 | "minifier" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/btford/ngmin" 30 | }, 31 | "bin": { 32 | "ngmin": "./bin/ngmin" 33 | }, 34 | "scripts": { 35 | "test": "./node_modules/.bin/mocha --globals angular,require" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/chain.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test chained declarations 3 | * angular.module('myMod', []). 4 | * controller( ... ). 5 | * controller( ... ); 6 | */ 7 | 8 | 9 | var assert = require('should'); 10 | 11 | // so we don't have to put the stuff we're testing into a string 12 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 13 | var annotate = function (arg) { 14 | return require('../main').annotate( 15 | stringifyFunctionBody(arg)); 16 | }; 17 | 18 | 19 | describe('annotate', function () { 20 | 21 | it('should annotate chained declarations', function () { 22 | var annotated = annotate(function () { 23 | angular.module('myMod', []). 24 | service('myService', function (dep) {}). 25 | service('MyCtrl', function ($scope) {}); 26 | }); 27 | 28 | annotated.should.equal(stringifyFunctionBody(function () { 29 | angular.module('myMod', []). 30 | service('myService', ['dep', function (dep) {}]). 31 | service('MyCtrl', ['$scope', function ($scope) {}]); 32 | })); 33 | }); 34 | 35 | it('should annotate multiple chained declarations', function () { 36 | var annotated = annotate(function () { 37 | angular.module('myMod', []). 38 | service('myService', function (dep) {}). 39 | service('myService2', function (dep) {}). 40 | service('myService3', function (dep) {}). 41 | service('MyCtrl', function ($scope) {}); 42 | }); 43 | 44 | annotated.should.equal(stringifyFunctionBody(function () { 45 | angular.module('myMod', []). 46 | service('myService', ['dep', function (dep) {}]). 47 | service('myService2', ['dep', function (dep) {}]). 48 | service('myService3', ['dep', function (dep) {}]). 49 | service('MyCtrl', ['$scope', function ($scope) {}]); 50 | })); 51 | }); 52 | 53 | it('should annotate multiple chained declarations on constants', function() { 54 | var annotated = annotate(function () { 55 | angular.module('myMod', []). 56 | constant('myConstant', 'someConstant'). 57 | constant('otherConstant', 'otherConstant'). 58 | service('myService1', function (dep) {}). 59 | service('MyCtrl', function ($scope) {}); 60 | }); 61 | 62 | annotated.should.equal(stringifyFunctionBody(function () { 63 | angular.module('myMod', []). 64 | constant('myConstant', 'someConstant'). 65 | constant('otherConstant', 'otherConstant'). 66 | service('myService1', ['dep', function (dep) {}]). 67 | service('MyCtrl', ['$scope', function ($scope) {}]); 68 | })); 69 | }); 70 | 71 | it('should annotate multiple chained declarations on values', function() { 72 | var annotated = annotate(function () { 73 | angular.module('myMod', []). 74 | value('myConstant', 'someConstant'). 75 | value('otherConstant', 'otherConstant'). 76 | service('myService1', function (dep) {}). 77 | service('MyCtrl', function ($scope) {}); 78 | }); 79 | 80 | annotated.should.equal(stringifyFunctionBody(function () { 81 | angular.module('myMod', []). 82 | value('myConstant', 'someConstant'). 83 | value('otherConstant', 'otherConstant'). 84 | service('myService1', ['dep', function (dep) {}]). 85 | service('MyCtrl', ['$scope', function ($scope) {}]); 86 | })); 87 | }); 88 | 89 | it('should annotate multiple chained declarations on constants and value regardless of order', function() { 90 | var annotated = annotate(function () { 91 | angular.module('myMod', []). 92 | value('myConstant', 'someConstant'). 93 | service('myService1', function (dep) {}). 94 | constant('otherConstant', 'otherConstant'). 95 | service('MyCtrl', function ($scope) {}); 96 | }); 97 | 98 | annotated.should.equal(stringifyFunctionBody(function () { 99 | angular.module('myMod', []). 100 | value('myConstant', 'someConstant'). 101 | service('myService1', ['dep', function (dep) {}]). 102 | constant('otherConstant', 'otherConstant'). 103 | service('MyCtrl', ['$scope', function ($scope) {}]); 104 | })); 105 | }); 106 | 107 | it('should annotate refs that have been chained', function () { 108 | var annotated = annotate(function () { 109 | var mod = angular.module('chain', []); 110 | mod.factory('a', function ($scope){}). 111 | factory('b', function ($scope){}); 112 | }); 113 | 114 | annotated.should.equal(stringifyFunctionBody(function () { 115 | var mod = angular.module('chain', []); 116 | mod.factory('a', ['$scope', function($scope){}]). 117 | factory('b', ['$scope', function($scope){}]); 118 | })); 119 | }); 120 | 121 | it('should annotate refs to chains', function () { 122 | var annotated = annotate(function () { 123 | var mod = angular.module('chain', []). 124 | factory('a', function ($scope){}); 125 | mod.factory('b', function ($scope){}); 126 | }); 127 | 128 | annotated.should.equal(stringifyFunctionBody(function () { 129 | var mod = angular.module('chain', []). 130 | factory('a', ['$scope', function($scope){}]); 131 | mod.factory('b', ['$scope', function($scope){}]); 132 | })); 133 | }); 134 | 135 | }); 136 | -------------------------------------------------------------------------------- /test/directive.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test annotations within the Directive Definition Object (DDO): 3 | * 4 | * angular.module('myMod', []).directive('whatever', function () { 5 | * return { 6 | * controller: function ($scope) { ... } // <--- this needs annotations 7 | * }; 8 | * }) 9 | * 10 | */ 11 | 12 | var assert = require('should'); 13 | 14 | // so we don't have to put the stuff we're testing into a string 15 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 16 | var annotate = function (arg) { 17 | return require('../main').annotate( 18 | stringifyFunctionBody(arg)); 19 | }; 20 | 21 | 22 | describe('annotate', function () { 23 | 24 | it('should annotate directive controllers', function () { 25 | var annotated = annotate(function () { 26 | angular.module('myMod', []). 27 | directive('myDir', function () { 28 | return { 29 | controller: function ($scope) { $scope.test = true; } 30 | }; 31 | }); 32 | }); 33 | 34 | annotated.should.equal(stringifyFunctionBody(function () { 35 | angular.module('myMod', []). 36 | directive('myDir', function () { 37 | return { 38 | controller: [ 39 | '$scope', 40 | function ($scope) { $scope.test = true; } 41 | ] 42 | }; 43 | }); 44 | })); 45 | }); 46 | 47 | it('should annotate directive controllers of annotated directives', function () { 48 | var annotated = annotate(function () { 49 | angular.module('myMod', []). 50 | directive('myDir', function ($window) { 51 | return { 52 | controller: function ($scope) { $scope.test = true; } 53 | }; 54 | }); 55 | }); 56 | 57 | annotated.should.equal(stringifyFunctionBody(function () { 58 | angular.module('myMod', []). 59 | directive('myDir', ['$window', function ($window) { 60 | return { 61 | controller: [ 62 | '$scope', 63 | function ($scope) { $scope.test = true; } 64 | ] 65 | }; 66 | }]); 67 | })); 68 | }); 69 | 70 | }); 71 | -------------------------------------------------------------------------------- /test/loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test for angular modules that are wrapped by goofy 3 | * 3rd party loaders like Require.js 4 | */ 5 | 6 | var assert = require('should'); 7 | 8 | // so we don't have to put the stuff we're testing into a string 9 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 10 | var annotate = function (arg) { 11 | return require('../main').annotate( 12 | stringifyFunctionBody(arg)); 13 | }; 14 | 15 | 16 | describe('annotate', function () { 17 | 18 | it('should annotate modules inside of loaders', function () { 19 | var annotated = annotate(function () { 20 | define(["./thing"], function(thing) { 21 | angular.module('myMod', []). 22 | controller('MyCtrl', function ($scope) {}); 23 | }); 24 | }); 25 | 26 | annotated.should.equal(stringifyFunctionBody(function () { 27 | define(["./thing"], function(thing) { 28 | angular.module('myMod', []). 29 | controller('MyCtrl', ['$scope', function ($scope) {}]); 30 | }); 31 | })); 32 | }); 33 | 34 | it('should annotate module refs inside of loaders', function () { 35 | var annotated = annotate(function () { 36 | 37 | 38 | define(["./thing"], function(thing) { 39 | var myMod = angular.module('myMod', []); 40 | myMod.controller('MyCtrl', function ($scope) {}); 41 | return myMod; 42 | }); 43 | 44 | }); 45 | 46 | annotated.should.equal(stringifyFunctionBody(function () { 47 | define(["./thing"], function(thing) { 48 | var myMod = angular.module('myMod', []); 49 | myMod.controller('MyCtrl', ['$scope', function ($scope) {}]); 50 | return myMod; 51 | }); 52 | })); 53 | }); 54 | 55 | 56 | }); 57 | -------------------------------------------------------------------------------- /test/reference.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test cases where there's a reference to a module 3 | * 4 | * var myMod = angular.module('myMod', []); 5 | * myMod.controller( ... ) 6 | * 7 | */ 8 | 9 | var assert = require('should'); 10 | 11 | // so we don't have to put the stuff we're testing into a string 12 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 13 | var annotate = function (arg) { 14 | return require('../main').annotate( 15 | stringifyFunctionBody(arg)); 16 | }; 17 | 18 | 19 | describe('annotate', function () { 20 | 21 | it('should annotate declarations on referenced modules', function () { 22 | var annotated = annotate(function () { 23 | var myMod = angular.module('myMod', []); 24 | myMod.controller('MyCtrl', function ($scope) {}); 25 | }); 26 | 27 | annotated.should.equal(stringifyFunctionBody(function () { 28 | var myMod = angular.module('myMod', []); 29 | myMod.controller('MyCtrl', [ 30 | '$scope', 31 | function ($scope) { 32 | } 33 | ]); 34 | })); 35 | }); 36 | 37 | it('should annotate declarations on referenced modules when reference is declared then initialized', function () { 38 | var annotated = annotate(function () { 39 | var myMod; 40 | myMod = angular.module('myMod', []); 41 | myMod.controller('MyCtrl', function ($scope) {}); 42 | }); 43 | 44 | annotated.should.equal(stringifyFunctionBody(function () { 45 | var myMod; 46 | myMod = angular.module('myMod', []); 47 | myMod.controller('MyCtrl', [ 48 | '$scope', 49 | function ($scope) { 50 | } 51 | ]); 52 | })); 53 | }); 54 | 55 | it('should annotate object-defined providers on referenced modules', function () { 56 | var annotated = annotate(function () { 57 | var myMod; 58 | myMod = angular.module('myMod', []); 59 | myMod.provider('MyService', { $get: function(service) {} }); 60 | }); 61 | 62 | annotated.should.equal(stringifyFunctionBody(function () { 63 | var myMod; 64 | myMod = angular.module('myMod', []); 65 | myMod.provider('MyService', { 66 | $get: ['service', function(service) {}] 67 | }); 68 | })); 69 | }); 70 | 71 | // TODO: lol commenting out test cases 72 | /* 73 | it('should annotate declarations on referenced modules ad infinitum', function () { 74 | var annotated = annotate(function () { 75 | var myMod = angular.module('myMod', []); 76 | var myMod2 = myMod, myMod3; 77 | myMod3 = myMod2; 78 | myMod3.controller('MyCtrl', function ($scope) {}); 79 | }); 80 | 81 | annotated.should.equal(stringifyFunctionBody(function () { 82 | var myMod = angular.module('myMod', []); 83 | var myMod2 = myMod, myMod3; 84 | myMod3 = myMod2; 85 | myMod3.controller('MyCtrl', ['$scope', function ($scope) {}]); 86 | })); 87 | }); 88 | */ 89 | 90 | // TODO: it should annotate silly assignment chains 91 | 92 | it('should not annotate declarations on non-module objects', function () { 93 | var fn = function () { 94 | var myMod, myOtherMod; 95 | myMod = angular.module('myMod', []); 96 | myOtherMod.controller('MyCtrl', function ($scope) {}); 97 | }; 98 | var annotated = annotate(fn); 99 | annotated.should.equal(stringifyFunctionBody(fn)); 100 | }); 101 | 102 | it('should keep comments', function() { 103 | var annotated = annotate(function () { 104 | var myMod = angular.module('myMod', []); 105 | /*! license */ 106 | myMod.controller('MyCtrl', function ($scope) {}); 107 | }); 108 | 109 | annotated.should.equal(stringifyFunctionBody(function () { 110 | var myMod = angular.module('myMod', []); 111 | /*! license */ 112 | myMod.controller('MyCtrl', [ 113 | '$scope', 114 | function ($scope) { 115 | } 116 | ]); 117 | })); 118 | }); 119 | 120 | }); 121 | -------------------------------------------------------------------------------- /test/route-provider.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test annotations within the Directive Definition Object (DDO): 3 | * 4 | * angular.module('myMod', []).directive('whatever', function () { 5 | * return { 6 | * controller: function ($scope) { ... } // <--- this needs annotations 7 | * }; 8 | * }) 9 | * 10 | */ 11 | 12 | var assert = require('should'); 13 | 14 | // so we don't have to put the stuff we're testing into a string 15 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 16 | var annotate = function (arg) { 17 | return require('../main').annotate( 18 | stringifyFunctionBody(arg)); 19 | }; 20 | 21 | 22 | describe('annotate', function () { 23 | 24 | it('should annotate $routeProvider.when()', function () { 25 | var annotated = annotate(function () { 26 | angular.module('myMod', []). 27 | config(function ($routeProvider) { 28 | $routeProvider.when('path', { 29 | controller: function ($scope) { 30 | $scope.works = true; 31 | } 32 | }); 33 | }); 34 | }); 35 | 36 | annotated.should.equal(stringifyFunctionBody(function () { 37 | angular.module('myMod', []). 38 | config(['$routeProvider', function ($routeProvider) { 39 | $routeProvider.when('path', { 40 | controller: ['$scope', function ($scope) { 41 | $scope.works = true; 42 | }] 43 | }); 44 | }]); 45 | })); 46 | }); 47 | 48 | 49 | it('should annotate chained $routeProvider.when()', function () { 50 | var annotated = annotate(function () { 51 | angular.module('myMod', []). 52 | config(function ($routeProvider) { 53 | $routeProvider. 54 | when('path', { 55 | controller: function ($scope) { 56 | $scope.works = true; 57 | } 58 | }). 59 | when('other/path', { 60 | controller: function ($http) { 61 | $http.get(); 62 | } 63 | }); 64 | }); 65 | }); 66 | 67 | annotated.should.equal(stringifyFunctionBody(function () { 68 | angular.module('myMod', []). 69 | config(['$routeProvider', function ($routeProvider) { 70 | $routeProvider. 71 | when('path', { 72 | controller: ['$scope', function ($scope) { 73 | $scope.works = true; 74 | }] 75 | }). 76 | when('other/path', { 77 | controller: ['$http', function ($http) { 78 | $http.get(); 79 | }] 80 | }); 81 | }]); 82 | })); 83 | }); 84 | 85 | 86 | }); 87 | -------------------------------------------------------------------------------- /test/simple.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Test simple cases 3 | * 4 | * angular.module('myMod', []).controller( ... ); 5 | * 6 | */ 7 | 8 | var assert = require('should'); 9 | 10 | // so we don't have to put the stuff we're testing into a string 11 | var stringifyFunctionBody = require('./util').stringifyFunctionBody; 12 | var annotate = function (arg) { 13 | return require('../main').annotate( 14 | stringifyFunctionBody(arg)); 15 | }; 16 | 17 | 18 | describe('annotate', function () { 19 | 20 | it('should annotate controllers', function () { 21 | var annotated = annotate(function () { 22 | angular.module('myMod', []). 23 | controller('MyCtrl', function ($scope) { 24 | $scope.foo = 'bar'; 25 | }); 26 | }); 27 | 28 | annotated.should.equal(stringifyFunctionBody(function () { 29 | angular.module('myMod', []).controller('MyCtrl', [ 30 | '$scope', 31 | function ($scope) { 32 | $scope.foo = 'bar'; 33 | } 34 | ]); 35 | })); 36 | }); 37 | 38 | 39 | it('should annotate directives', function () { 40 | var annotated = annotate(function () { 41 | angular.module('myMod', []). 42 | directive('myDirective', function ($rootScope) { 43 | return { 44 | restrict: 'E', 45 | template: 'sup' 46 | }; 47 | }); 48 | }); 49 | 50 | annotated.should.equal(stringifyFunctionBody(function () { 51 | angular.module('myMod', []).directive('myDirective', [ 52 | '$rootScope', 53 | function ($rootScope) { 54 | return { 55 | restrict: 'E', 56 | template: 'sup' 57 | }; 58 | } 59 | ]); 60 | })); 61 | }); 62 | 63 | 64 | it('should annotate filters', function () { 65 | var annotated = annotate(function () { 66 | angular.module('myMod', []). 67 | filter('myFilter', function (dep) {}); 68 | }); 69 | 70 | annotated.should.equal(stringifyFunctionBody(function () { 71 | angular.module('myMod', []).filter('myFilter', [ 72 | 'dep', 73 | function (dep) { 74 | } 75 | ]); 76 | })); 77 | }); 78 | 79 | 80 | it('should annotate services', function () { 81 | var annotated = annotate(function () { 82 | angular.module('myMod', []). 83 | service('myService', function (dep) {}); 84 | }); 85 | 86 | annotated.should.equal(stringifyFunctionBody(function () { 87 | angular.module('myMod', []).service('myService', [ 88 | 'dep', 89 | function (dep) { 90 | } 91 | ]); 92 | })); 93 | }); 94 | 95 | 96 | it('should annotate factories', function () { 97 | var annotated = annotate(function () { 98 | angular.module('myMod', []). 99 | controller('factory', function (dep) {}); 100 | }); 101 | 102 | annotated.should.equal(stringifyFunctionBody(function () { 103 | angular.module('myMod', []).controller('factory', [ 104 | 'dep', 105 | function (dep) { 106 | } 107 | ]); 108 | })); 109 | }); 110 | 111 | 112 | it('should annotate decorators', function () { 113 | var annotated = annotate(function () { 114 | angular.module('myMod', []). 115 | decorator('myService', function (dep) {}); 116 | }); 117 | 118 | annotated.should.equal(stringifyFunctionBody(function () { 119 | angular.module('myMod', []).decorator('myService', [ 120 | 'dep', 121 | function (dep) { 122 | } 123 | ]); 124 | })); 125 | }); 126 | 127 | 128 | it('should annotate config', function () { 129 | var annotated = annotate(function () { 130 | angular.module('myMod', []). 131 | config(function (dep) {}); 132 | }); 133 | 134 | annotated.should.equal(stringifyFunctionBody(function () { 135 | angular.module('myMod', []).config([ 136 | 'dep', 137 | function (dep) { 138 | } 139 | ]); 140 | })); 141 | }); 142 | 143 | 144 | it('should annotate run', function () { 145 | var annotated = annotate(function () { 146 | angular.module('myMod', []). 147 | run(function (dep) {}); 148 | }); 149 | 150 | annotated.should.equal(stringifyFunctionBody(function () { 151 | angular.module('myMod', []).run([ 152 | 'dep', 153 | function (dep) { 154 | } 155 | ]); 156 | })); 157 | }); 158 | 159 | 160 | it('should annotate providers defined by functions', function () { 161 | var annotated = annotate(function () { 162 | angular.module('myMod', []). 163 | provider('myService', function (dep) { 164 | this.$get = function(otherDep) {}; 165 | }); 166 | }); 167 | 168 | annotated.should.equal(stringifyFunctionBody(function () { 169 | angular.module('myMod', []).provider('myService', [ 170 | 'dep', 171 | function (dep) { 172 | this.$get = ['otherDep', function(otherDep) {}]; 173 | } 174 | ]); 175 | })); 176 | }); 177 | 178 | 179 | it('should annotate providers defined by objects', function () { 180 | var annotated = annotate(function () { 181 | angular.module('myMod', []). 182 | provider('myService', { 183 | $get: function(otherDep) {} 184 | }) 185 | }); 186 | 187 | annotated.should.equal(stringifyFunctionBody(function () { 188 | angular.module('myMod', []). 189 | provider('myService', { 190 | $get: ['otherDep', function(otherDep) {}] 191 | }); 192 | })); 193 | }); 194 | 195 | 196 | it('should annotate declarations on modules being referenced', function () { 197 | var annotated = annotate(function () { 198 | angular.module('myMod', []); 199 | angular.module('myMod'). 200 | provider('myService', function (dep) {}); 201 | }); 202 | 203 | annotated.should.equal(stringifyFunctionBody(function () { 204 | angular.module('myMod', []); 205 | angular.module('myMod').provider('myService', [ 206 | 'dep', 207 | function (dep) { 208 | } 209 | ]); 210 | })); 211 | }); 212 | 213 | 214 | it('should not annotate declarations with no dependencies', function () { 215 | var fn = function () { 216 | angular.module('myMod', []). 217 | provider('myService', function () {}); 218 | }; 219 | var annotated = annotate(fn); 220 | 221 | annotated.should.equal(stringifyFunctionBody(fn)); 222 | }); 223 | 224 | 225 | it('should not annotate constants', function () { 226 | var fn = function () { 227 | angular.module('myMod', []).constant('fortyTwo', 42); 228 | }; 229 | 230 | var annotated = annotate(fn); 231 | annotated.should.equal(stringifyFunctionBody(fn)); 232 | }); 233 | 234 | 235 | it('should not annotate values', function () { 236 | var fn = function () { 237 | angular.module('myMod', []).value('fortyTwo', 42); 238 | }; 239 | 240 | var annotated = annotate(fn); 241 | annotated.should.equal(stringifyFunctionBody(fn)); 242 | }); 243 | 244 | }); 245 | -------------------------------------------------------------------------------- /test/util.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Test utils 4 | */ 5 | 6 | 7 | var body = require('fn-body'), 8 | normalize = require('normalize-fn'); 9 | 10 | // given a function, return its body as a normalized string. 11 | // makes tests look a bit cleaner 12 | exports.stringifyFunctionBody = function (fn) { 13 | return normalize(body(fn)); 14 | }; 15 | --------------------------------------------------------------------------------