schmod / babel-plugin-angularjs-annotate

Add Angular 1.x dependency injection annotations to ES6 code
http://schmod.github.io/babel-plugin-angularjs-annotate
MIT License
240 stars 29 forks source link

Does not work with async functions #20

Open mattbrunetti opened 7 years ago

mattbrunetti commented 7 years ago

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!)

gdaszuta commented 7 years ago

@mattbrunetti hi, have you found any way to fix it/work around it?

schmod commented 7 years ago

Hooooooboy. I'll have to take a look.

I have not run tests against the presets that include support for async functions. IIRC, we've run into the _x issue before, as Babel's promise to run plugins before presets isn't actually respected in some cases.

schmod commented 7 years ago

@gdaszuta @mattbrunetti Just curious: What is your use-case for this. Does Angular even know what to do with an async function?

mattbrunetti commented 7 years ago

@schmod We were trying to use async functions in resolve functions used with angular-ui-router. These functions are called with $injector.invoke() and are expected to return a promise. I don't think Angular's invoke function needs to do anything special with them or even be aware that they're async.

@gdaszuta We determined two workarounds.. (a) avoid using async functions, or (b) separate into two functions: the injected function and the async function. example:

Instead of this ...

resolve: {
  async someResource (someService) {
    'ngInject'
    // ...
  }
}

... do this ...

resolve: {
  someResource (someService) {
    'ngInject'
    return (async () => {
      // ...
    })()
  }
}
dgreene1 commented 6 years ago

Any news on this?

LM-G commented 5 years ago

2019, still not working :(

zenflow commented 5 years ago

@LM-G 2019 and you're using Angular 1?

LM-G commented 5 years ago

@zenflow Sadly, yes :( . I just joined an organization which is migrating an old ng1 app to a new fancy one with VueJS.

madflow commented 5 years ago

one with VueJS.

Please let us know how that worked out :D