0.1.0 • Published 2 years ago

@buildup_ag/eslint-plugin v0.1.0

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

Description

These rules are custom eslint rules for the Buildup AG.

Installation

A) Add "@buildup_ag/eslint-plugin": "^0.0.9" to the dependencies inside the package.json of the angular app. Use a suitable version number. B) In the .eslintrc.json of the angular app, add

{
    "files": ["*.ts"],
    "plugins": ["@buildup_ag"],
    "rules": {
        "@buildup_ag/no-operator-in-switch-cases": "error",
        "@buildup_ag/readonly-injectables": "error",
        "@buildup_ag/take-until-before-subscription": "error"
    }
},

to the overrides property.

Rules

no-operator-in-switch-cases

Enforces the application to not have operators like "OR" or "AND" in cases of a switch statement. Operators in switch statements are prohibited, for multi-criteria-cases fall-throughs should be used instead.

Examples of incorrect code for this rule:

switch (expr) {
  case 'Oranges' || 'Apples':
                 ~~ Operational operator in switch case
    break;
  default:
    return foo;
}

switch (expr) {
  case 'Oranges' && 'Apples':
                 ~~ Operational operator in switch case
    break;
  default:
    return foo;
}

Examples of correct code for this rule:

switch (expr) {
  case 'Oranges':
    break;
  case 'Apples':
    break;
  default:
    return foo;
}

switch (expr) {
  case 'Oranges':
  case 'Apples':
    break;
  default:
    return foo;
}

readonly-injectables

An injected dependency is usually created as a singleton and overwriting it breaks the whole concept of dependency injection pattern. This rule enforces the application to prepend an injected dependence with a readonly statement.

This rule is inspired by https://github.com/shpaq23/custom-eslint-rules.

Examples of incorrect code for this rule:

constructor(private restService: RestService)
                  ~~ not preceded by readonly

Examples of correct code for this rule:

constructor(private readonly restService: RestService)

take-until-before-subscription

Enforces the application to properly unsubscribe from subscriptions. This rule makes sure that:

  • All subscriptions are preceded by a pipe statement
  • The last argument of the pipe preceding a subscription is a takeUntil statement
  • The takeUntil statement has a single argument
  • The single argument of the takeUntil statement is a property of the class
  • The single argument of the takeUntil statement is initialized as a subject
  • The component containing the subscription implements an ngOnDestroy method
  • The subject used as argument for the takeUntil statement is called with next and complete in the ngOnDestroy method of the component

Examples of incorrect code for this rule:

this.rest.method(this.id).subscribe();
                        ~~ no preceded by pipe

this.rest.method(this.id).pipe(undefined).subscribe();
                               ~~~~~~~~~~ no takeUntil argument

this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe), undefined).subscribe();
                                                              ~~~~~~~~~~ takeUntil is not last argument of pipe

this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe, undefined)).subscribe();
                                                             ~~~~~~~~~ takeUntil does not take a single argument

@Component({
    selector: 'app-component',
    styleUrls: ['./app-component.component.scss'],
    templateUrl: './app-component.component.html',
})
export class AppComponentComponent implements OnDestroy, OnInit {
    ngUnsubscribe = new NotASubject();
                    ~~~~~~~~~~~~~~~~~~ takeUntil argument not initialized as subject

    foo() {
      this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe)).subscribe();
    }

    ngOnDestroy() {
      this.ngUnsubscribe.next();
      this.ngUnsubscribe.complete();
    }
}

@Component({
    selector: 'app-component',
    styleUrls: ['./app-component.component.scss'],
    templateUrl: './app-component.component.html',
})
export class AppComponentComponent implements OnDestroy, OnInit {
    ngUnsubscribe = new Subject();

    foo() {
      this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe)).subscribe();
    }

    ~~~~~~~~~~~~~~~~~~ no ngOnDestroy method
}

@Component({
    selector: 'app-component',
    styleUrls: ['./app-component.component.scss'],
    templateUrl: './app-component.component.html',
})
export class AppComponentComponent implements OnDestroy, OnInit {
    ngUnsubscribe = new Subject();

    foo() {
      this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe)).subscribe();
    }

    ngOnDestroy() {
      this.ngUnsubscribe.NeitherNextNorComplete();
                        ~~~~~~~~~~~~~~~~~~~~~~~~~ takeUntil argument not called with .next() and .complete()
    }
}

Examples of correct code for this rule:

@Component({
    selector: 'app-component',
    styleUrls: ['./app-component.component.scss'],
    templateUrl: './app-component.component.html',
})
export class AppComponentComponent implements OnDestroy, OnInit {
    ngUnsubscribe = new Subject();

    foo() {
      this.rest.method(this.id).pipe(takeUntil(this.ngUnsubscribe)).subscribe();
    }

    ngOnDestroy() {
      this.ngUnsubscribe.next();
      this.ngUnsubscribe.complete();
    }
}

Publish

  • Install all dependencies with npm install
  • Increase version number in package.json
  • Build plugin with npm run-script build
  • Upload to NPM with npm publish --access public