Giter Site home page Giter Site logo

schmod / babel-plugin-angularjs-annotate Goto Github PK

View Code? Open in Web Editor NEW

This project forked from olov/ng-annotate

241.0 241.0 27.0 2 MB

Add Angular 1.x dependency injection annotations to ES6 code

Home Page: http://schmod.github.io/babel-plugin-angularjs-annotate

License: MIT License

JavaScript 100.00%
angularjs babel babel-plugin dependency-injection javascript

babel-plugin-angularjs-annotate's People

Contributors

andrey-skl avatar anotherchrisberry avatar craigburke avatar duncanbeevers avatar fracz avatar frapontillo avatar groner avatar guria avatar mastilver avatar noppa avatar olov avatar pgilad avatar pioug avatar rmariuzzo avatar rubensayshi avatar sbrunner avatar schmod avatar sdorra avatar siebertm avatar smrq avatar treymack avatar tyson-benson avatar wileam avatar xdissent avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

babel-plugin-angularjs-annotate's Issues

Does not work with async functions

We are using babel-preset-env and this plugin; no other presets or plugins.

Given the source...

const myFunction = async someService => {
  'ngInject'
  // ...
}

the output from babel is this...

var myFunction = function () {
  var _ref = _asyncToGenerator(regeneratorRuntime.mark(['someService', function _callee(someService) {
    'ngInject';
    // ...

    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
          case 'end':
            return _context.stop();
        }
      }
    }, _callee, undefined);
  }]));

  return function myFunction(_x) {
    return _ref.apply(this, arguments);
  };
}();
myFunction.$inject = ['_x'];

I see 3 problems with this:

  1. myFunction.$inject should be set with ['someService'] rather than ['_x']
  2. The function wrapped with ['someService', ...] should be myFunction rather than _callee
  3. We don't need/want annotation via both inline array way and $inject property way.

I believe the desired output would be something like so...

var myFunction = ['someService', function () {
  var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(someService) {
    'ngInject';
    // ...

    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
          case 'end':
            return _context.stop();
        }
      }
    }, _callee, undefined);
  }));

  return function myFunction(_x) {
    return _ref.apply(this, arguments);
  };
}()];

I thought the problem may be that the transforms for async/await are being applied first, but apparently that is not so:

Plugins run before Presets.
Plugin ordering is first to last.
Preset ordering is reversed (last to first).

Source: https://babeljs.io/docs/plugins/#plugin-preset-ordering

@schmod Any ideas how to get around this? (Thanks for stepping up to give ng-annotate es6 support btw. I think this package will catch on and be greatly appreciated by the community!)

Option for a decorator

Making this possible:

@inject('$q')
class Controller {
    constructor() {
        console.log(this.$q);
    }
}

Underscore "_" breaks annotations when "@babel/plugin-proposal-class-properties" is used

  1. Have a babel setup that transforms class properties. For example, babel/preset-env
  2. Have the following code, where a function is assigned as a class property AND variable with same name as injected dependency is used inside:
const serviceModule = angular.module('serviceservice', []);

class Service {
  constructor($location) {
    this.$inject = {$location: $location};
  }


  reload = () => {
    const $location = this.$inject.$location;
    const query = $location.search().query;
  };
}

serviceModule.service('service', Service);
  1. Try to handle this case with 'babel-plugin-angularjs-annotate'. See reproduction here

Expected: $location is properly annotated
Actual: $location is renamed to _$location by @babel/plugin-proposal-class-properties transformer. Then babel-plugin-angularjs-annotate fails to handle it:

const serviceModule = angular.module("serviceservice", []);

class Service {
  constructor(_$location) {
    this.reload = async () => {
      const { $location } = this.$inject;
      const query = $location.search().query;
    };

    this.$inject = {
      $location: _$location
    };
  }
}

Service.$inject = ["_$location"];
serviceModule.service("service", Service);

Possible solution: maybe babel-plugin-angularjs-annotate can automatically detect that argument was renamed with adding "_" and rename it back when constructing $inject?

The babel package shouldn't be a dependency

Currently this plugin has the babel package as a dependency and it shouldn't. Plugin packages may declare the packages they need to work in peerDependencies or not declare at all since it's important that all plugins use the same package and not their own copies.

Other Babel plugins don't include babel as a dependency.

Usage instructions in .babelrc are non-standard

The README mentions the way to add the plugin to .babelrc:

{
  "presets": ["es2015"],
  "plugins": ["path/to/babel-ng-annotate"]
}

However, that seems like an anti-pattern; people shouldn't depend on specific paths to the plugin (especially that the babel-ng-annotate doesn't match the name of the plugin), they should just use the plugin name as with every other plugin:

{
  "presets": ["es2015"],
  "plugins": ["angularjs-annotate"]
}

babel 7 support

I'm currently modernising an angular 1.5 app

I would like to use babel 7 but this plugin has not been updated, are there any plans for this update?

Support for @ngInject within JSDoc blocks

Hi,

I was wondering if there's any chance you could consider supporting JSDoc/NGDoc multiline comments with explicit @ngInject annotation:

  /**
   * Example
   * @someannotation
   * @ngInject
   */
  class svc {}

I've made a simple pull request but I'm quite overwhelmed with tests, made just one for ES2015 code. Submitting shortly.

Use implicit mode to add `ngInject` annotations

Create a mode for developers to "retrofit" an existing code-base to use explicit annotations.

This mode should use our "implicit" matching to find all of the locations where we think that annotations belong. Instead of adding the $inject annotations in these places, we should then add the 'ngInject' directives that would be necessary to use this plugin in "explicit-only" mode.

In practice, this transformation would be run against an entire codebase (with no other transformations), manually reviewed by a human, and the results would then be checked into source control.

Ideally, this should also convert /* @ngInject */ to 'ngInject'; wherever possible.


As a follow-up, also add a "verify" mode that scans existing code for missing 'ngInject' directives, and prints a warning or error.

Along with strictDi, this brings us most of the benefits of disabling "implicit" matching, while also providing a layer of safety to warn developers when they forget to add 'ngInject' to their code.

"Cannot set property '$inject' of undefined" with explicit es6 class annotation

Hi I'm having a module which has following look:

export default class ExampleClass {
  constructor(customService) {
    'ngInject';

    this.customService = customService;
  }
}

ErrorType.serviceName = 'ERROR_TYPE';

For some reason, in generated code, ExampleClass.$inject = ['customService']; appears before ExampleClass function definition.

remove/reuse existing $inject expressions

The following test-case from the original ng-annotate does not yet pass with the Babel plugin:

Ctrl1.$inject = ["serviceName"];
// @ngInject
// already has .$inject array (before function definition)
function Ctrl1(a) {
}

// @ngInject
// already has .$inject array (after function definition)
function Ctrl2(a) {
}
Ctrl2.$inject = ["serviceName"];

function outer() {
    MyCtrl["$inject"] = ["asdf"];
    return {
        controller: MyCtrl,
    };

    // @ngInject
    function MyCtrl(a) {
    }
}

We need to detect existing $inject statements, and remove and/or correct them. (If there's a conflict, we should probably also print a warning)

codeFrame is not a function

I'm getting this error when I build using webpack.

ERROR in ./controllers/_config.js Module build failed (from ./node_modules/babel-loader/lib/index.js): TypeError: codeFrame is not a function at isAnnotatedArray (C:\xampp\htdocs\Mininfy app\apartment-management-system\ApartmentManagementSystemUI\node_modules\babel-plugin-angularjs-annotate\nginject.js:401:23) at Object.inspectFunction (C:\xampp\htdocs\Mininfy app\apartment-management-system\ApartmentManagementSystemUI\node_modules\babel-plugin-angularjs-annotate\nginject.js:104:9) at PluginPass.enter (C:\xampp\htdocs\Mininfy app\apartment-management-system\ApartmentManagementSystemUI\node_modules\babel-plugin-angularjs-annotate\babel-ng-annotate.js:103:20)

webpack config:

` module: {
rules : [
{
test : /controllers.*.js$/,
use : [

      {
        loader : 'babel-loader',
        query: {
          plugins: ['angularjs-annotate'],
          presets: ['@babel/preset-env']
      }
      }
    ]
  },
  {
    test : /src.*\.tpl\.html$/,
    use  : [
      {
        loader : 'raw-loader'
      }
    ]
  }
],

},`

Block unsafe use of arrow functions

Arrow functions cannot be safely used in providers or services, because these types are intended to be invoked with the new operator, and expect to have their own value of this.

We should discourage (or outright disallow) people from doing this, because the breakages that it causes could lead to subtle and unpredictable bugs.

Cannot set property $inject of function SomeController which has only a getter

Hi everyone, I've faced with the issue when using babel-plugin-angularjs-annotate plugin v.0.10.0.
I've received an error:

**Console**
Uncaught TypeError: Cannot set property $inject of function SomeController($scope, $state) {
...<omitted>... } which has only a getter

SomeController.js

const module = angular.module('module1', []);
export default class SomeController {
  static get $inject() {
    return ['$scope', '$state'];
  }
  constructor($scope, $state) {
    this.$scope = $scope;
    this.$state = $state;
}
module.controller('SomeController', SomeController);

.babelrc

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-proposal-class-properties", "angularjs-annotate"]
}

What is wrong in my config?

reference-following does not handle re-assigned variables

We currently do not handle cases like this:

var ctrl = function(d){};
ctrl = function(e){}

var c1 = {
    controller: ctrl
}

ctrl = function(f){};

var c2 = {
    controller: ctrl, 
}

angular
    .module("myMod", [])
    .component("c1", c1)
    .component("c2", c2);

Output:

var ctrl = function(d){};
ctrl.$inject = ["d"];
ctrl = function(e){}

var c1 = {
    controller: ctrl
}

ctrl = function(f){};

var c2 = {
    controller: ctrl, 
}

angular
    .module("myMod", [])
    .component("c1", c1)
    .component("c2", c2);

Realistically, this will be difficult/impossible to infer statically, so it may not even be worth bothering to correct the test case above (which can be inferred statically).

Babel tells us that ctrl can not be treated like a constant, and it may be sufficient to simply print a warning whenever we try to follow a mutable reference.

Not working when some property of the class has a Decorator

If your class has a Decorator, then the plugin skips the transformation.

It works for everything else. Tested changing the /* @ngInject */ comment to different places.

I'm using babel 7

class DashboardController {
/* @ngInject */
  constructor(
    private $q: ng.IQService,
    private attendanceEventService: IAttendanceEventService,
    private caseService: CaseService,
    private holidayService: HolidayService,
    private attendanceService: IAttendanceService,
    private employeeService: EmployeeService
  ) {
  }

  @AuthorizeDecorator.authorize(['getSomething'])
  getSomething() {
    ...
  }
}

This is the output from babel:

var dashboard__dec, dashboard__class;

function dashboard__applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
  var desc = {};
  Object['ke' + 'ys'](descriptor).forEach(function(key) {
    desc[key] = descriptor[key];
  });
  desc.enumerable = !!desc.enumerable;
  desc.configurable = !!desc.configurable;
  if ('value' in desc || desc.initializer) {
    desc.writable = true;
  }
  desc = decorators.slice().reverse().reduce(function(desc, decorator) {
    return decorator(target, property, desc) || desc;
  }, desc);
  if (context && desc.initializer !== void 0) {
    desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
    desc.initializer = undefined;
  }
  if (desc.initializer === void 0) {
    Object['define' + 'Property'](target, property, desc);
    desc = null;
  }
  return desc;
}

let DashboardController = (dashboard__dec = identity[b].authorize(['getSomething']), (
  dashboard__class = class DashboardController {
    /*@ngInject*/
    constructor($q, attendanceEventService, caseService, holidayService, attendanceService, employeeService) {
      this.$q = $q;
      this.attendanceEventService = attendanceEventService;
      this.caseService = caseService;
      this.holidayService = holidayService;
      this.attendanceService = attendanceService;
      this.employeeService = employeeService;
    }

    getSomething() {
      // ...
    }

  }, (dashboard__applyDecoratedDescriptor(dashboard__class.prototype, 
    \"getSomething\", 
    [dashboard__dec], 
    Object.getOwnPropertyDescriptor(dashboard__class.prototype, \"getSomething\"), 
    dashboard__class.prototype)), dashboard__class));

thanks

"Module 'xxx' is not available!" errors when converting from ngAnnotate

I'm updating libraries on a legacy project. Our build system relies on gulp and i've installed gulp-babel, babel-core etc and the scripts run. However the app fails with Module '[module name]' is not available! errors. I assume that babel is doing more under the hood than ngAnnotate was and it's causing some issues. I've tried changing settings in my .babelrc file, but that hasn't helped. Here's my current configuration.

.babelrc...

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["ie >= 10"],
        "modules": false,
        "debug": true
      }
    }]
  ],
  "plugins": ["angularjs-annotate"]
}

application coffee script gulp task...

gulp.task('appJs', function(cb) {

  function templates(){
    return gulp
      .src(['./src/**/*.html'])
      .pipe(changed('./dev/js'))
      .pipe(flatten())
      .pipe(
        htmlmin({
          collapseWhitespace: true,
          removeComments: true,
          removeAttributeQuotes: true
        })
      )
      .pipe(
        angularTemplatecache({
          module: 'pvdm.core.templates'
        })
      )
  }

  function coffeescript(){
    return gulp
      .src(['!./src/**/*spec.coffee','./src/**/*module.coffee','./src/**/*.coffee'])
      .pipe(changed('./dev/js'))
      .pipe(coffee())
      .pipe(babel())
  }

  return eventStream
    .merge(templates(), coffeescript())
    .pipe(concat('app.js'))
    .pipe(gulp.dest('./dev/js'))

});

vendor js gulp task

gulp.task('vendorJs', function(cb){
  return gulp.src(config.vendor_js)
    .pipe(changed('./dev/js'))
    .pipe(concat('vendor.js'))
    .pipe(babel())
    .pipe(gulp.dest('./dev/js'));
});

Unit tests failing since `@babel/plugin-transform-classes` 7.16.5

Since@babel/plugin-transform-classes 7.16.5, seven unit tests are failing:

not ok 467 ES5: simple class
not ok 481 ES5: annotated class
not ok 482 ES5 explicitOnly: annotated class
not ok 489 ES5: annotated constructor
not ok 490 ES5 explicitOnly: annotated constructor
not ok 493 ES5: constructor with prologue directive
not ok 494 ES5 explicitOnly: constructor with prologue directive

I bisected the issue to this line diff in commit babel/babel@acda160 in the PR babel/babel#12115

It looks like in ES5 mode, @babel/plugin-transform-classes transforms class declarations to function expressions (which are still recognized by babel-plugin-angularjs-annotate as annotation candidates), but following 7.16.5, these expressions are now wrapped in the _createClass() helper, which babel-plugin-angularjs-annotate does not recognize as eligible for annotation.

This issue would have been caught by the test suite with earlier versions of @babel/plugin-transform-classes if additional methods besides the constructor had been present in the test cases.

0.8.2 is extremely slow

It became extremely slow when I updated babel-plugin-angularjs-annotate from 0.8.1 to 0.8.2.

time babel --presets es2015 --plugins angularjs-annotate app.es6.js > /dev/null

app.es6.js is around 750KB/25,000 lines.

With 0.8.1

real 0m5.835s
user 0m6.075s
sys 0m0.275s

With 0.8.2

real 2m5.533s
user 2m4.816s
sys 0m0.986s

I'm running babel 6.26.0 with node 6.11.4 on Mac OS 10.12.6.

Unexpected token

"babel-core": "^6.26.3",
"babel-plugin-angularjs-annotate": "^0.9.0",
"gulp-babel": "^7.0.1",

The code snippet that causes an issue is this

$scope.test = () => {
    const { row } = $stateParams;
    if (row && row.id) {
        vm.dataId = { ...row };
    }
};

$scope.test();

After switching to BPAA

gulpfile.js

// .pipe($.ngAnnotate({ add: true }))
.pipe($.babel({
    compact: false,
    presets:['es2015'],
    plugins: [["angularjs-annotate", { explicitOnly : true}]]
}))

Error:

[10:24:38] Plumber found unhandled error:
 SyntaxError in plugin "gulp-babel"
Message:
    /mnt/e/aca/src/client/js/app.js: Unexpected token (7712:30)

The problem is that the app.js file is not generated so I dont know how to know which token it is exactly.


Before I switched to BPAA gulp-annotate.

gulpfile.js

.pipe($.ngAnnotate({ add: true }))
.pipe($.babel({
    compact: false,
    presets:['es2015'],
    // plugins: [["angularjs-annotate", { explicitOnly : true}]]
}))

Error

[10:45:20] Plumber found unhandled error:
 Error in plugin 'gulp-ng-annotate'
Message:
    js/app.js: error: couldn't process source due to parse error
Unexpected token (7712:30)

This is because ng-annotate doesn't support some es6 syntax.

Though, while still using the above configuration (pre BPAA) I was using an arrow function but gulp-ng-annotate didn't complain.

return ParamsService.getContinents().then(data => data);

Crashes on object shorthand

Currently fails with the following error:

TypeError: test.js: Cannot read property '$chained' of undefined

You should be able to reproduce this with the following code (test.js):

import angular from 'angular';
import ngRoute from 'angular-route';

export default angular.module('app', [
  ngRoute
])

.config(function($routeProvider) {
  'ngInject';

  $routeProvider
    .when('/some/url', {
      templateUrl: './template.html',
      controller: 'ViewController',
      controllerAs: 'view',
      resolve: {
        payload($route, $location) {
          'ngInject';

          return true;
        }
      }
    });
});

Create the following babelrc:

{
  "presets": [
    [
      "env",
      {
        "targets": {
          "chrome": 52
        }
      }
    ]
  ],
  "plugins": [
    "angularjs-annotate"
  ]
}

and the following command:

./node_modules/.bin/babel test.js

Versions:

Node: 7.0.0
NPM: 4.0.1
Babel: 6.18.0 (babel-core 6.18.2)


When you remove payload() {} from the resolve object, the code successfully transpiles.

last is not defined

I checked the code at the nginject.js and that "last" function, indeed, seems to be missing.

Whereยดs that supposed to be coming from?

Iยดm running on node 6.7.0, on windows

ReferenceError: ../softWrench.sW4.Web/Content/temp/scripts/app.concat.js: last is not defined at isAnnotatedArray (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-plugin-angularjs-annotate\nginject.js:375:63) at Object.inspectFunction (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-plugin-angularjs-annotate\nginject.js:103:9) at PluginPass.enter (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-plugin-angularjs-annotate\babel-ng-annotate.js:103:20) at newFn (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\visitors.js:276:21) at NodePath._call (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\path\context.js:76:18) at NodePath.call (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\path\context.js:48:17) at NodePath.visit (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\path\context.js:105:12) at TraversalContext.visitQueue (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:150:16) at TraversalContext.visitMultiple (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:103:17) at TraversalContext.visit (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:190:19) at Function.traverse.node (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\index.js:114:17) at NodePath.visit (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\path\context.js:115:19) at TraversalContext.visitQueue (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:150:16) at TraversalContext.visitMultiple (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:103:17) at TraversalContext.visit (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\context.js:190:19) at Function.traverse.node (C:\Users\luizh\workspace\softwrench\Build\node_modules\babel-traverse\lib\index.js:114:17)

Problem with function hoisting

Input code:

module.exports = function($filterProvider) {
  'ngInject';

  function ordinalSuffixFilter(ordinalSuffix) {
    'ngInject';


    return function(day) {
      if (angular.isNumber(day) && isFinite(day)) {
        return ordinalSuffix(Number(day));
      }
    };
  }

  $filterProvider.register('sqOrdinalSuffix', ordinalSuffixFilter);

};

Output code:

'use strict';

ordinalSuffixFilter.$inject = ['ordinalSuffix'];
module.exports = ['$filterProvider', function ($filterProvider) {
  'ngInject';

  function ordinalSuffixFilter(ordinalSuffix) {
    'ngInject';

    return function (day) {
      if (angular.isNumber(day) && isFinite(day)) {
        return ordinalSuffix(Number(day));
      }
    };
  }

  $filterProvider.register('sqOrdinalSuffix', ordinalSuffixFilter);
}];

In the given example ordinalSuffixFilter.$inject = ['ordinalSuffix']; is defined on the wrong scope therefore it leads to "undefined variable orfinalSuffixFilter" error. I believe that in order to avoid such errors annotations should be added directly above the annotated function.

Project with angular and vue code

I was having problems with running npm run prod because angular wouldn't load the minified functions correctly and logging this error:

Error: [$injector:modulerr] Failed to instantiate module app due to: [$injector:modulerr] Failed to instantiate module app.config due to: [$injector:unpr] Unknown provider: e http://errors.angularjs.org/1.5.8/$injector/unpr?p0=e t

Resolved it by adding angularjs-annotate to .babelrc plugin:

"plugins": [
    "transform-vue-jsx",
    "syntax-dynamic-import",
    "angularjs-annotate"
  ]

However, as a result of this fix, I started getting error TypeError: "e._f(...) is not a function", which is related to global vue filters Vue.filter(...).

Is there any way to get the plugin angularjs-annotate to work on angular code only, ignoring my vue code?

Simple component generating "target.get(...).filter is not a function" error

(function(){
    "use strict";
    // define component
    var testFeedback = {
        controller: testFeedbackController,
    }
    // define controller
    function testFeedbackController() {
    }

    angular
        .module("test.feedback.pkg", [])
        // feedback
        .component("testFeedback", testFeedback)
        ;
})();

That's it, that's what I've stripped the code down to and it's still generating this mysterious error. If I swap it out to directive style, the error goes away. This is frustrating, since component support is exactly why I switched from ngAnnotate to this plugin...

(There is no 'filter' anywhere in the entire file, but even if I comment out literally everything except these lines... the error still happens. :\ )

Method names can shadow import names

I've run into a bug where if a class method has the same name as an import, prefixed with an underscore, it shadows the import with the similar name. Brief example:

import now from 'lodash/now'

const f = function ($log) {
  'ngInject'
  class C {
    _now () {
      // This line ends up referring to the method containing it.
      now()
    }
  }

  return C
}

I've created a full reproduction case with more information here: https://github.com/edsrzf/babel-angularjs-repro

Note that this uses babel 7. I've tried pulling in the changes from #43 but they don't seem to help anything.

I'm happy to try to fix this if I can get some guidance. In particular, I'm not sure if this is actually a bug in this plugin or if it's merely a symptom of some issue within babel itself.

Support 'ngInject' string-based annotation

The README only mentions implicit annotation or one done via the /* @ngInject */ comment. The 'ngInject'; string-based annotation should be supported as well:

class svc {
  constructor(dep1){
    'ngInject';
    this.dep1 = dep1;
  }
  method1() {
    this.dep1.doSth();
  }
}

$inject is not added on exported class when transforming to ES5

When using the following code angularjs-annotate fails to annotate the class if the class is transpiled to ES5

/*@ngInject*/
export class Broken {
  	constructor($q) {
    
    }  
}box chec

The problem can be reproduced on the demo page https://schmod.github.io/babel-plugin-angularjs-annotate/ with the transform checkbox checked

Note that this works fine if the class is not exported.

I found several alternative placement of the @ngInject that work.

export /*@ngInject*/ class Ok {
  	constructor($q) {
    
    }  
}

export class Ok2 {
  /*@ngInject*/	
  constructor($q) {
    
    }  
}

It 1 also works if I use an alias for export

/* @ngInject */
class MyControllerInternal {
  constructor($q) {}
}

export const MyController = MyControllerInternal;

Any way to catch babel-renamed function arguments?

I ran into a problem related to babel renaming function arguments when they collide with babel adding names to anonymous functions (stack overflow discussion on it here: https://stackoverflow.com/q/38383512). We have a DI argument named foo, which gets renamed to _foo by babel , which breaks angular annotations.

We start with something like this:

function(foo) {
  var bar = {
    foo: function() {}
  };
}

And get:

['_foo', function(_foo) {
  var bar = {
    foo: function foo() {}
  };
}]

I'm guessing this isn't a bug in angularjs-annotate, but I'm wondering if there's any way to run annotations prior to babel renaming arguments? Or is that impossible the way babel plugins are structured?

Issue with default parameter arguments

Hi,
There seems to be something wrong with default parameter arguments:

Input code:

const outside = function (arg = {}){
  /*@ngInject*/
  const inside = function ($q) {};
  return inside;
}

Output code:

"use strict";

var outside = function outside() {
  var arg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

  /*@ngInject*/
  var inside = function inside($q) {};
  return inside;
};

Removing the default argument does work, inside.$inject = ["$q"]; appears again.

What does "Declarator name different _elementReadyDirectiveFactory" actually indicate?

I mostly want to leave this here, for anyone doing a web search about this behavior.

During my WebPack build, I repeatedly saw the line:

Declarator name different _elementReadyDirectiveFactory

The message is coming from https://github.com/schmod/babel-plugin-angularjs-annotate/blob/master/ng-annotate-main.js#L785-L788 I don't understand what it indicates and I also wasn't able to resolve this by trial-and-error.

Conflict with `transform-es2015-function-name`

Run the following:

echo 'x => ({ x: () => x });' | babel --plugins transform-es2015-function-name

Expected output is the unchanged input:

x => ({ x: () => x });

But instead we get the following:

_x => ({ x: () => _x });

In a real-world project, we use webpack with babel-loader in a config like:

loaders: [
    {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
            presets: ['es2015'],
            plugins: ['angularjs-annotate'],
            cacheDirectory: ''
        }
    },
    /* ... */
]

Where the es2015 preset contains transform-es2015-function-name.

But this results in some of our controllers not being able to find certain dependencies.

Not sure if this is an upstream bug, or if this should be dealt with here. The generated code is otherwise valid, and I guess upstream could argue that nothing is wrong here.

This is on babel 6.18.0 and babel-plugin-transform-es2015-function-name 6.9.0. Our app, where we get the missing dependency errors, uses babel-plugin-angularjs-annotate 0.6.0.

Some more scenario's:

// BAD: replace arrow function with regular function
function foo(x) { return { x: () => x }; };
// function foo(_x) {
//  return { x: () => _x };
// }

// GOOD: replace `x` return with something else
x => ({ x: () => 7 });
// x => ({ x: () => 7 });

// GOOD: replace property name with something else
x => ({ z: () => x });
// x => ({ z: () => x });

// GOOD: use method syntax
x => ({ x() { return x; } });
// x => ({ x() {
//     return x;
//   } });

Does not work with awesome-typescript-loader and babel-loader

It seems a class that is extended by another class is not annotated correctly. Following code is generated by babel-plugin-angularjs-annotate:

/***/ },
/* 455 */
/***/ function(module, exports, __webpack_require__) {

"use strict";
"use strict";

var __extends = undefined && undefined.__extends || function (d, b) {
    for (var p in b) {
        if (b.hasOwnProperty(p)) d[p] = b[p];
    }function __() {
        this.constructor = d;
    }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var AbstractArrayPersistActor_1 = __webpack_require__(453);
var constants_1 = __webpack_require__(47);
var ProductPersistActor = function (_super) {
    ProductPersistActor.$inject = ['$log', '$q', 'pouchDB', 'productActions', 'productStore'];

    __extends(ProductPersistActor, _super);
    /* @ngInject */
    function ProductPersistActor($log, $q, pouchDB, productActions, productStore) {
        _super.call(this, $log, $q, pouchDB);
        this.productActions = productActions;
        this.productStore = productStore;
    }
    ProductPersistActor.prototype.filter = function (doc) {
        return doc._id.startsWith(constants_1.PREFIX);
    };
    ProductPersistActor.prototype.isLoaded = function () {
        return this.productStore.loaded;
    };
    ProductPersistActor.prototype.getDocuments = function () {
        return this.productStore.products;
    };
    return ProductPersistActor;
}(AbstractArrayPersistActor_1.AbstractArrayPersistActor);
exports.ProductPersistActor = ProductPersistActor;

for comparision the code that is generated when I use ng-annotate after babel was executed:

/***/ },
/* 556 */
/***/ function(module, exports, __webpack_require__) {

"use strict";
"use strict";

var __extends = undefined && undefined.__extends || function (d, b) {
    for (var p in b) {
        if (b.hasOwnProperty(p)) d[p] = b[p];
    }function __() {
        this.constructor = d;
    }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var AbstractArrayPersistActor_1 = __webpack_require__(554);
var constants_1 = __webpack_require__(47);
var ProductPersistActor = function (_super) {
    __extends(ProductPersistActor, _super);
    /* @ngInject */
    ProductPersistActor.$inject = ["$log", "$q", "pouchDB", "productActions", "productStore"];
    function ProductPersistActor($log, $q, pouchDB, productActions, productStore) {
        _super.call(this, $log, $q, pouchDB);
        this.productActions = productActions;
        this.productStore = productStore;
    }
    ProductPersistActor.prototype.filter = function (doc) {
        return doc._id.startsWith(constants_1.PREFIX);
    };
    ProductPersistActor.prototype.isLoaded = function () {
        return this.productStore.loaded;
    };
    ProductPersistActor.prototype.getDocuments = function () {
        return this.productStore.products;
    };
    return ProductPersistActor;
}(AbstractArrayPersistActor_1.AbstractArrayPersistActor);
exports.ProductPersistActor = ProductPersistActor;

Note that the $inject is placed below the comment which seems better and that is added after __extends was called.

It resulting error is that the this context seems to get compromised and the instantiated class is not working correctly. Will try to dig a little bit deeper in the problem. Maybe you have an idea what the cause can be.

Remove prologue string?

I use the 'ngInject' prologue string everywhere, and angularjs-annotate does a wonderful job with it. But once the transform has happened, do we still need that prologue? We could save a bit of space in the final bundle by removing it.

ngInject does not work on direct export

Hello,

ngInject does not work when exporting a class, it worked with ng-annotate.

/* @ngInject */
class A {
    constructor(test){
      this.test = test;
    }
}

This works.

/* @ngInject */
export class A {
    constructor(test){
      this.test = test;
    }
}

This doesn't.

/* @ngInject */
class A {
    constructor(test){
      this.test = test;
    }
}

export {A};

This does.

Add support for the explicit-only mode

The implicit mode has many potential surprises; I'd like to be able to explicitly mark all places that should be annotated and have a guarantee nothing else gets annotated. In this mode only classes/functions marked with /* @ngInject */ or 'ngInject'; would be annotated.

Can not inject dependencies on class when declared on an object property

Hello there,

I'm stuck with an issue with following angularJS component declaration where the plugin does not generate $inject array

export const MyComponent = {
  template: '...',
  bindings: {},
  controller: class MyComponentController {
    constructor ($http) {
      'ngInject'
    }
  }
}

I think this is because the plugin has nowhere to include the MyComponentController.$inject = ['$http'] statement because of the way the class is declared and associated to the controller property.

There is two possible solutions in this case

  1. Add a MyComponent.controller.$inject = [...] statement
  2. (my favorite) Add a class property to end up with something like:
export const MyComponent = {
  template: '...',
  bindings: {},
  controller: class MyComponentController {
    constructor ($http) {
      'ngInject'
    }
    get $inject() {
        return ['$http']
    }
  }
}

For the moment I use the following workaround:

export const MyComponent = {
  template: '...',
  bindings: {},
  controller: (() => {
    class MyComponentController {
      constructor ($http) {
        'ngInject'
      }
    }
    return MyComponentController
  })()
}

It is a bit more verbose and add an additional nested level to the code

What do you think of this?

Thank you for reading !

Comment Format Not Working With angular-ui-router Resolves, Worked With Regular ng-annotate

Comments are allowed on actual providers (.provider, .factory, .controller, etc.), but not on UI Router resolves. On the previous, now-deprecated ng-annotate, comments are allowed here, too. This is easily worked around, as we can use the directive form ('ngInject'; as the first statement in a resolve), but it could cause major headaches during transition from ng-annotate to babel-plugin-angularjs-annotate, which is already bad enough with having to add babel to the build process.

For example,

angular.module('myApp', myState);

/** @ngInject */
function myState($stateRegistry) {
    $stateRegistry.register({
        name: 'myState',
        url: '/',
        resolve: {
            /** @ngInject */
            myResolve: function($state) {
            },
        },
    });
}

worked with ng-annotate, but not with this plugin. With this plugin, it throws an error saying "The transition errored", with a type of 6. If you need any more information, I can find it, but I am not sure what kind is generally useful.

On the other hand,

angular.module('myApp', myState);

/** @ngInject */
function myState($stateRegistry) {
    $stateRegistry.register({
        name: 'myState',
        url: '/',
        resolve: {
            myResolve: function($state) {
                'ngInject';
            },
        },
    });
}

still works.

For others looking at this issue, it is also worth noting that resolves without any dependencies will still work with the comment format. Also, this will not break your app, just that one state.

Prettier issues

Hi, so prettier adds a wrapping bracket to the string ('ngInject') . Which isn't compiling correctly.

class Foo {

  constructor(private $http) {
    ('ngInject');

    this.$http; // undefined
  }
}

TypeScript -> es2017 -> Babel -> es5.

Can you please direct me to the line / file I'll need to edit to make this mod. Could be a root ng-annotate issue?

crashes with illegal component declaration

An "illegal" component declaration causes the plugin to crash and exit. We should tolerate this gracefully.

angular.module('foo').component({})

causes the plugin to exit with:

unknown: Cannot set property '$chained' of undefined

Smart assign to `this` in constructors

angular.module('app').controller('Ctrl', class Ctrl {
  /* @ngInject */
  constructor($scope) {
    //some code
  }
});

could become:

angular.module('app').controller('Ctrl', class Ctrl {
  static $inject = ['$scope']
  constructor() {
    [this.$scope] = arguments;
    //some code
  }
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.