feat(core): add undecorated classes with decorated fields schematic (#32130)
Adds a schematic that adds a `Directive` decorator to undecorated classes that have fields that use Angular decorators. PR Close #32130
This commit is contained in:

committed by
atscott

parent
b6fa9299e5
commit
904a2018e0
@ -11,6 +11,7 @@ ts_library(
|
||||
"//packages/core/schematics/migrations/renderer-to-renderer2",
|
||||
"//packages/core/schematics/migrations/static-queries",
|
||||
"//packages/core/schematics/migrations/template-var-assignment",
|
||||
"//packages/core/schematics/migrations/undecorated-classes-with-decorated-fields",
|
||||
"//packages/core/schematics/utils",
|
||||
"//packages/core/schematics/utils/tslint",
|
||||
"@npm//tslint",
|
||||
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Replacement, RuleFailure, Rules} from 'tslint';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {FALLBACK_DECORATOR, addImport, getNamedImports, getUndecoratedClassesWithDecoratedFields, hasNamedImport} from '../undecorated-classes-with-decorated-fields/utils';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TSLint rule that adds an Angular decorator to classes that have Angular field decorators.
|
||||
* https://hackmd.io/vuQfavzfRG6KUCtU7oK_EA
|
||||
*/
|
||||
export class Rule extends Rules.TypedRule {
|
||||
applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const printer = ts.createPrinter();
|
||||
const classes = getUndecoratedClassesWithDecoratedFields(sourceFile, typeChecker);
|
||||
|
||||
return classes.map((current, index) => {
|
||||
const {classDeclaration: declaration, importDeclaration} = current;
|
||||
const name = declaration.name;
|
||||
|
||||
// Set the class identifier node (if available) as the failing node so IDEs don't highlight
|
||||
// the entire class with red. This is similar to how errors are shown for classes in other
|
||||
// cases like an interface not being implemented correctly.
|
||||
const start = (name || declaration).getStart();
|
||||
const end = (name || declaration).getEnd();
|
||||
const fixes = [Replacement.appendText(declaration.getStart(), `@${FALLBACK_DECORATOR}()\n`)];
|
||||
|
||||
// If it's the first class that we're processing in this file, add `Directive` to the imports.
|
||||
if (index === 0 && !hasNamedImport(importDeclaration, FALLBACK_DECORATOR)) {
|
||||
const namedImports = getNamedImports(importDeclaration);
|
||||
|
||||
if (namedImports) {
|
||||
fixes.push(new Replacement(
|
||||
namedImports.getStart(), namedImports.getWidth(),
|
||||
printer.printNode(
|
||||
ts.EmitHint.Unspecified, addImport(namedImports, FALLBACK_DECORATOR),
|
||||
sourceFile)));
|
||||
}
|
||||
}
|
||||
|
||||
return new RuleFailure(
|
||||
sourceFile, start, end,
|
||||
'Classes with decorated fields must have an Angular decorator as well.',
|
||||
'undecorated-classes-with-decorated-fields', fixes);
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user