refactor(ngcc): simplify and rename `getClassDeclarationFromInnerDeclaration()` (#38959)
The new function does not try to restrict the kind of AST node that it finds, leaving that to the caller. This will make it more resuable in the UMD reflection host. PR Close #38959
This commit is contained in:
parent
5038e5741b
commit
1d6e67478e
|
@ -302,6 +302,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
|
|||
if (superDeclaration.known !== null || superDeclaration.identity !== null) {
|
||||
return superDeclaration;
|
||||
}
|
||||
|
||||
let declarationNode: ts.Node = superDeclaration.node;
|
||||
if (isNamedVariableDeclaration(superDeclaration.node) && !isTopLevel(superDeclaration.node)) {
|
||||
const variableValue = this.getVariableValue(superDeclaration.node);
|
||||
|
@ -310,9 +311,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
|
|||
}
|
||||
}
|
||||
|
||||
const outerClassNode = getClassDeclarationFromInnerDeclaration(declarationNode);
|
||||
const declaration = outerClassNode !== null ?
|
||||
this.getDeclarationOfIdentifier(outerClassNode.name) :
|
||||
const outerNode = getOuterNodeFromInnerDeclaration(declarationNode);
|
||||
const declaration = outerNode !== null && isNamedVariableDeclaration(outerNode) ?
|
||||
this.getDeclarationOfIdentifier(outerNode.name) :
|
||||
superDeclaration;
|
||||
if (declaration === null || declaration.node === null || declaration.known !== null) {
|
||||
return declaration;
|
||||
|
@ -2569,51 +2570,53 @@ function isTopLevel(node: ts.Node): boolean {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the actual (outer) declaration of a class.
|
||||
* Get a node that represents the actual (outer) declaration of a class from its implementation.
|
||||
*
|
||||
* Sometimes, the implementation of a class is an expression that is hidden inside an IIFE and
|
||||
* returned to be assigned to a variable outside the IIFE, which is what the rest of the program
|
||||
* interacts with.
|
||||
* assigned to a variable outside the IIFE, which is what the rest of the program interacts with.
|
||||
* For example,
|
||||
*
|
||||
* Given the inner declaration, we want to get to the declaration of the outer variable that
|
||||
* represents the class.
|
||||
* ```
|
||||
* OuterNode = Alias = (function() { function InnerNode() {} return InnerNode; })();
|
||||
* ```
|
||||
*
|
||||
* @param node a node that could be the inner declaration inside an IIFE.
|
||||
* @returns the outer variable declaration or `null` if it is not a "class".
|
||||
* @param node a node that could be the implementation inside an IIFE.
|
||||
* @returns a node that represents the outer declaration, or `null` if it is does not match the IIFE
|
||||
* format shown above.
|
||||
*/
|
||||
export function getClassDeclarationFromInnerDeclaration(node: ts.Node):
|
||||
ClassDeclaration<ts.VariableDeclaration>|null {
|
||||
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) ||
|
||||
ts.isVariableStatement(node)) {
|
||||
// It might be the function expression inside the IIFE. We need to go 5 levels up...
|
||||
|
||||
// - IIFE body.
|
||||
let outerNode = node.parent;
|
||||
if (!outerNode || !ts.isBlock(outerNode)) return null;
|
||||
|
||||
// - IIFE function expression.
|
||||
outerNode = outerNode.parent;
|
||||
if (!outerNode || (!ts.isFunctionExpression(outerNode) && !ts.isArrowFunction(outerNode))) {
|
||||
return null;
|
||||
}
|
||||
outerNode = outerNode.parent;
|
||||
|
||||
// - Parenthesis inside IIFE.
|
||||
if (outerNode && ts.isParenthesizedExpression(outerNode)) outerNode = outerNode.parent;
|
||||
|
||||
// - IIFE call expression.
|
||||
if (!outerNode || !ts.isCallExpression(outerNode)) return null;
|
||||
outerNode = outerNode.parent;
|
||||
|
||||
// - Parenthesis around IIFE.
|
||||
if (outerNode && ts.isParenthesizedExpression(outerNode)) outerNode = outerNode.parent;
|
||||
|
||||
// - Outer variable declaration.
|
||||
if (!outerNode || !ts.isVariableDeclaration(outerNode)) return null;
|
||||
|
||||
// Finally, ensure that the variable declaration has a `name` identifier.
|
||||
return hasNameIdentifier(outerNode) ? outerNode : null;
|
||||
export function getOuterNodeFromInnerDeclaration(node: ts.Node): ts.Node|null {
|
||||
if (!ts.isFunctionDeclaration(node) && !ts.isClassDeclaration(node) &&
|
||||
!ts.isVariableStatement(node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
// It might be the function expression inside the IIFE. We need to go 5 levels up...
|
||||
|
||||
// - IIFE body.
|
||||
let outerNode = node.parent;
|
||||
if (!outerNode || !ts.isBlock(outerNode)) return null;
|
||||
|
||||
// - IIFE function expression.
|
||||
outerNode = outerNode.parent;
|
||||
if (!outerNode || (!ts.isFunctionExpression(outerNode) && !ts.isArrowFunction(outerNode))) {
|
||||
return null;
|
||||
}
|
||||
outerNode = outerNode.parent;
|
||||
|
||||
// - Parenthesis inside IIFE.
|
||||
if (outerNode && ts.isParenthesizedExpression(outerNode)) outerNode = outerNode.parent;
|
||||
|
||||
// - IIFE call expression.
|
||||
if (!outerNode || !ts.isCallExpression(outerNode)) return null;
|
||||
outerNode = outerNode.parent;
|
||||
|
||||
// - Parenthesis around IIFE.
|
||||
if (outerNode && ts.isParenthesizedExpression(outerNode)) outerNode = outerNode.parent;
|
||||
|
||||
// - Skip any aliases between the IIFE and the far left hand side of any assignments.
|
||||
while (isAssignment(outerNode.parent)) {
|
||||
outerNode = outerNode.parent;
|
||||
}
|
||||
|
||||
return outerNode;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, KnownDeclaration, Parameter, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
|
||||
import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, isNamedFunctionDeclaration, KnownDeclaration, Parameter, reflectObjectLiteral} from '../../../src/ngtsc/reflection';
|
||||
import {getTsHelperFnFromDeclaration, getTsHelperFnFromIdentifier, hasNameIdentifier} from '../utils';
|
||||
|
||||
import {Esm2015ReflectionHost, getClassDeclarationFromInnerDeclaration, getPropertyValueFromSymbol, isAssignmentStatement, ParamInfo} from './esm2015_host';
|
||||
import {Esm2015ReflectionHost, getOuterNodeFromInnerDeclaration, getPropertyValueFromSymbol, isAssignmentStatement, ParamInfo} from './esm2015_host';
|
||||
import {NgccClassSymbol} from './ngcc_host';
|
||||
|
||||
|
||||
|
@ -186,16 +186,16 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost {
|
|||
return classSymbol;
|
||||
}
|
||||
|
||||
if (!ts.isFunctionDeclaration(declaration) || !hasNameIdentifier(declaration)) {
|
||||
if (!isNamedFunctionDeclaration(declaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const outerDeclaration = getClassDeclarationFromInnerDeclaration(declaration);
|
||||
if (outerDeclaration === null || !hasNameIdentifier(outerDeclaration)) {
|
||||
const outerNode = getOuterNodeFromInnerDeclaration(declaration);
|
||||
if (outerNode === null || !hasNameIdentifier(outerNode)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.createClassSymbol(outerDeclaration, declaration);
|
||||
return this.createClassSymbol(outerNode.name, declaration);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,9 +71,9 @@ export function findAll<T>(node: ts.Node, test: (node: ts.Node) => node is ts.No
|
|||
* @param declaration The declaration to test.
|
||||
* @returns true if the declaration has an identifier for a name.
|
||||
*/
|
||||
export function hasNameIdentifier(declaration: ts.Declaration): declaration is ts.Declaration&
|
||||
export function hasNameIdentifier(declaration: ts.Node): declaration is ts.Declaration&
|
||||
{name: ts.Identifier} {
|
||||
const namedDeclaration: ts.Declaration&{name?: ts.Node} = declaration;
|
||||
const namedDeclaration: ts.Node&{name?: ts.Node} = declaration;
|
||||
return namedDeclaration.name !== undefined && ts.isIdentifier(namedDeclaration.name);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue