UNPKG

luftborn-rxjs-takeuntil-destroy

Version:

ESLint plugin that enforces the use of takeUntilDestroyed operator in RxJS subscription pipes to prevent memory leaks in Angular applications

197 lines (143 loc) 5.39 kB
# luftborn-rxjs-takeuntil-destroy An ESLint plugin that enforces the use of `takeUntilDestroyed` or other take operators in RxJS subscription pipes to prevent memory leaks in Angular applications. ## Description This ESLint rule helps prevent memory leaks in Angular applications by ensuring that all Observable subscriptions use either the `takeUntilDestroyed` operator from `@angular/core/rxjs-interop` or one of the RxJS take operators (`takeUntil`, `takeWhile`, `take`, `takeLast`). These operators ensure that subscriptions are properly terminated, preventing memory leaks. ## Installation ```bash npm install luftborn-rxjs-takeuntil-destroy --save-dev ``` ## Requirements - ESLint 6.0.0 or higher (compatible with ESLint 9+) - Node.js 14.0.0 or higher - Angular 16.0.0 or higher (for @angular/core/rxjs-interop) - RxJS 7.0.0 or higher ## Usage Add the plugin to your ESLint configuration: ### ESLint Config (eslintrc.js / eslintrc.json) ```json { "plugins": ["luftborn-rxjs-takeuntil-destroy"], "rules": { "luftborn-rxjs-takeuntil-destroy/require-take-until-destroyed": "error" } } ``` ### ESLint Flat Config (eslint.config.js) ```js const luftbornRxjsTakeuntilDestroy = require('luftborn-rxjs-takeuntil-destroy'); module.exports = [ { plugins: { 'luftborn-rxjs-takeuntil-destroy': luftbornRxjsTakeuntilDestroy }, rules: { 'luftborn-rxjs-takeuntil-destroy/require-take-until-destroyed': 'error' } } ]; ``` ## Rule Details The `require-take-until-destroyed` rule enforces that all Observable subscriptions use either the `takeUntilDestroyed` operator or one of the RxJS take operators (`takeUntil`, `takeWhile`, `take`, `takeLast`) to ensure subscriptions are properly terminated, preventing memory leaks. This rule is auto-fixable. When you run ESLint with the `--fix` option, it will automatically add `takeUntilDestroyed()` to your subscription pipes where needed. ### Examples #### ❌ Incorrect ```typescript // Missing takeUntilDestroyed operator this.observable.subscribe(result => { console.log(result); }); // Using pipe but missing takeUntilDestroyed this.observable.pipe( map(data => data) ).subscribe(result => { console.log(result); }); ``` #### ✅ Correct ```typescript import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; // Using takeUntilDestroyed in pipe this.observable.pipe( map(data => data), takeUntilDestroyed() ).subscribe(result => { console.log(result); }); // Using renamed import import { takeUntilDestroyed as tud } from '@angular/core/rxjs-interop'; this.observable.pipe( map(data => data), tud() ).subscribe(result => { console.log(result); }); // Using a variable with 'destroy' in the name const destroyRef = inject(DestroyRef); const untilDestroyed = takeUntilDestroyed(destroyRef); this.observable.pipe( map(data => data), untilDestroyed ).subscribe(result => { console.log(result); }); // Using takeUntil from RxJS import { takeUntil } from 'rxjs'; destroy$ = new Subject<void>(); this.observable.pipe( map(data => data), takeUntil(this.destroy$) ).subscribe(result => { console.log(result); }); // Using takeWhile from RxJS import { takeWhile } from 'rxjs'; alive = true; this.observable.pipe( map(data => data), takeWhile(() => this.alive) ).subscribe(result => { console.log(result); }); // Using take from RxJS import { take } from 'rxjs'; this.observable.pipe( map(data => data), take(1) ).subscribe(result => { console.log(result); }); // Using takeLast from RxJS import { takeLast } from 'rxjs'; this.observable.pipe( map(data => data), takeLast(1) ).subscribe(result => { console.log(result); }); ``` ## Rule Options This rule has no options. ### Auto-fix Behavior When auto-fix is applied: 1. For subscriptions without a pipe call, it adds a pipe with `takeUntilDestroyed()` before the subscribe call. 2. For subscriptions with a pipe call but missing a take operator, it adds `takeUntilDestroyed()` as the last operator in the pipe. Note: The auto-fix assumes that `takeUntilDestroyed` is imported from `@angular/core/rxjs-interop`. If it's not imported, you'll need to add the import manually. ## Implementation Details The rule checks for: 1. Observable subscriptions without a pipe call 2. Observable subscriptions with a pipe call but missing any of the supported take operators 3. Proper import and usage of the `takeUntilDestroyed` operator from `@angular/core/rxjs-interop` 4. Proper import and usage of RxJS take operators (`takeUntil`, `takeWhile`, `take`, `takeLast`) from 'rxjs' The rule recognizes: - Renamed imports for all supported operators - Variables that might contain any of the supported operators - Various patterns for subscription cleanup ## License MIT © Luftborn ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. 1. Fork the repository https://github.com/Arigatouz/luftborn-rxjs-takeuntil-destroy 2. Create your feature branch (`git switch -c feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request