Angular and AngularJS Support in JavaScript analyzer

Hey, y’all — DeepSource JavaScript analyzer now supports AngularJS ( v1.* ) and Angular (latest) frameworks.

Angular

JS-0571: Invalid lifecycle method in class

Some lifecycle methods can only be used in certain class types.

The not preferred way:

@Injectable()
	class Test {
	  ngAfterContentChecked() { console.log('AfterContentChecked'); }
	}

The preferred way:

@Injectable()
	class Test {
		ngOnDestroy() { console.log('OnDestroy'); }
	}

JS-0572: @Attribute decorator should not be used

It is a good practice to specify this attribute name directly by naming correctly the corresponding parameter, in order to avoid duplicates code.

The not preferred way:

class Test {
   constructor(@Attribute() foo: any) {}
}

The preferred way:

class Test {
   constructor(@Optional() foo: any, @Optional() bar: any) {}
}

JS-0573: Prevent explicit calls to lifecycle methods

Explicit calls to lifecycle methods could be confusing. It is Angular’s responsibility to invoke them.

The not preferred way:

@Pipe({
  name: 'test'
})
class Test {
  test() {
    this.ngOnInit();
  }
}

The preferred way:

@Component({
  selector: 'test'
})
 
class Test {
  test() {
    super.ngAfterContentChecked();
  }
}

JS-0575: Found impure pipes

Impure pipes should be avoided because they are invoked on each change-detection cycle. Impure pipes can’t leverage caching, instance re-use and simple tests.

The not preferred way:

@Pipe({
    name: 'test',
    pure: false
})
class Test {}

The preferred way:

@Pipe({
    name: 'test',
    pure: true
})
class Test {}

AngularJS

JS-0516: Disallow use of internal angular properties prefixed with $$

All scope’s properties/methods starting with $$ are used internally by AngularJS. You should not use them directly. Exception can be allowed with this option: {allow:['$$watchers']}

The not-preferred way:

$scope.$$watchers.forEach(function (watcher) {
    // ...
});

The preferred way:

$scope.$apply();

JS-0518: Prefer the use of controllerAs in routes or states

The not-preferred way:

$routeProvider.when('/myroute', {
    controller: 'MyController'
}) // error: Route "/myroute" should use controllerAs syntax

The preferred way:

$routeProvider.when('/myroute', {
    controller: 'MyController',
    controllerAs: 'vm'
});

JS-0520: Assignments to $scope in controllers

The not-preferred way:

// error: You should not set properties on $scope in controllers. 
// Use controllerAs syntax and add data to "this"
angular.module("myModule").controller("SomeController", function($scope) {
    $scope.value = 42;
});

The preferred way:

angular.module("myModule").controller("SomeController", function($scope) {
    // this for values
    this.value = 42;

    // $scope is fine for watchers
    $scope.$watch(angular.bind(this, function () {
        return this.value
    }), function () {
        // ...
    });
});

JS-0526: Use of inline templates is discouraged

The not-preferred way:

angular.module('myModule').directive('helloWorld', function () {
    return {
        template: '<div>Hello World! <button>Say hello!</button></div>'
    };
}); // error: Inline template is too complex. Use an external template instead

The preferred way:

angular.module('myModule').directive('helloWorld', function () {
    return {
        templateUrl: 'template/helloWorld.html'
    };
});

How to enable the plugins?

To enable these plugins on your repository, add the following snippet to your .deepsource.toml :

version = 1

[[analyzers]]
name = "javascript"
enabled = true

  [analyzers.meta]
  plugins = ["angularjs"]

and

version = 1

[[analyzers]]
name = "javascript"
enabled = true

  [analyzers.meta]
  plugins = ["angular"]