feat(ngcc): migrate services that are missing @Injectable()
(#33362)
A class that is provided as Angular service is required to have an `@Injectable()` decorator so that the compiler generates its injectable definition for the runtime. Applications are automatically migrated using the "missing-injectable" schematic, however libraries built for older version of Angular may not yet satisfy this requirement. This commit ports the "missing-injectable" schematic to a migration that is ran when ngcc is processing a library. This ensures that any service that is provided from an NgModule or Directive/Component will have an `@Injectable()` decorator. PR Close #33362
This commit is contained in:
@ -6,15 +6,18 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ErrorCode, FatalDiagnosticError} from '../../../src/ngtsc/diagnostics';
|
||||
import {AbsoluteFsPath} from '../../../src/ngtsc/file_system';
|
||||
import {MetadataReader} from '../../../src/ngtsc/metadata';
|
||||
import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
|
||||
import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection';
|
||||
import {DecoratorHandler} from '../../../src/ngtsc/transform';
|
||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||
import {MigrationHost} from '../migrations/migration';
|
||||
|
||||
import {AnalyzedClass, AnalyzedFile} from './types';
|
||||
import {analyzeDecorators} from './util';
|
||||
import {analyzeDecorators, isWithinPackage} from './util';
|
||||
|
||||
/**
|
||||
* The standard implementation of `MigrationHost`, which is created by the
|
||||
@ -24,7 +27,7 @@ export class DefaultMigrationHost implements MigrationHost {
|
||||
constructor(
|
||||
readonly reflectionHost: NgccReflectionHost, readonly metadata: MetadataReader,
|
||||
readonly evaluator: PartialEvaluator, private handlers: DecoratorHandler<any, any>[],
|
||||
private analyzedFiles: AnalyzedFile[]) {}
|
||||
private entryPointPath: AbsoluteFsPath, private analyzedFiles: AnalyzedFile[]) {}
|
||||
|
||||
injectSyntheticDecorator(clazz: ClassDeclaration, decorator: Decorator): void {
|
||||
const classSymbol = this.reflectionHost.getClassSymbol(clazz) !;
|
||||
@ -41,6 +44,25 @@ export class DefaultMigrationHost implements MigrationHost {
|
||||
mergeAnalyzedClasses(oldAnalyzedClass, newAnalyzedClass);
|
||||
}
|
||||
}
|
||||
|
||||
getAllDecorators(clazz: ClassDeclaration): Decorator[]|null {
|
||||
const sourceFile = clazz.getSourceFile();
|
||||
const analyzedFile = this.analyzedFiles.find(file => file.sourceFile === sourceFile);
|
||||
if (analyzedFile === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const analyzedClass = analyzedFile.analyzedClasses.find(c => c.declaration === clazz);
|
||||
if (analyzedClass === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return analyzedClass.decorators;
|
||||
}
|
||||
|
||||
isInScope(clazz: ClassDeclaration): boolean {
|
||||
return isWithinPackage(this.entryPointPath, clazz.getSourceFile());
|
||||
}
|
||||
}
|
||||
|
||||
function getOrCreateAnalyzedFile(
|
||||
|
Reference in New Issue
Block a user