grunt-angular-annotator

Generates Angular injection annotations for Controllers, Factories and Services

npm install grunt-angular-annotator
3 downloads in the last week
18 downloads in the last month

grunt-angular-annotator

Generates Angular declarations for Factories, Services and Controllers

Getting Started

This plugin requires Grunt ~0.4.0

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-angular-annotator --save-dev

One the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks('grunt-angular-annotator');

The "angular" task

Overview

Annotates your Service, Factory and Controller objects for Angular dependency injection. Eliminates the need to maintain redundant boilerplate code for each object.

You write this:

module = angular.module 'MyModule', []

MyService = ($http, $q) ->
  # service implementation

MyOtherServiceFactory = ($resource, MyService) ->
  # factory implementation for MyOtherService

MyController = ($location, MyOtherService) ->
  # controller implementation

and this plugin takes care of inserting the appropriate Angular declarations to your JavaScript each time you build:

module.service('MyService', ['$http','$q']);
module.factory('MyOtherService', ['$resource','MyService', MyOtherServiceFactory]);
module.controller('MyController', ['$location','MyOtherService', MyController]);

Background

We are developing our user interface using AngularJS and CoffeeScript. All of our source code files have the following structure:

module = angular.module 'SomeModule', ['Module Dependency A', 'Module Dependency B']

# factory method for SomeService
SomeService = ($http, $q, AnotherOneOfOurServices) ->

  serviceMethodA: (arg1, arg2) ->
    return ...

  serviceMethodB: (arg1, arg2) ->
    return ...

module.service 'SomeService', ['$http', '$q', 'AnotherOneOfOurServices', SomeService]

The same basic pattern applies for Factory and Controller objects.

Needless to say, the need to manually keep the Angular object declaration in sync with the factory method parameters gets annoying very quickly. If you modify the factory method arguments (add, remove or rearrange parameters) but fail to update the Angular object declaration to match, Angular does not complain. Instead you wind up with shifted and/or undefined parameter values at runtime, accompanied by some potentially head-scratching errors.

This plugin addresses this problem by automatically inserting the Angular object declarations as part of your Grunt build. It does not modify your source code. For CoffeeScript developers, it modifies the JavaScript files generated by the compiler. Pure JavaScript developers can achieve the same effect by simply copying their source files before running the annotators.

Setup

In your project's Gruntfile, add a section named angular to the data object passed into grunt.initConfig(). The src property should expand to the set of JavaScript files generated by the CoffeeScript compiler (or to copies of your original JavaScript code):

grunt.initConfig({

    coffee: {
      compile: {
        files: [{
          expand: true,
          cwd: 'src',
          src: ['**/*.coffee'],
          dest: 'tmp',
          ext: '.js'
        }]
      }
    },

    angular: {
      postcompile: {
        src: [ 'tmp/**/*.js' ]
      }
    },
})

As long as you follow the conventions outlined below, you can then remove the manual angular.factory, angular.service and angular.controller declarations from your source code.

Gotchas

At this point, this annotator relies on several assumptions about your JavaScript or CoffeeScript source code files:

  1. Each file contains source code for a single module
  2. The variable module refers to the angular module for the current file
  3. All of your controller objects end in the suffix Controller
  4. All of your directive methods end in the suffix Directive
  5. All of your service objects end in the suffix Service
  6. All of your factory methods end in the suffix Factory
  7. The service obtained from a factory object has the same name as the factory object, without the Factory suffix.

These seem like decent conventions to me, but I'm open to making it more flexible.

In addition to injectable objects, the annotator also handles methods invoked via angular.run and angular.config. Simple replace this:

module.run(['$resource','MyService', function($resource, MyService) {
  // do some application initialization here
}]);

with this:

MyRun = function($resource, MyService) {
  // do some application initialization here
};

Any method that ends in Run or Config will get annotated appropriately. ('Init' would be a nicer suffix than 'Run', but for the sake of consistency with angular I won't rock the boat).

Note that this annotator also modifies JavaScript files in place. This works well for modifying the output of the CoffeeScript compiler. If you code in JavaScript, you should first copy your source files and then modify the copies in place. I'm also open to incorporating this into the annotator by looking for an optional dest property.

Options

None at this time

Usage Examples

See the Gruntfile.js in the project source code for a configuration example.

Contributing

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.

Release History

0.0.1 Initial release

0.0.2 Fix handling of methods with no injected dependencies; added support for Directives, Controllers, Config and Run methods; renamed task from angularAnnotate to just angular

npm loves you