├── .gitattributes ├── .babelrc ├── .prettierignore ├── .eslintignore ├── test ├── .eslintrc.json ├── fixtures │ ├── not-annotated.js │ ├── partially-annotated-messy.js │ ├── annotated-regexp.js │ ├── annotated.js │ ├── annotated-messy.js │ ├── multiple-1.js │ ├── multiple-2.js │ ├── annotated-single.js │ ├── annotated-es6.js │ ├── not-annotated-es6.js │ ├── concatenated.js │ └── concatenated-separator.js └── spec │ └── api.js ├── .gitignore ├── .travis.yml ├── .eslintrc.json ├── .mailmap ├── .prettierrc.js ├── LICENSE ├── appveyor.yml ├── package.json ├── README.md ├── tasks └── ng-annotate.js └── Gruntfile.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | test/fixtures/** 2 | test/tmp/** 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | test/tmp/**/*.js 3 | test/fixtures/**/*.js 4 | -------------------------------------------------------------------------------- /test/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /package-lock.json 2 | /yarn.lock 3 | /*.log 4 | /node_modules/ 5 | /test/tmp 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '10' 5 | - '12' 6 | - '13' 7 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "mgol", 5 | 6 | "env": { 7 | "node": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Michał Gołębiowski-Owczarek 2 | Michał Gołębiowski-Owczarek 3 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // See https://prettier.io/docs/en/options.html 4 | module.exports = { 5 | singleQuote: true, 6 | 7 | // JS files are not compiled to ES5 so trailing commas in function 8 | // parameters would break in older browsers. 9 | trailingComma: 'all', 10 | 11 | tabWidth: 4, 12 | }; 13 | -------------------------------------------------------------------------------- /test/fixtures/not-annotated.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }) 11 | .service("appService", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }); 26 | 27 | 28 | nonMatchedMod.service("appService", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/partially-annotated-messy.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope",'$timeout',function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }); 26 | 27 | 28 | nonMatchedMod.service("appService", ['$rootScope',function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/annotated-regexp.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/annotated.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/annotated-messy.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope",'$timeout',function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ['$rootScope',function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/multiple-1.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/multiple-2.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /test/fixtures/annotated-single.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(['$rootScope', '$timeout', function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ['$rootScope', function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ['$rootScope', function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ['$rootScope', function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /test/fixtures/annotated-es6.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | (function () { 4 | "use strict"; 5 | 6 | angular.module("app", ["dep1", "dep2"]).run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 7 | var uselessConstant = 2; 8 | { 9 | var _uselessConstant = 3; 10 | } 11 | $timeout(function () { 12 | $rootScope.a = 2; 13 | }); 14 | $rootScope.b = 2; 15 | }]).service("appService", ["$rootScope", function ($rootScope) { 16 | this.getA = function getA() { 17 | return $rootScope.a; 18 | }; 19 | }]).run(["appService", _.noop]); 20 | 21 | var matchedMod = angular.module("app2", []); 22 | var nonMatchedMod = angular.module("app3", []); 23 | 24 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 25 | this.getA = function getA() { 26 | return $rootScope.a; 27 | }; 28 | }]); 29 | 30 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 31 | this.getA = function getA() { 32 | return $rootScope.a; 33 | }; 34 | }]); 35 | })(); 36 | -------------------------------------------------------------------------------- /test/fixtures/not-annotated-es6.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(function ($rootScope, $timeout) { 6 | const uselessConstant = 2; 7 | { 8 | const uselessConstant = 3; 9 | } 10 | $timeout(function () { 11 | $rootScope.a = 2; 12 | }); 13 | $rootScope.b = 2; 14 | }) 15 | .service("appService", function ($rootScope) { 16 | this.getA = function getA() { 17 | return $rootScope.a; 18 | }; 19 | }) 20 | .run(["appService", _.noop]); 21 | 22 | var matchedMod = angular.module("app2", []); 23 | var nonMatchedMod = angular.module("app3", []); 24 | 25 | matchedMod.service("appService", function ($rootScope) { 26 | this.getA = function getA() { 27 | return $rootScope.a; 28 | }; 29 | }); 30 | 31 | 32 | nonMatchedMod.service("appService", function ($rootScope) { 33 | this.getA = function getA() { 34 | return $rootScope.a; 35 | }; 36 | }); 37 | })(); 38 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | clone_depth: 10 4 | 5 | # Fix line endings in Windows. (runs before repo cloning) 6 | init: 7 | - git config --global core.autocrlf input 8 | 9 | # Test against these versions of Node.js. 10 | environment: 11 | matrix: 12 | - nodejs_version: '10' 13 | - nodejs_version: '13' 14 | 15 | # Install scripts. (runs after repo cloning) 16 | install: 17 | # Get the Node version with matching major & minor numbers 18 | - ps: Install-Product node $env:nodejs_version 19 | # Typical npm stuff. 20 | - npm install 21 | 22 | # Post-install test scripts. 23 | test_script: 24 | # Output useful info for debugging. 25 | - node --version 26 | - npm --version 27 | - npm test 28 | 29 | # Don't actually build. 30 | build: off 31 | 32 | # Finish immediately if one of the jobs fails. 33 | matrix: 34 | fast_finish: true 35 | 36 | # Set up cache, clear it on package.json changes. 37 | cache: 38 | # npm cache. 39 | - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json 40 | # Local npm packages. 41 | - node_modules -> package.json 42 | 43 | # Set build version format here instead of in the admin panel. 44 | version: '{build}' 45 | -------------------------------------------------------------------------------- /test/fixtures/concatenated.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | 35 | (function () { 36 | "use strict"; 37 | 38 | angular.module("app", ["dep1", "dep2"]) 39 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 40 | $timeout(function () { 41 | $rootScope.a = 2; 42 | }); 43 | $rootScope.b = 2; 44 | }]) 45 | .service("appService", ["$rootScope", function ($rootScope) { 46 | this.getA = function getA() { 47 | return $rootScope.a; 48 | }; 49 | }]) 50 | .run(["appService", _.noop]); 51 | 52 | var matchedMod = angular.module("app2", []); 53 | var nonMatchedMod = angular.module("app3", []); 54 | 55 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 56 | this.getA = function getA() { 57 | return $rootScope.a; 58 | }; 59 | }]); 60 | 61 | 62 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 63 | this.getA = function getA() { 64 | return $rootScope.a; 65 | }; 66 | }]); 67 | })(); 68 | -------------------------------------------------------------------------------- /test/fixtures/concatenated-separator.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | angular.module("app", ["dep1", "dep2"]) 5 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 6 | $timeout(function () { 7 | $rootScope.a = 2; 8 | }); 9 | $rootScope.b = 2; 10 | }]) 11 | .service("appService", ["$rootScope", function ($rootScope) { 12 | this.getA = function getA() { 13 | return $rootScope.a; 14 | }; 15 | }]) 16 | .run(["appService", _.noop]); 17 | 18 | var matchedMod = angular.module("app2", []); 19 | var nonMatchedMod = angular.module("app3", []); 20 | 21 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 22 | this.getA = function getA() { 23 | return $rootScope.a; 24 | }; 25 | }]); 26 | 27 | 28 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 29 | this.getA = function getA() { 30 | return $rootScope.a; 31 | }; 32 | }]); 33 | })(); 34 | ;(function () { 35 | "use strict"; 36 | 37 | angular.module("app", ["dep1", "dep2"]) 38 | .run(["$rootScope", "$timeout", function ($rootScope, $timeout) { 39 | $timeout(function () { 40 | $rootScope.a = 2; 41 | }); 42 | $rootScope.b = 2; 43 | }]) 44 | .service("appService", ["$rootScope", function ($rootScope) { 45 | this.getA = function getA() { 46 | return $rootScope.a; 47 | }; 48 | }]) 49 | .run(["appService", _.noop]); 50 | 51 | var matchedMod = angular.module("app2", []); 52 | var nonMatchedMod = angular.module("app3", []); 53 | 54 | matchedMod.service("appService", ["$rootScope", function ($rootScope) { 55 | this.getA = function getA() { 56 | return $rootScope.a; 57 | }; 58 | }]); 59 | 60 | 61 | nonMatchedMod.service("appService", ["$rootScope", function ($rootScope) { 62 | this.getA = function getA() { 63 | return $rootScope.a; 64 | }; 65 | }]); 66 | })(); 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-ng-annotate", 3 | "version": "4.0.1-pre", 4 | "description": "Add, remove and rebuild AngularJS dependency injection annotations.", 5 | "homepage": "https://github.com/mgol/grunt-ng-annotate", 6 | "author": { 7 | "name": "Michał Gołębiowski-Owczarek", 8 | "email": "m.goleb@gmail.com" 9 | }, 10 | "keywords": [ 11 | "angular", 12 | "angularjs", 13 | "annotate", 14 | "annotation", 15 | "annotations", 16 | "di", 17 | "dependency", 18 | "injection", 19 | "minify", 20 | "grunt", 21 | "gruntplugin", 22 | "non-intrusive", 23 | "transformation" 24 | ], 25 | "repository": { 26 | "type": "git", 27 | "url": "https://github.com/mgol/grunt-ng-annotate.git" 28 | }, 29 | "bugs": "https://github.com/mgol/grunt-ng-annotate/issues", 30 | "license": "MIT", 31 | "files": [ 32 | "tasks", 33 | "src" 34 | ], 35 | "dependencies": { 36 | "ng-annotate": "^1.2.2" 37 | }, 38 | "devDependencies": { 39 | "babel-core": "6.26.3", 40 | "babel-preset-es2015": "6.24.1", 41 | "convert-source-map": "1.7.0", 42 | "cross-spawn": "7.0.2", 43 | "eslint": "6.8.0", 44 | "eslint-config-mgol": "0.0.47", 45 | "expect.js": "0.3.1", 46 | "grunt": "1.1.0", 47 | "grunt-babel": "7.0.0", 48 | "grunt-cli": "1.3.2", 49 | "grunt-contrib-clean": "2.0.0", 50 | "grunt-contrib-copy": "1.0.0", 51 | "grunt-eslint": "22.0.0", 52 | "grunt-mocha-test": "0.13.3", 53 | "husky": "4.2.3", 54 | "lint-staged": "10.1.2", 55 | "load-grunt-tasks": "5.1.0", 56 | "mocha": "7.1.1", 57 | "prettier": "2.0.3", 58 | "source-map": "0.7.3", 59 | "time-grunt": "2.0.0" 60 | }, 61 | "peerDependencies": { 62 | "grunt": ">=0.4.5" 63 | }, 64 | "scripts": { 65 | "prettier-check": "prettier --check \"**/*.{json,js,yml,yaml,md}\"", 66 | "prettier-format": "prettier --write \"**/*.{json,js,yml,yaml,md}\"", 67 | "test": "npm run prettier-check && grunt --stack" 68 | }, 69 | "engines": { 70 | "node": ">=10" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grunt-ng-annotate 2 | 3 | > Add, remove and rebuild AngularJS dependency injection annotations. Based on [ng-annotate](https://www.npmjs.org/package/ng-annotate). 4 | 5 | **NOTE: `grunt-ng-annotate` is no longer developed similarly to the underlying [ng-annotate](https://www.npmjs.com/package/ng-annotate) package. Switch to [babel-plugin-angularjs-annotate](https://www.npmjs.com/package/babel-plugin-angularjs-annotate) or provide annotations by yourself.** 6 | 7 | [![Build Status](https://travis-ci.org/mgol/grunt-ng-annotate.svg?branch=master)](https://travis-ci.org/mgol/grunt-ng-annotate) 8 | [![Build status](https://ci.appveyor.com/api/projects/status/rr3i854ic8rb47i5/branch/master?svg=true)](https://ci.appveyor.com/project/mgol/grunt-ng-annotate/branch/master) 9 | [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 10 | 11 | ## Getting Started 12 | 13 | This plugin requires Grunt. 14 | 15 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: 16 | 17 | ```shell 18 | npm install grunt-ng-annotate --save-dev 19 | ``` 20 | 21 | Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: 22 | 23 | ```js 24 | grunt.loadNpmTasks('grunt-ng-annotate'); 25 | ``` 26 | 27 | ## Overview 28 | 29 | This project defines the `ngAnnotate` task. In your project's Gruntfile, add a section named `ngAnnotate` to the data object passed into `grunt.initConfig()`. 30 | 31 | ```js 32 | grunt.initConfig({ 33 | ngAnnotate: { 34 | options: { 35 | // Task-specific options go here. 36 | }, 37 | your_target: { 38 | // Target-specific file lists and/or options go here. 39 | }, 40 | }, 41 | }); 42 | ``` 43 | 44 | ## Options 45 | 46 | The `ngAnnotate` task accepts a couple of options: 47 | 48 | ### add 49 | 50 | Tells if ngAnnotate should add annotations. 51 | 52 | Type: `boolean` 53 | 54 | Default: `true` 55 | 56 | ### remove 57 | 58 | Tells if ngAnnotate should remove annotations. 59 | 60 | Type: `boolean` 61 | 62 | Default: `false` 63 | 64 | Note that both `add` and `remove` options can be set to true; in such a case `ngAnnotate` first removes 65 | annotations and then re-adds them (it can be used to check if annotations were provided correctly). 66 | 67 | ### regexp 68 | 69 | If provided, only strings matched by the regexp are interpreted as module names. You can provide both a regular expression and a string representing one. See README of ng-annotate for further details: https://npmjs.org/package/ng-annotate 70 | 71 | Type: `regexp` 72 | 73 | Default: none 74 | 75 | ### singleQuotes 76 | 77 | Switches the quote type for strings in the annotations array to single ones; e.g. `'$scope'` instead of `"$scope"`. 78 | 79 | Type: `boolean` 80 | 81 | Default: `false` 82 | 83 | ### separator 84 | 85 | Concatenated files will be joined on this string. 86 | 87 | Type: `string` 88 | 89 | Default: `grunt.util.linefeed` 90 | 91 | If you're post-processing concatenated JavaScript files with a minifier, you may need to use a semicolon ';' as the separator. 92 | 93 | ### sourceMap 94 | 95 | Enables source map generation. 96 | 97 | Type: `boolean` or `string` 98 | 99 | Default: `false` 100 | 101 | If set to a string, the string points to a file where to save the source map. If set to `true`, an inline source map will be used. 102 | 103 | ### ngAnnotateOptions 104 | 105 | If ngAnnotate supports a new option that is not directly supported via this Grunt task yet, you can pass it here. These options gets merged with the above specific to ngAnnotate. Options passed here have lower precedence to the direct ones described above. 106 | 107 | Type: `object` 108 | 109 | Default: `{}` 110 | 111 | ## Usage Examples 112 | 113 | ```js 114 | grunt.initConfig({ 115 | ngAnnotate: { 116 | options: { 117 | singleQuotes: true, 118 | }, 119 | app1: { 120 | files: { 121 | 'a.js': ['a.js'], 122 | 'c.js': ['b.js'], 123 | 'f.js': ['d.js', 'e.js'], 124 | }, 125 | }, 126 | app2: { 127 | files: [ 128 | { 129 | expand: true, 130 | src: ['f.js'], 131 | ext: '.annotated.js', // Dest filepaths will have this extension. 132 | extDot: 'last', // Extensions in filenames begin after the last dot 133 | }, 134 | ], 135 | }, 136 | app3: { 137 | files: [ 138 | { 139 | expand: true, 140 | src: ['g.js'], 141 | rename: function (dest, src) { 142 | return src + '-annotated'; 143 | }, 144 | }, 145 | ], 146 | }, 147 | }, 148 | }); 149 | 150 | grunt.loadNpmTasks('grunt-ng-annotate'); 151 | ``` 152 | 153 | After executing `grunt ngAnnotate`, you'll get file `a.js` annotated and saved under the same name, file `b.js` annotated and saved as `c.js` and files `d.js` and `e.js` concatenated, annotated and saved as `f.js`. Annotations will be saved using single quotes. 154 | 155 | An annotated version of the `f.js` file will be saved as `f.annotated.js` and an annotated version of the `g.js` file will be saved as `g.js-annotated`. 156 | 157 | ## Supported Node.js versions 158 | 159 | This project aims to support all Node.js versions supported upstream (see [Release README](https://github.com/nodejs/Release/blob/master/README.md) for more details). 160 | 161 | ## Contributing 162 | 163 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). 164 | 165 | ## License 166 | 167 | Copyright (c) 2014 Michał Gołębiowski-Owczarek. Licensed under the MIT license. 168 | -------------------------------------------------------------------------------- /test/spec/api.js: -------------------------------------------------------------------------------- 1 | // Note: we don't need to test full ngAnnotate functionality here as that's already 2 | // tested in ngAnnotate repository. We just need to check if we pass what we should 3 | // to ngAnnotate, as well as our custom options. 4 | 5 | 'use strict'; 6 | 7 | const fs = require('fs'); 8 | const expect = require('expect.js'); 9 | const sourceMap = require('source-map'); 10 | const convertSourceMap = require('convert-source-map'); 11 | 12 | const SourceMapConsumer = sourceMap.SourceMapConsumer; 13 | 14 | const readFile = (path) => 15 | normalizeNewLines(fs.readFileSync(path, { encoding: 'utf8' })); 16 | 17 | const normalizeNewLines = (input) => 18 | input.replace(/\r\n/g, '\n').replace(/\r$/, ''); 19 | 20 | const readTmp = (filename) => readFile(`${__dirname}/../tmp/${filename}`); 21 | 22 | const readFix = (filename) => readFile(`${__dirname}/../fixtures/${filename}`); 23 | 24 | describe('grunt-ng-annotate API', () => { 25 | it('should add annotations by default and not remove ones', () => { 26 | expect(readTmp('partially-annotated-messy-default.js')).to.be( 27 | readFix('annotated-messy.js'), 28 | ); 29 | }); 30 | 31 | it('should add annotations when `add: true`', () => { 32 | expect(readTmp('not-annotated.js')).to.be(readFix('annotated.js')); 33 | }); 34 | 35 | it('should remove annotations when `remove: true`', () => { 36 | expect(readTmp('annotated.js')).to.be(readFix('not-annotated.js')); 37 | }); 38 | 39 | it('should both add and remove annotations when `add: true, remove: true`', () => { 40 | expect(readTmp('partially-annotated-messy-addremove.js')).to.be( 41 | readFix('annotated.js'), 42 | ); 43 | }); 44 | 45 | it('should annotate only modules matching regexp', () => { 46 | expect(readTmp('not-annotated-regexp.js')).to.be( 47 | readFix('annotated-regexp.js'), 48 | ); 49 | }); 50 | 51 | it('should concatenate source files and save into the destination path', () => { 52 | expect(readTmp('concatenated.js')).to.be(readFix('concatenated.js')); 53 | }); 54 | 55 | it('should concatenate source files with separator and save to destination path', () => { 56 | expect(readTmp('concatenated-separator.js')).to.be( 57 | readFix('concatenated-separator.js'), 58 | ); 59 | }); 60 | 61 | it('should respect the `singleQuotes` setting', () => { 62 | expect(readTmp('not-annotated-singlequotes.js')).to.be( 63 | readFix('annotated-single.js'), 64 | ); 65 | }); 66 | 67 | it('should pass the `ngAnnotateOptions` object to ngAnnotate', () => { 68 | expect(readTmp('not-annotated-ngannotateoptions.js')).to.be( 69 | readFix('annotated-single.js'), 70 | ); 71 | }); 72 | 73 | it('should pass the correct options when using multiple input sources', () => { 74 | expect(readTmp('multiple-1.js')).to.be(readFix('not-annotated.js')); 75 | expect(readTmp('multiple-2.js')).to.be(readFix('not-annotated.js')); 76 | }); 77 | 78 | it('should successfully overwrite files if requested', () => { 79 | expect(readTmp('overwritten.js')).to.be(readFix('annotated.js')); 80 | }); 81 | 82 | describe('source maps', () => { 83 | const getSourcePart = (source) => 84 | source.replace(/\n\/\/# sourceMappingURL=\S+/, ''); 85 | 86 | it('should generate an inline source map by default', async () => { 87 | const generated = readTmp('not-annotated-source-map.js'); 88 | const existingMap = convertSourceMap 89 | .fromSource(generated) 90 | .toObject(); 91 | const smc = await new SourceMapConsumer(existingMap); 92 | 93 | expect(smc.sources).to.eql(['../fixtures/not-annotated.js']); 94 | expect(smc.sourcesContent).to.eql([ 95 | readFix('../fixtures/not-annotated.js'), 96 | ]); 97 | 98 | expect(getSourcePart(generated).trim()).to.be( 99 | readFix('annotated.js').trim(), 100 | ); 101 | 102 | expect( 103 | smc.originalPositionFor({ 104 | line: 5, 105 | column: 63, 106 | }), 107 | ).to.eql({ 108 | line: 5, 109 | column: 35, 110 | source: smc.sources[0], 111 | name: null, 112 | }); 113 | 114 | smc.destroy(); 115 | }); 116 | 117 | it('should generate an external source map when asked', async () => { 118 | const generated = readTmp('not-annotated-source-map-external.js'); 119 | const smc = await new SourceMapConsumer( 120 | readTmp('not-annotated-source-map-external.js.map'), 121 | ); 122 | 123 | expect(getSourcePart(generated).trim()).to.be( 124 | readFix('annotated.js').trim(), 125 | ); 126 | 127 | expect(smc.sources).to.eql(['../fixtures/not-annotated.js']); 128 | expect(smc.sourcesContent).to.eql([readFix('not-annotated.js')]); 129 | 130 | smc.destroy(); 131 | }); 132 | 133 | it('should combine source maps', async () => { 134 | const generated = readTmp('not-annotated-es6-source-map.js'); 135 | 136 | expect(getSourcePart(generated).trim()).to.be( 137 | readFix('annotated-es6.js').trim(), 138 | ); 139 | 140 | const existingMap = convertSourceMap 141 | .fromSource(generated) 142 | .toObject(); 143 | const smc = await new SourceMapConsumer(existingMap); 144 | 145 | expect(smc.sources).to.eql([ 146 | 'not-annotated-es6.js', 147 | '../fixtures/not-annotated-es6.js', 148 | ]); 149 | 150 | expect( 151 | smc.originalPositionFor({ 152 | line: 9, 153 | column: 19, 154 | }), 155 | ).to.eql({ 156 | line: 8, 157 | column: 22, 158 | source: smc.sources[smc.sources.length - 1], 159 | name: 'uselessConstant', 160 | }); 161 | 162 | smc.destroy(); 163 | }); 164 | }); 165 | }); 166 | -------------------------------------------------------------------------------- /tasks/ng-annotate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * grunt-ng-annotate 3 | * https://github.com/mzgol/grunt-ng-annotate 4 | * 5 | * Author Michał Gołębiowski-Owczarek 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | const path = require('path'); 12 | const ngAnnotate = require('ng-annotate'); 13 | 14 | module.exports = function (grunt) { 15 | const getPathFromTo = (fromFile, toFile) => 16 | path 17 | .relative( 18 | path.resolve(path.dirname(fromFile)), 19 | path.resolve(toFile), 20 | ) 21 | // URLs should have UNIX-y paths. 22 | .replace(/\\+/g, '/'); 23 | 24 | const handleOptions = (options) => { 25 | const finalOptions = { 26 | ...options, 27 | ngAnnotateOptions: { 28 | ...options.ngAnnotateOptions, 29 | }, 30 | }; 31 | 32 | if (finalOptions.add == null) { 33 | finalOptions.ngAnnotateOptions.add = true; 34 | } else { 35 | finalOptions.ngAnnotateOptions.add = finalOptions.add; 36 | delete finalOptions.add; 37 | } 38 | 39 | if (finalOptions.remove == null) { 40 | finalOptions.ngAnnotateOptions.remove = false; 41 | } else { 42 | finalOptions.ngAnnotateOptions.remove = finalOptions.remove; 43 | delete finalOptions.remove; 44 | } 45 | 46 | if (finalOptions.regexp != null) { 47 | finalOptions.ngAnnotateOptions.regexp = finalOptions.regexp; 48 | delete finalOptions.regexp; 49 | } 50 | 51 | if (finalOptions.singleQuotes != null) { 52 | finalOptions.ngAnnotateOptions.single_quotes = 53 | finalOptions.singleQuotes; 54 | delete finalOptions.singleQuotes; 55 | } 56 | 57 | if (finalOptions.separator != null) { 58 | finalOptions.ngAnnotateOptions.separator = options.separator; 59 | delete finalOptions.separator; 60 | } 61 | 62 | if (finalOptions.sourceMap) { 63 | finalOptions.ngAnnotateOptions.map = { 64 | inline: options.sourceMap === true, 65 | }; 66 | } 67 | 68 | if (options.transformDest != null) { 69 | grunt.fail.fatal( 70 | [ 71 | 'The `transformDest` option is no longer supported.', 72 | 'The following configuration:', 73 | '', 74 | ' app: {', 75 | ' options: {', 76 | ' transformDest: function (srcPath) {', 77 | ' return doSomethingWithSrcPath(srcPath);', 78 | ' },', 79 | ' },', 80 | " src: ['app/*.js'],", 81 | ' },', 82 | '', 83 | 'should be replaced by:', 84 | '', 85 | ' app: {', 86 | ' files: [', 87 | ' {', 88 | ' expand: true,', 89 | " src: ['app/*.js'],", 90 | ' rename: function (destPath, srcPath) {', 91 | ' return doSomethingWithSrcPath(srcPath);', 92 | ' },', 93 | ' },', 94 | ' ],', 95 | ' },', 96 | ].join('\n'), 97 | ); 98 | } 99 | 100 | if (options.outputFileSuffix != null) { 101 | grunt.fail.fatal( 102 | [ 103 | 'The `outputFileSuffix` option is no longer supported.', 104 | 'The following configuration:', 105 | '', 106 | ' app: {', 107 | ' options: {', 108 | " outputFileSuffix: '-annotated',", 109 | ' },', 110 | " src: ['app/*.js'],", 111 | ' },', 112 | '', 113 | 'should be replaced by:', 114 | '', 115 | ' app: {', 116 | ' files: [', 117 | ' {', 118 | ' expand: true,', 119 | " src: ['app/*.js'],", 120 | ' rename: function (destPath, srcPath) {', 121 | " return srcPath + '-annotated';", 122 | ' },', 123 | ' },', 124 | ' ],', 125 | ' },', 126 | ].join('\n'), 127 | ); 128 | } 129 | 130 | return finalOptions; 131 | }; 132 | 133 | grunt.registerMultiTask( 134 | 'ngAnnotate', 135 | 'Add, remove and rebuild AngularJS dependency injection annotations', 136 | 137 | function () { 138 | let filesNum = 0; 139 | let validRun = true; 140 | // Merge task-specific and/or target-specific options with these defaults. 141 | const options = handleOptions(this.options()); 142 | 143 | const runNgAnnotate = (mapping, options) => { 144 | filesNum++; 145 | 146 | const ngAnnotateOptions = { 147 | ...options.ngAnnotateOptions, 148 | ...(options.ngAnnotateOptions.map 149 | ? { 150 | map: { 151 | ...options.ngAnnotateOptions.map, 152 | }, 153 | } 154 | : {}), 155 | }; 156 | 157 | if (ngAnnotateOptions.map) { 158 | if (mapping.src.length > 1) { 159 | grunt.fail.fatal( 160 | "The ngAnnotate task doesn't support " + 161 | 'source maps with many-to-one mappings.', 162 | ); 163 | } 164 | 165 | ngAnnotateOptions.map.inFile = getPathFromTo( 166 | mapping.dest, 167 | mapping.src[0], 168 | ); 169 | } 170 | 171 | // seperator for file concatenation; defaults to linefeed 172 | const separator = 173 | typeof ngAnnotateOptions.separator === 'string' 174 | ? ngAnnotateOptions.separator 175 | : grunt.util.linefeed; 176 | 177 | const concatenatedSource = mapping.src 178 | .map((file) => grunt.file.read(file)) 179 | .join(separator); 180 | 181 | const ngAnnotateOutput = ngAnnotate( 182 | concatenatedSource, 183 | ngAnnotateOptions, 184 | ); 185 | 186 | // Write the destination file. 187 | if (ngAnnotateOutput.errors) { 188 | grunt.log.write( 189 | `Generating "${mapping.dest}" from: "${mapping.src.join( 190 | '", "', 191 | )}"...`, 192 | ); 193 | grunt.log.error(); 194 | ngAnnotateOutput.errors.forEach((error) => { 195 | grunt.log.error(error); 196 | }); 197 | return false; 198 | } 199 | 200 | // Write ngAnnotate output (and a source map if requested) to the target file. 201 | 202 | if (ngAnnotateOptions.map && !ngAnnotateOptions.map.inline) { 203 | ngAnnotateOutput.src += `\n//# sourceMappingURL=${getPathFromTo( 204 | mapping.dest, 205 | options.sourceMap, 206 | )}`; 207 | grunt.file.write(options.sourceMap, ngAnnotateOutput.map); 208 | } 209 | 210 | grunt.file.write(mapping.dest, ngAnnotateOutput.src); 211 | 212 | return true; 213 | }; 214 | 215 | // Iterate over all specified file groups. 216 | this.files.forEach((mapping) => { 217 | if (!runNgAnnotate(mapping, options)) { 218 | validRun = false; 219 | } 220 | }); 221 | 222 | if (validRun) { 223 | if (filesNum < 1) { 224 | grunt.log.ok('No files provided to the ngAnnotate task.'); 225 | } else { 226 | grunt.log.ok( 227 | `${ 228 | filesNum + (filesNum === 1 ? ' file' : ' files') 229 | } successfully annotated.`, 230 | ); 231 | } 232 | } 233 | return validRun; 234 | }, 235 | ); 236 | }; 237 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * grunt-ng-annotate 3 | * https://github.com/mgol/grunt-ng-annotate 4 | * 5 | * Author Michał Gołębiowski-Owczarek 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | const spawn = require('cross-spawn'); 12 | 13 | module.exports = function (grunt) { 14 | require('time-grunt')(grunt); 15 | 16 | grunt.initConfig({ 17 | clean: { 18 | test: { 19 | src: ['test/tmp'], 20 | }, 21 | }, 22 | 23 | babel: { 24 | testPreparation: { 25 | options: { 26 | sourceMap: 'inline', 27 | }, 28 | files: [ 29 | { 30 | dest: 'test/tmp/not-annotated-es6.js', 31 | src: 'test/fixtures/not-annotated-es6.js', 32 | }, 33 | ], 34 | }, 35 | }, 36 | 37 | copy: { 38 | testPreparation: { 39 | files: [ 40 | { 41 | dest: 'test/tmp/overwritten.js', 42 | src: 'test/fixtures/not-annotated.js', 43 | }, 44 | ], 45 | }, 46 | }, 47 | 48 | eslint: { 49 | all: { 50 | src: ['Gruntfile.js', 'src', 'tasks', 'test'], 51 | }, 52 | }, 53 | 54 | // Configuration to be run (and then tested). 55 | ngAnnotate: { 56 | options: { 57 | ngAnnotateOptions: {}, 58 | }, 59 | default: { 60 | files: [ 61 | { 62 | dest: 'test/tmp/partially-annotated-messy-default.js', 63 | src: 'test/fixtures/partially-annotated-messy.js', 64 | }, 65 | ], 66 | }, 67 | add: { 68 | options: { 69 | add: true, 70 | remove: false, 71 | }, 72 | files: [ 73 | { 74 | dest: 'test/tmp/not-annotated.js', 75 | src: 'test/fixtures/not-annotated.js', 76 | }, 77 | ], 78 | }, 79 | remove: { 80 | options: { 81 | add: false, 82 | remove: true, 83 | }, 84 | files: [ 85 | { 86 | dest: 'test/tmp/annotated.js', 87 | src: 'test/fixtures/annotated.js', 88 | }, 89 | ], 90 | }, 91 | addRemove: { 92 | options: { 93 | add: true, 94 | remove: true, 95 | }, 96 | files: [ 97 | { 98 | dest: 'test/tmp/partially-annotated-messy-addremove.js', 99 | src: 'test/fixtures/partially-annotated-messy.js', 100 | }, 101 | ], 102 | }, 103 | regexp: { 104 | options: { 105 | add: true, 106 | remove: false, 107 | regexp: /^matchedMod$/, 108 | }, 109 | files: [ 110 | { 111 | dest: 'test/tmp/not-annotated-regexp.js', 112 | src: 'test/fixtures/not-annotated.js', 113 | }, 114 | ], 115 | }, 116 | srcDest: { 117 | files: [ 118 | { 119 | dest: 'test/tmp/concatenated.js', 120 | src: [ 121 | 'test/tmp/not-annotated.js', 122 | 'test/tmp/annotated.js', 123 | ], 124 | }, 125 | ], 126 | }, 127 | srcDestSeparator: { 128 | options: { 129 | separator: ';', 130 | }, 131 | files: [ 132 | { 133 | dest: 'test/tmp/concatenated-separator.js', 134 | src: [ 135 | 'test/tmp/not-annotated.js', 136 | 'test/tmp/annotated.js', 137 | ], 138 | }, 139 | ], 140 | }, 141 | singleQuotes: { 142 | options: { 143 | add: true, 144 | remove: false, 145 | singleQuotes: true, 146 | }, 147 | files: [ 148 | { 149 | dest: 'test/tmp/not-annotated-singlequotes.js', 150 | src: 'test/fixtures/not-annotated.js', 151 | }, 152 | ], 153 | }, 154 | sourceMap: { 155 | options: { 156 | add: true, 157 | remove: false, 158 | sourceMap: true, 159 | }, 160 | files: [ 161 | { 162 | dest: 'test/tmp/not-annotated-source-map.js', 163 | src: 'test/fixtures/not-annotated.js', 164 | }, 165 | ], 166 | }, 167 | sourceMapNotInline: { 168 | options: { 169 | add: true, 170 | remove: false, 171 | sourceMap: 172 | 'test/tmp/not-annotated-source-map-external.js.map', 173 | }, 174 | files: [ 175 | { 176 | dest: 'test/tmp/not-annotated-source-map-external.js', 177 | src: 'test/fixtures/not-annotated.js', 178 | }, 179 | ], 180 | }, 181 | sourceMapCombined: { 182 | options: { 183 | add: true, 184 | remove: false, 185 | sourceMap: true, 186 | }, 187 | files: [ 188 | { 189 | dest: 'test/tmp/not-annotated-es6-source-map.js', 190 | src: 'test/tmp/not-annotated-es6.js', 191 | }, 192 | ], 193 | }, 194 | ngAnnotateOptions: { 195 | options: { 196 | singleQuotes: true, 197 | }, 198 | files: [ 199 | { 200 | dest: 'test/tmp/not-annotated-ngannotateoptions.js', 201 | src: 'test/fixtures/not-annotated.js', 202 | }, 203 | ], 204 | }, 205 | multipleFileSources: { 206 | options: { 207 | add: false, 208 | remove: true, 209 | }, 210 | files: [ 211 | { 212 | expand: true, 213 | cwd: 'test/fixtures', 214 | src: ['multiple-1.js', 'multiple-2.js'], 215 | dest: 'test/tmp', 216 | }, 217 | ], 218 | }, 219 | overwrittenSource: { 220 | options: { 221 | add: true, 222 | remove: false, 223 | }, 224 | files: [ 225 | { 226 | dest: 'test/tmp/overwritten.js', 227 | src: 'test/tmp/overwritten.js', 228 | }, 229 | ], 230 | }, 231 | }, 232 | 233 | // Unit tests. 234 | mochaTest: { 235 | all: { 236 | options: { 237 | reporter: 'spec', 238 | }, 239 | src: 'test/spec/*.js', 240 | }, 241 | }, 242 | }); 243 | 244 | // Load all grunt tasks matching the `grunt-*` pattern. 245 | require('load-grunt-tasks')(grunt); 246 | 247 | // Load this plugin's task(s). 248 | grunt.loadTasks('tasks'); 249 | 250 | grunt.registerTask('lint', ['eslint']); 251 | 252 | grunt.registerTask('testPreparation', [ 253 | 'copy:testPreparation', 254 | 'babel:testPreparation', 255 | ]); 256 | 257 | grunt.registerTask('test', ['mochaTest']); 258 | 259 | grunt.registerTask('ngAnnotateAndTestSpawned', function () { 260 | const done = this.async(); 261 | 262 | spawn('grunt', ['ngAnnotate', 'test'], { 263 | cwd: __dirname, 264 | stdio: 'inherit', 265 | }).on('close', (code) => { 266 | if (code === 0) { 267 | done(); 268 | return; 269 | } 270 | grunt.log.error(`'\`grunt ngAnnotate\` failed with code ${code}`); 271 | done(false); 272 | }); 273 | }); 274 | 275 | // By default, lint and run tests. 276 | grunt.registerTask('default', [ 277 | 'clean', 278 | 'lint', 279 | 'testPreparation', 280 | 'ngAnnotateAndTestSpawned', 281 | ]); 282 | }; 283 | --------------------------------------------------------------------------------