feat(ivy): resolve references to vars in .d.ts files (#25775)
Previously, if ngtsc encountered a VariableDeclaration without an initializer, it would assume that the variable was undefined, and return that result. However, for symbols exported from external modules that resolve to .d.ts files, variable declarations are of the form: export declare let varName: Type; This form also lacks an initializer, but indicates the presence of an importable symbol which can be referenced. This commit changes the static resolver to understand variable declarations with the 'declare' keyword and to generate references when it encounters them. PR Close #25775
This commit is contained in:
parent
13ccdfd89d
commit
96d6b79ada
|
@ -439,10 +439,7 @@ class StaticInterpreter {
|
|||
if (this.host.isClass(node)) {
|
||||
return this.getReference(node, context);
|
||||
} else if (ts.isVariableDeclaration(node)) {
|
||||
if (!node.initializer) {
|
||||
return undefined;
|
||||
}
|
||||
return this.visitExpression(node.initializer, context);
|
||||
return this.visitVariableDeclaration(node, context);
|
||||
} else if (ts.isParameter(node) && context.scope.has(node)) {
|
||||
return context.scope.get(node) !;
|
||||
} else if (ts.isExportAssignment(node)) {
|
||||
|
@ -456,6 +453,16 @@ class StaticInterpreter {
|
|||
}
|
||||
}
|
||||
|
||||
private visitVariableDeclaration(node: ts.VariableDeclaration, context: Context): ResolvedValue {
|
||||
if (node.initializer !== undefined) {
|
||||
return this.visitExpression(node.initializer, context);
|
||||
} else if (isVariableDeclarationDeclared(node)) {
|
||||
return this.getReference(node, context);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private visitEnumDeclaration(node: ts.EnumDeclaration, context: Context): ResolvedValue {
|
||||
const enumRef = this.getReference(node, context) as Reference<ts.EnumDeclaration>;
|
||||
const map = new Map<string, EnumValue>();
|
||||
|
@ -728,3 +735,16 @@ function identifierOfDeclaration(decl: ts.Declaration): ts.Identifier|undefined
|
|||
function isPossibleClassDeclaration(node: ts.Node): node is ts.Declaration {
|
||||
return ts.isClassDeclaration(node) || ts.isVariableDeclaration(node);
|
||||
}
|
||||
|
||||
function isVariableDeclarationDeclared(node: ts.VariableDeclaration): boolean {
|
||||
if (node.parent === undefined || !ts.isVariableDeclarationList(node.parent)) {
|
||||
return false;
|
||||
}
|
||||
const declList = node.parent;
|
||||
if (declList.parent === undefined || !ts.isVariableStatement(declList.parent)) {
|
||||
return false;
|
||||
}
|
||||
const varStmt = declList.parent;
|
||||
return varStmt.modifiers !== undefined &&
|
||||
varStmt.modifiers.some(mod => mod.kind === ts.SyntaxKind.DeclareKeyword);
|
||||
}
|
||||
|
|
|
@ -284,4 +284,17 @@ describe('ngtsc metadata', () => {
|
|||
expect(result.enumRef.node.name.text).toBe('Foo');
|
||||
expect(result.name).toBe('B');
|
||||
});
|
||||
|
||||
it('variable declaration resolution works', () => {
|
||||
const {program} = makeProgram([
|
||||
{name: 'decl.d.ts', contents: 'export declare let value: number;'},
|
||||
{name: 'entry.ts', contents: `import {value} from './decl'; const target$ = value;`},
|
||||
]);
|
||||
const checker = program.getTypeChecker();
|
||||
const host = new TypeScriptReflectionHost(checker);
|
||||
const result = getDeclaration(program, 'entry.ts', 'target$', ts.isVariableDeclaration);
|
||||
const res = staticallyResolve(result.initializer !, host, checker);
|
||||
console.error(res);
|
||||
expect(res instanceof Reference).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue