@@ -27,47 +27,49 @@ export class ModuleWithProvidersTransform {
27
27
private partialEvaluator : PartialEvaluator =
28
28
new PartialEvaluator ( new TypeScriptReflectionHost ( this . typeChecker ) , this . typeChecker ) ;
29
29
30
- /** Set of methods which were already checked or migrated. */
31
- private visitedMethods = new Set < ts . MethodDeclaration > ( ) ;
32
-
33
30
constructor (
34
31
private typeChecker : ts . TypeChecker ,
35
32
private getUpdateRecorder : ( sf : ts . SourceFile ) => UpdateRecorder ) { }
36
33
37
34
/** Migrates a given NgModule by walking through the referenced providers and static methods. */
38
35
migrateModule ( module : ResolvedNgModule ) : AnalysisFailure [ ] {
39
- return module . staticMethodsWithoutType . map ( this . _resolveStaticMethod . bind ( this ) )
36
+ return module . staticMethodsWithoutType . map ( this . _migrateStaticNgModuleMethod . bind ( this ) )
40
37
. filter ( v => v ) as AnalysisFailure [ ] ;
41
38
}
42
39
43
40
/** Migrates a ModuleWithProviders type definition that has no explicit generic type */
44
- migrateType ( type : ts . TypeReferenceNode ) {
41
+ migrateType ( type : ts . TypeReferenceNode ) : AnalysisFailure [ ] {
45
42
const parent = type . parent ;
46
43
let moduleText : string | undefined ;
47
44
if ( ( ts . isFunctionDeclaration ( parent ) || ts . isMethodDeclaration ( parent ) ) && parent . body ) {
48
45
const returnStatement = parent . body . statements . find ( ts . isReturnStatement ) ;
49
- moduleText = this . _getReturnStatementNgModuleType ( returnStatement ) ;
46
+
47
+ // No return type found, exit
48
+ if ( ! returnStatement || ! returnStatement . expression ) {
49
+ return [ { node : parent , message : `Return type is not statically analyzable.` } ] ;
50
+ }
51
+
52
+ moduleText = this . _getNgModuleTypeOfExpression ( returnStatement . expression ) ;
50
53
} else if ( ts . isPropertyDeclaration ( parent ) || ts . isVariableDeclaration ( parent ) ) {
51
54
if ( ! parent . initializer ) {
52
55
addTodoToNode ( type , TODO_COMMENT ) ;
53
56
this . _updateNode ( type , type ) ;
54
57
return [ { node : parent , message : `Unable to determine type for declaration.` } ] ;
55
58
}
56
59
57
- const evaluatedExpr = this . partialEvaluator . evaluate ( parent . initializer ) ;
58
- moduleText = this . _visitObjectLiteralExpressionResolvedValue ( evaluatedExpr ) ;
60
+ moduleText = this . _getNgModuleTypeOfExpression ( parent . initializer ) ;
59
61
}
60
62
61
63
if ( moduleText ) {
62
- this . migrateTypeReferenceNode ( type , moduleText ) ;
64
+ this . _addGenericToTypeReference ( type , moduleText ) ;
63
65
return [ ] ;
64
66
}
65
67
66
68
return [ { node : parent , message : `Type is not statically analyzable.` } ] ;
67
69
}
68
70
69
71
/** Add a given generic to a type reference node */
70
- migrateTypeReferenceNode ( node : ts . TypeReferenceNode , typeName : string ) {
72
+ private _addGenericToTypeReference ( node : ts . TypeReferenceNode , typeName : string ) {
71
73
const newGenericExpr = createModuleWithProvidersType ( typeName , node ) ;
72
74
this . _updateNode ( node , newGenericExpr ) ;
73
75
}
@@ -76,12 +78,7 @@ export class ModuleWithProvidersTransform {
76
78
* Migrates a given static method if its ModuleWithProviders does not provide
77
79
* a generic type.
78
80
*/
79
- migrateStaticMethod ( method : ts . MethodDeclaration , typeName : string ) {
80
- if ( this . visitedMethods . has ( method ) ) {
81
- return ;
82
- }
83
- this . visitedMethods . add ( method ) ;
84
-
81
+ private _updateStaticMethodType ( method : ts . MethodDeclaration , typeName : string ) {
85
82
const newGenericExpr =
86
83
createModuleWithProvidersType ( typeName , method . type as ts . TypeReferenceNode ) ;
87
84
const newMethodDecl = ts . updateMethod (
@@ -100,33 +97,38 @@ export class ModuleWithProvidersTransform {
100
97
return ngModule && ( value . size === 1 || ( providers && value . size === 2 ) ) ;
101
98
}
102
99
103
- /** Determine the generic type of a suspected ModuleWithProviders return type */
104
- private _resolveStaticMethod ( node : ts . MethodDeclaration ) : AnalysisFailure | null {
105
- const returnStatement : ts . ReturnStatement | undefined = node . body &&
100
+ /** Determine the generic type of a suspected ModuleWithProviders return type and add it
101
+ * explicitly */
102
+ private _migrateStaticNgModuleMethod ( node : ts . MethodDeclaration ) : AnalysisFailure | null {
103
+ const returnStatement = node . body &&
106
104
node . body . statements . find ( n => ts . isReturnStatement ( n ) ) as ts . ReturnStatement | undefined ;
107
- const moduleText = this . _getReturnStatementNgModuleType ( returnStatement ) ;
105
+
106
+ // No return type found, exit
107
+ if ( ! returnStatement || ! returnStatement . expression ) {
108
+ return { node : node , message : `Return type is not statically analyzable.` } ;
109
+ }
110
+
111
+ const moduleText = this . _getNgModuleTypeOfExpression ( returnStatement . expression ) ;
108
112
109
113
if ( moduleText ) {
110
- this . migrateStaticMethod ( node , moduleText ) ;
114
+ this . _updateStaticMethodType ( node , moduleText ) ;
111
115
return null ;
112
116
}
113
117
114
118
return { node : node , message : `Method type is not statically analyzable.` } ;
115
119
}
116
120
117
- /** Evaluate and return the ngModule type from a method or function's return statement */
118
- private _getReturnStatementNgModuleType ( returnStatement ?: ts . ReturnStatement ) : string | undefined {
119
- // No return type found, exit
120
- if ( ! returnStatement || ! returnStatement . expression ) {
121
- return ;
122
- }
123
-
124
- const evaluatedExpr = this . partialEvaluator . evaluate ( returnStatement . expression ) ;
125
- return this . _visitObjectLiteralExpressionResolvedValue ( evaluatedExpr ) ;
121
+ /** Evaluate and return the ngModule type from an expression */
122
+ private _getNgModuleTypeOfExpression ( expr : ts . Expression ) : string | undefined {
123
+ const evaluatedExpr = this . partialEvaluator . evaluate ( expr ) ;
124
+ return this . _getTypeOfResolvedValue ( evaluatedExpr ) ;
126
125
}
127
126
128
- /** Visits a given object literal expression to determine the ngModule type. */
129
- private _visitObjectLiteralExpressionResolvedValue ( value : ResolvedValue ) : string | undefined {
127
+ /**
128
+ * Visits a given object literal expression to determine the ngModule type. If the expression
129
+ * cannot be resolved, add a TODO to alert the user.
130
+ */
131
+ private _getTypeOfResolvedValue ( value : ResolvedValue ) : string | undefined {
130
132
if ( value instanceof Map && this . isModuleWithProvidersType ( value ) ) {
131
133
const mapValue = value . get ( 'ngModule' ) ! ;
132
134
if ( mapValue instanceof Reference && ts . isClassDeclaration ( mapValue . node ) &&
0 commit comments