fix(migrations): do not incorrectly add todo for @Injectable or @Pipe (#37732)

As of v10, the `undecorated-classes-with-decorated-fields` migration
generally deals with undecorated classes using Angular features. We
intended to run this migation as part of v10 again as undecorated
classes with Angular features are no longer supported in planned v11.

The migration currently behaves incorrectly in some cases where an
`@Injectable` or `@Pipe` decorated classes uses the `ngOnDestroy`
lifecycle hook. We incorrectly add a TODO for those classes. This
commit fixes that.

Additionally, this change makes the migration more robust to
not migrate a class if it inherits from a component, pipe
injectable or non-abstract directive. We previously did not
need this as the undecorated-classes-with-di migration ran
before, but this is no longer the case.

Last, this commit fixes an issue where multiple TODO's could be
added. This happens when multiple Angular CLI build targets have
an overlap in source files. Multiple programs then capture the
same source file, causing the migration to detect an undecorated
class multiple times (i.e. adding a TODO twice).

Fixes #37726.

PR Close #37732
This commit is contained in:
Paul Gschwendtner
2020-06-25 15:38:18 +02:00
committed by Andrew Kushnir
parent ce879fc416
commit d12cdb5019
6 changed files with 430 additions and 83 deletions

View File

@ -136,24 +136,36 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () =>
it('should not change decorated classes', () => {
writeFile('/index.ts', `
import { Input, Component, Output, EventEmitter } from '@angular/core';
import { Input, Component, Directive, Pipe, Injectable } from '@angular/core';
@Component({})
export class Base {
export class MyComp {
@Input() isActive: boolean;
}
@Directive({selector: 'dir'})
export class MyDir {
@Input() isActive: boolean;
}
export class Child extends Base {
@Output() clicked = new EventEmitter<void>();
@Injectable()
export class MyService {
ngOnDestroy() {}
}
@Pipe({name: 'my-pipe'})
export class MyPipe {
ngOnDestroy() {}
}
`);
runTSLint(true);
const content = getFile('/index.ts');
expect(content).toContain(
`import { Input, Component, Output, EventEmitter, Directive } from '@angular/core';`);
expect(content).toContain(`@Component({})\n export class Base {`);
expect(content).toContain(`@Directive()\nexport class Child extends Base {`);
expect(content).toMatch(/@Component\({}\)\s+export class MyComp {/);
expect(content).toMatch(/@Directive\({selector: 'dir'}\)\s+export class MyDir {/);
expect(content).toMatch(/@Injectable\(\)\s+export class MyService {/);
expect(content).toMatch(/@Pipe\({name: 'my-pipe'}\)\s+export class MyPipe {/);
expect(content).not.toContain('TODO');
});
it('should add @Directive to undecorated classes that have @Output', () => {