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
241 stars 26 forks source link

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

Closed mlegenhausen closed 7 years ago

mlegenhausen commented 7 years ago

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.

mlegenhausen commented 7 years ago

Never mind. The problem was not in this babel plugin, simply had some wired behaviour in getting this stuff working with webpack, typescript and awesome-typescript-loader. For everyone looking around for a configuration here is mine:

// tsconfig.js
{
  ...
  "awesomeTypescriptLoaderOptions": {
    "useBabel": true,
    "babelOptions": {
      "plugins": ["angularjs-annotate"],
      "presets": ["es2015"]
    }
  }
}

Don't try to chain awesome-typescript-loader with babel-loader this will create the above described error.

schmod commented 7 years ago

Extended ES6 classes seem to work fine.

class foo extends bar {
  constructor($scope){
    "ngInject";
    super();
  }
}

new foo();

Yields

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var foo = function (_bar) {
  foo.$inject = ["$scope"];

  _inherits(foo, _bar);

  function foo($scope) {
    "ngInject";

    _classCallCheck(this, foo);

    return _possibleConstructorReturn(this, Object.getPrototypeOf(foo).call(this));
  }

  return foo;
}(bar);

new foo();

In this example, $inject is defined before _inherits(foo,_bar) is called.

I don't quite understand why this isn't happening with awesome-typescript-loader, but there may be nothing that we can do about it (particularly if the TS loader is invoked after Babel).

If you don't have any objections, I'm going to close this, as I'm not sure there's anything else to do at this point.