refactor(ivy): correctly type class declarations in ngtsc
/ngcc
(#29209)
Previously, several `ngtsc` and `ngcc` APIs dealing with class declaration nodes used inconsistent types. For example, some methods of the `DecoratorHandler` interface expected a `ts.Declaration` argument, but actual `DecoratorHandler` implementations specified a stricter `ts.ClassDeclaration` type. As a result, the stricter methods would operate under the incorrect assumption that their arguments were of type `ts.ClassDeclaration`, while the actual arguments might be of different types (e.g. `ngcc` would call them with `ts.FunctionDeclaration` or `ts.VariableDeclaration` arguments, when compiling ES5 code). Additionally, since we need those class declarations to be referenced in other parts of the program, `ngtsc`/`ngcc` had to either repeatedly check for `ts.isIdentifier(node.name)` or assume there was a `name` identifier and use `node.name!`. While this assumption happens to be true in the current implementation, working around type-checking is error-prone (e.g. the assumption might stop being true in the future). This commit fixes this by introducing a new type to be used for such class declarations (`ts.Declaration & {name: ts.Identifier}`) and using it consistently throughput the code. PR Close #29209
This commit is contained in:

committed by
Miško Hevery

parent
2d859a8c3a
commit
bb6a3632f6
@ -11,6 +11,7 @@ ts_library(
|
||||
"//packages:types",
|
||||
"//packages/compiler",
|
||||
"//packages/compiler-cli/src/ngtsc/path",
|
||||
"//packages/compiler-cli/src/ngtsc/reflection",
|
||||
"//packages/compiler-cli/src/ngtsc/util",
|
||||
"@npm//@types/node",
|
||||
"@npm//typescript",
|
||||
|
@ -9,6 +9,7 @@
|
||||
import {Expression, ExternalExpr} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ClassDeclaration} from '../../reflection';
|
||||
import {FileToModuleHost, ReferenceEmitStrategy} from './emitter';
|
||||
import {ImportMode, Reference} from './references';
|
||||
|
||||
@ -18,20 +19,16 @@ const CHARS_TO_ESCAPE = /[^a-zA-Z0-9/_]/g;
|
||||
export class AliasGenerator {
|
||||
constructor(private fileToModuleHost: FileToModuleHost) {}
|
||||
|
||||
aliasSymbolName(decl: ts.Declaration, context: ts.SourceFile): string {
|
||||
if (!ts.isClassDeclaration(decl)) {
|
||||
throw new Error(`Attempt to write an alias to something which isn't a class`);
|
||||
}
|
||||
|
||||
aliasSymbolName(decl: ClassDeclaration, context: ts.SourceFile): string {
|
||||
// The declared module is used to get the name of the alias.
|
||||
const declModule =
|
||||
this.fileToModuleHost.fileNameToModuleName(decl.getSourceFile().fileName, context.fileName);
|
||||
|
||||
const replaced = declModule.replace(CHARS_TO_ESCAPE, '_').replace(/\//g, '$');
|
||||
return 'ɵng$' + replaced + '$$' + decl.name !.text;
|
||||
return 'ɵng$' + replaced + '$$' + decl.name.text;
|
||||
}
|
||||
|
||||
aliasTo(decl: ts.Declaration, via: ts.SourceFile): Expression {
|
||||
aliasTo(decl: ClassDeclaration, via: ts.SourceFile): Expression {
|
||||
const name = this.aliasSymbolName(decl, via);
|
||||
// viaModule is the module it'll actually be imported from.
|
||||
const moduleName = this.fileToModuleHost.fileNameToModuleName(via.fileName, via.fileName);
|
||||
|
Reference in New Issue
Block a user