ts2famix 2.1.0-beta.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +24 -24
- package/LICENSE +24 -24
- package/README.md +78 -78
- package/dist/analyze.js +3 -3
- package/dist/analyze_functions/process_functions.js +92 -62
- package/dist/famix_functions/EntityDictionary.js +672 -597
- package/dist/famix_functions/helpers_creation.js +18 -12
- package/dist/fqn.js +351 -18
- package/dist/lib/famix/famix_JSON_exporter.js +1 -1
- package/dist/lib/famix/famix_base_element.js +1 -1
- package/dist/lib/famix/famix_repository.js +14 -5
- package/dist/lib/famix/index.js +1 -1
- package/dist/lib/famix/model/famix/access.js +1 -1
- package/dist/lib/famix/model/famix/accessor.js +1 -1
- package/dist/lib/famix/model/famix/alias.js +1 -1
- package/dist/lib/famix/model/famix/arrow_function.js +1 -1
- package/dist/lib/famix/model/famix/behavioral_entity.js +1 -1
- package/dist/lib/famix/model/famix/class.js +1 -1
- package/dist/lib/famix/model/famix/comment.js +1 -1
- package/dist/lib/famix/model/famix/concretisation.js +1 -1
- package/dist/lib/famix/model/famix/container_entity.js +1 -1
- package/dist/lib/famix/model/famix/decorator.js +1 -1
- package/dist/lib/famix/model/famix/entity.js +1 -1
- package/dist/lib/famix/model/famix/enum.js +1 -1
- package/dist/lib/famix/model/famix/enum_value.js +1 -1
- package/dist/lib/famix/model/famix/function.js +1 -1
- package/dist/lib/famix/model/famix/import_clause.js +1 -1
- package/dist/lib/famix/model/famix/index.js +1 -1
- package/dist/lib/famix/model/famix/indexed_file_anchor.js +1 -1
- package/dist/lib/famix/model/famix/inheritance.js +1 -1
- package/dist/lib/famix/model/famix/interface.js +1 -1
- package/dist/lib/famix/model/famix/invocation.js +1 -1
- package/dist/lib/famix/model/famix/method.js +1 -1
- package/dist/lib/famix/model/famix/module.js +2 -2
- package/dist/lib/famix/model/famix/named_entity.js +1 -1
- package/dist/lib/famix/model/famix/parameter.js +1 -1
- package/dist/lib/famix/model/famix/parameter_concretisation.js +1 -1
- package/dist/lib/famix/model/famix/parameter_type.js +1 -1
- package/dist/lib/famix/model/famix/parametric_arrow_function.js +1 -1
- package/dist/lib/famix/model/famix/parametric_class.js +1 -1
- package/dist/lib/famix/model/famix/parametric_function.js +1 -1
- package/dist/lib/famix/model/famix/parametric_interface.js +1 -1
- package/dist/lib/famix/model/famix/parametric_method.js +1 -1
- package/dist/lib/famix/model/famix/primitive_type.js +1 -1
- package/dist/lib/famix/model/famix/property.js +1 -1
- package/dist/lib/famix/model/famix/reference.js +1 -1
- package/dist/lib/famix/model/famix/scoping_entity.js +1 -1
- package/dist/lib/famix/model/famix/script_entity.js +1 -1
- package/dist/lib/famix/model/famix/source_anchor.js +1 -1
- package/dist/lib/famix/model/famix/source_language.js +1 -1
- package/dist/lib/famix/model/famix/sourced_entity.js +1 -1
- package/dist/lib/famix/model/famix/structural_entity.js +1 -1
- package/dist/lib/famix/model/famix/type.js +1 -1
- package/dist/lib/famix/model/famix/variable.js +1 -1
- package/dist/lib/ts-complex/cyclomatic-service.js +1 -1
- package/dist/refactorer/refactor-getter-setter.js +1 -1
- package/dist/ts2famix-cli-wrapper.js +1 -1
- package/dist/ts2famix-cli.js +1 -1
- package/doc-uml/famix-typescript-model.puml +619 -607
- package/doc-uml/famix-typescript-model.svg +1 -1
- package/eslint.config.mjs +28 -28
- package/jest.config.json +1 -1
- package/package.json +70 -70
- package/src/analyze.ts +120 -120
- package/src/analyze_functions/process_functions.ts +1069 -1040
- package/src/famix_functions/EntityDictionary.ts +2061 -2016
- package/src/famix_functions/helpers_creation.ts +143 -135
- package/src/fqn.ts +416 -50
- package/src/generate_uml.sh +20 -20
- package/src/lib/famix/License.md +22 -22
- package/src/lib/famix/famix_JSON_exporter.ts +56 -56
- package/src/lib/famix/famix_base_element.ts +22 -22
- package/src/lib/famix/famix_repository.ts +288 -278
- package/src/lib/famix/index.ts +8 -8
- package/src/lib/famix/model/famix/access.ts +50 -50
- package/src/lib/famix/model/famix/accessor.ts +15 -15
- package/src/lib/famix/model/famix/alias.ts +39 -39
- package/src/lib/famix/model/famix/arrow_function.ts +15 -15
- package/src/lib/famix/model/famix/behavioral_entity.ts +97 -97
- package/src/lib/famix/model/famix/class.ts +85 -85
- package/src/lib/famix/model/famix/comment.ts +47 -47
- package/src/lib/famix/model/famix/concretisation.ts +40 -40
- package/src/lib/famix/model/famix/container_entity.ts +160 -160
- package/src/lib/famix/model/famix/decorator.ts +37 -37
- package/src/lib/famix/model/famix/entity.ts +15 -15
- package/src/lib/famix/model/famix/enum.ts +30 -30
- package/src/lib/famix/model/famix/enum_value.ts +28 -28
- package/src/lib/famix/model/famix/function.ts +15 -15
- package/src/lib/famix/model/famix/import_clause.ts +51 -51
- package/src/lib/famix/model/famix/index.ts +41 -41
- package/src/lib/famix/model/famix/indexed_file_anchor.ts +46 -46
- package/src/lib/famix/model/famix/inheritance.ts +40 -40
- package/src/lib/famix/model/famix/interface.ts +75 -75
- package/src/lib/famix/model/famix/invocation.ts +65 -65
- package/src/lib/famix/model/famix/method.ts +89 -89
- package/src/lib/famix/model/famix/module.ts +71 -71
- package/src/lib/famix/model/famix/named_entity.ts +95 -95
- package/src/lib/famix/model/famix/parameter.ts +28 -28
- package/src/lib/famix/model/famix/parameter_concretisation.ts +51 -51
- package/src/lib/famix/model/famix/parameter_type.ts +58 -58
- package/src/lib/famix/model/famix/parametric_arrow_function.ts +32 -32
- package/src/lib/famix/model/famix/parametric_class.ts +49 -49
- package/src/lib/famix/model/famix/parametric_function.ts +32 -32
- package/src/lib/famix/model/famix/parametric_interface.ts +49 -49
- package/src/lib/famix/model/famix/parametric_method.ts +32 -32
- package/src/lib/famix/model/famix/primitive_type.ts +15 -15
- package/src/lib/famix/model/famix/property.ts +94 -94
- package/src/lib/famix/model/famix/reference.ts +40 -40
- package/src/lib/famix/model/famix/scoping_entity.ts +35 -35
- package/src/lib/famix/model/famix/script_entity.ts +34 -34
- package/src/lib/famix/model/famix/source_anchor.ts +30 -30
- package/src/lib/famix/model/famix/source_language.ts +35 -35
- package/src/lib/famix/model/famix/sourced_entity.ts +70 -70
- package/src/lib/famix/model/famix/structural_entity.ts +43 -43
- package/src/lib/famix/model/famix/type.ts +87 -87
- package/src/lib/famix/model/famix/variable.ts +27 -27
- package/src/lib/famix/package.json +28 -28
- package/src/lib/ts-complex/cyclomatic-service.ts +83 -83
- package/src/refactorer/refactor-getter-setter.ts +140 -140
- package/src/ts2famix-cli-wrapper.ts +21 -21
- package/src/ts2famix-cli.ts +60 -60
- package/tsconfig.check-tests.json +14 -14
- package/tsconfig.json +73 -72
- package/.vscode/settings.json +0 -4
- package/TODO +0 -1
- package/arwea-fix.json +0 -1
- package/bogus.ts +0 -3
- package/class-diagram.puml +0 -792
- package/debug.txt +0 -13332
- package/debuglog.txt +0 -12073
- package/dist/famix2puml.js +0 -126
- package/dist/getClasses-arrow-body.js +0 -43
- package/dist/lib/famix/src/famix_JSON_exporter.js +0 -55
- package/dist/lib/famix/src/famix_base_element.js +0 -18
- package/dist/lib/famix/src/famix_repository.js +0 -224
- package/dist/lib/famix/src/index.js +0 -31
- package/dist/lib/famix/src/model/famix/access.js +0 -40
- package/dist/lib/famix/src/model/famix/accessor.js +0 -17
- package/dist/lib/famix/src/model/famix/alias.js +0 -33
- package/dist/lib/famix/src/model/famix/arrowFunction.js +0 -17
- package/dist/lib/famix/src/model/famix/arrow_function.js +0 -17
- package/dist/lib/famix/src/model/famix/behavioral_entity.js +0 -79
- package/dist/lib/famix/src/model/famix/class.js +0 -71
- package/dist/lib/famix/src/model/famix/comment.js +0 -39
- package/dist/lib/famix/src/model/famix/concretisation.js +0 -31
- package/dist/lib/famix/src/model/famix/container_entity.js +0 -126
- package/dist/lib/famix/src/model/famix/decorator.js +0 -32
- package/dist/lib/famix/src/model/famix/entity.js +0 -17
- package/dist/lib/famix/src/model/famix/enum.js +0 -31
- package/dist/lib/famix/src/model/famix/enum_value.js +0 -25
- package/dist/lib/famix/src/model/famix/function.js +0 -17
- package/dist/lib/famix/src/model/famix/implicit_variable.js +0 -17
- package/dist/lib/famix/src/model/famix/import_clause.js +0 -41
- package/dist/lib/famix/src/model/famix/index.js +0 -86
- package/dist/lib/famix/src/model/famix/indexed_file_anchor.js +0 -38
- package/dist/lib/famix/src/model/famix/inheritance.js +0 -33
- package/dist/lib/famix/src/model/famix/interface.js +0 -64
- package/dist/lib/famix/src/model/famix/invocation.js +0 -54
- package/dist/lib/famix/src/model/famix/method.js +0 -67
- package/dist/lib/famix/src/model/famix/module.js +0 -60
- package/dist/lib/famix/src/model/famix/named_entity.js +0 -78
- package/dist/lib/famix/src/model/famix/parameter.js +0 -25
- package/dist/lib/famix/src/model/famix/parameterConcretisation.js +0 -44
- package/dist/lib/famix/src/model/famix/parameter_concretisation.js +0 -44
- package/dist/lib/famix/src/model/famix/parameter_type.js +0 -45
- package/dist/lib/famix/src/model/famix/parametricArrowFunction.js +0 -29
- package/dist/lib/famix/src/model/famix/parametric_arrow_function.js +0 -31
- package/dist/lib/famix/src/model/famix/parametric_class.js +0 -44
- package/dist/lib/famix/src/model/famix/parametric_function.js +0 -31
- package/dist/lib/famix/src/model/famix/parametric_interface.js +0 -44
- package/dist/lib/famix/src/model/famix/parametric_method.js +0 -31
- package/dist/lib/famix/src/model/famix/primitive_type.js +0 -17
- package/dist/lib/famix/src/model/famix/property.js +0 -73
- package/dist/lib/famix/src/model/famix/reference.js +0 -33
- package/dist/lib/famix/src/model/famix/scoping_entity.js +0 -36
- package/dist/lib/famix/src/model/famix/script_entity.js +0 -29
- package/dist/lib/famix/src/model/famix/source_anchor.js +0 -27
- package/dist/lib/famix/src/model/famix/source_language.js +0 -35
- package/dist/lib/famix/src/model/famix/sourced_entity.js +0 -60
- package/dist/lib/famix/src/model/famix/structural_entity.js +0 -39
- package/dist/lib/famix/src/model/famix/text_anchor.js +0 -38
- package/dist/lib/famix/src/model/famix/type.js +0 -73
- package/dist/lib/famix/src/model/famix/variable.js +0 -24
- package/fqn-model.json +0 -1
- package/iterateGenericTypes.ts +0 -69
- package/out/class-diagram/class-diagram.svg +0 -1
- package/sample.json +0 -1
- package/sample.ts +0 -1
- package/stats.txt +0 -3091
- package/tabby-debug-output.txt +0 -19433
- package/ts2famix.log +0 -22656
- package/validate-references.js +0 -103
|
@@ -1,1040 +1,1069 @@
|
|
|
1
|
-
import { ClassDeclaration, MethodDeclaration, VariableStatement, FunctionDeclaration, VariableDeclaration, InterfaceDeclaration, ParameterDeclaration, ConstructorDeclaration, MethodSignature, SourceFile, ModuleDeclaration, PropertyDeclaration, PropertySignature, Decorator, GetAccessorDeclaration, SetAccessorDeclaration, ExportedDeclarations, CommentRange, EnumDeclaration, EnumMember, TypeParameterDeclaration, TypeAliasDeclaration, SyntaxKind, FunctionExpression, Block, Identifier, ExpressionWithTypeArguments, ImportDeclaration, Node, ArrowFunction, Scope, ClassExpression } from "ts-morph";
|
|
2
|
-
import * as Famix from "../lib/famix/model/famix";
|
|
3
|
-
import { calculate } from "../lib/ts-complex/cyclomatic-service";
|
|
4
|
-
import * as fs from 'fs';
|
|
5
|
-
import { logger, entityDictionary } from "../analyze";
|
|
6
|
-
import { getFQN } from "../fqn";
|
|
7
|
-
import { InvocableType } from "src/famix_functions/EntityDictionary";
|
|
8
|
-
|
|
9
|
-
export type AccessibleTSMorphElement = ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember;
|
|
10
|
-
export type FamixID = number;
|
|
11
|
-
|
|
12
|
-
export const methodsAndFunctionsWithId = new Map<number, InvocableType>(); // Maps the Famix method, constructor, getter, setter and function ids to their ts-morph method, constructor, getter, setter or function object
|
|
13
|
-
|
|
14
|
-
export const accessMap = new Map<FamixID, AccessibleTSMorphElement>(); // Maps the Famix parameter, variable, property and enum value ids to their ts-morph parameter, variable, property or enum member object
|
|
15
|
-
export const classes = new Array<ClassDeclaration>(); // Array of all the classes of the source files
|
|
16
|
-
export const interfaces = new Array<InterfaceDeclaration>(); // Array of all the interfaces of the source files
|
|
17
|
-
export const modules = new Array<SourceFile>(); // Array of all the source files which are modules
|
|
18
|
-
export const listOfExportMaps = new Array<ReadonlyMap<string, ExportedDeclarations[]>>(); // Array of all the export maps
|
|
19
|
-
export let currentCC: { [key: string]: number }; // Stores the cyclomatic complexity metrics for the current source file
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*
|
|
24
|
-
* @
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
* @
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*
|
|
55
|
-
* @
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
*
|
|
275
|
-
* @param
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
logger.debug(`Finding
|
|
300
|
-
m.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
*
|
|
309
|
-
* @
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
*
|
|
323
|
-
* @
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
c
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (m instanceof
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Builds a Famix model for the
|
|
518
|
-
* @param
|
|
519
|
-
* @param fmxScope The Famix model of the
|
|
520
|
-
*/
|
|
521
|
-
function
|
|
522
|
-
logger.debug(`Finding
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
//
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
property
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
//
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
scope
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
logger.debug(`
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
*
|
|
762
|
-
* @param
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
*
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
logger.debug(`
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
//
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1
|
+
import { ClassDeclaration, MethodDeclaration, VariableStatement, FunctionDeclaration, VariableDeclaration, InterfaceDeclaration, ParameterDeclaration, ConstructorDeclaration, MethodSignature, SourceFile, ModuleDeclaration, PropertyDeclaration, PropertySignature, Decorator, GetAccessorDeclaration, SetAccessorDeclaration, ExportedDeclarations, CommentRange, EnumDeclaration, EnumMember, TypeParameterDeclaration, TypeAliasDeclaration, SyntaxKind, FunctionExpression, Block, Identifier, ExpressionWithTypeArguments, ImportDeclaration, Node, ArrowFunction, Scope, ClassExpression } from "ts-morph";
|
|
2
|
+
import * as Famix from "../lib/famix/model/famix";
|
|
3
|
+
import { calculate } from "../lib/ts-complex/cyclomatic-service";
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import { logger, entityDictionary } from "../analyze";
|
|
6
|
+
import { getFQN } from "../fqn";
|
|
7
|
+
import { InvocableType } from "src/famix_functions/EntityDictionary";
|
|
8
|
+
|
|
9
|
+
export type AccessibleTSMorphElement = ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember;
|
|
10
|
+
export type FamixID = number;
|
|
11
|
+
|
|
12
|
+
export const methodsAndFunctionsWithId = new Map<number, InvocableType>(); // Maps the Famix method, constructor, getter, setter and function ids to their ts-morph method, constructor, getter, setter or function object
|
|
13
|
+
|
|
14
|
+
export const accessMap = new Map<FamixID, AccessibleTSMorphElement>(); // Maps the Famix parameter, variable, property and enum value ids to their ts-morph parameter, variable, property or enum member object
|
|
15
|
+
export const classes = new Array<ClassDeclaration>(); // Array of all the classes of the source files
|
|
16
|
+
export const interfaces = new Array<InterfaceDeclaration>(); // Array of all the interfaces of the source files
|
|
17
|
+
export const modules = new Array<SourceFile>(); // Array of all the source files which are modules
|
|
18
|
+
export const listOfExportMaps = new Array<ReadonlyMap<string, ExportedDeclarations[]>>(); // Array of all the export maps
|
|
19
|
+
export let currentCC: { [key: string]: number }; // Stores the cyclomatic complexity metrics for the current source file
|
|
20
|
+
const processedNodesWithTypeParams = new Set<number>(); // Set of nodes that have been processed and have type parameters
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Checks if the file has any imports or exports to be considered a module
|
|
24
|
+
* @param sourceFile A source file
|
|
25
|
+
* @returns A boolean indicating if the file is a module
|
|
26
|
+
*/
|
|
27
|
+
function isSourceFileAModule(sourceFile: SourceFile): boolean {
|
|
28
|
+
return sourceFile.getImportDeclarations().length > 0 || sourceFile.getExportedDeclarations().size > 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gets the path of a module to be imported
|
|
33
|
+
* @param importDecl An import declaration
|
|
34
|
+
* @returns The path of the module to be imported
|
|
35
|
+
*/
|
|
36
|
+
export function getModulePath(importDecl: ImportDeclaration): string {
|
|
37
|
+
let path: string;
|
|
38
|
+
if (importDecl.getModuleSpecifierSourceFile() === undefined) {
|
|
39
|
+
if (importDecl.getModuleSpecifierValue().substring(importDecl.getModuleSpecifierValue().length - 3) === ".ts") {
|
|
40
|
+
path = importDecl.getModuleSpecifierValue();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
path = importDecl.getModuleSpecifierValue() + ".ts";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
path = importDecl.getModuleSpecifierSourceFile()!.getFilePath();
|
|
48
|
+
}
|
|
49
|
+
return path;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Gets the interfaces implemented or extended by a class or an interface
|
|
55
|
+
* @param interfaces An array of interfaces
|
|
56
|
+
* @param subClass A class or an interface
|
|
57
|
+
* @returns An array of InterfaceDeclaration and ExpressionWithTypeArguments containing the interfaces implemented or extended by the subClass
|
|
58
|
+
*/
|
|
59
|
+
export function getImplementedOrExtendedInterfaces(interfaces: Array<InterfaceDeclaration>, subClass: ClassDeclaration | InterfaceDeclaration): Array<InterfaceDeclaration | ExpressionWithTypeArguments> {
|
|
60
|
+
let impOrExtInterfaces: Array<ExpressionWithTypeArguments>;
|
|
61
|
+
if (subClass instanceof ClassDeclaration) {
|
|
62
|
+
impOrExtInterfaces = subClass.getImplements();
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
impOrExtInterfaces = subClass.getExtends();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const interfacesNames = interfaces.map(i => i.getName());
|
|
69
|
+
const implementedOrExtendedInterfaces = new Array<InterfaceDeclaration | ExpressionWithTypeArguments>();
|
|
70
|
+
|
|
71
|
+
impOrExtInterfaces.forEach(i => {
|
|
72
|
+
if (interfacesNames.includes(i.getExpression().getText())) {
|
|
73
|
+
implementedOrExtendedInterfaces.push(interfaces[interfacesNames.indexOf(i.getExpression().getText())]);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
implementedOrExtendedInterfaces.push(i);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return implementedOrExtendedInterfaces;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function processFiles(sourceFiles: Array<SourceFile>): void {
|
|
84
|
+
sourceFiles.forEach(file => {
|
|
85
|
+
logger.info(`File: >>>>>>>>>> ${file.getFilePath()}`);
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(file.getFilePath())) {
|
|
88
|
+
currentCC = calculate(file.getFilePath());
|
|
89
|
+
} else {
|
|
90
|
+
currentCC = {};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
processFile(file);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Builds a Famix model for a source file
|
|
99
|
+
* @param f A source file
|
|
100
|
+
*/
|
|
101
|
+
function processFile(f: SourceFile): void {
|
|
102
|
+
const isModule = isSourceFileAModule(f);
|
|
103
|
+
|
|
104
|
+
if (isModule) {
|
|
105
|
+
modules.push(f);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const exportMap = f.getExportedDeclarations();
|
|
109
|
+
if (exportMap) listOfExportMaps.push(exportMap);
|
|
110
|
+
|
|
111
|
+
const fmxFile = entityDictionary.createOrGetFamixFile(f, isModule);
|
|
112
|
+
|
|
113
|
+
logger.debug(`processFile: file: ${f.getBaseName()}, fqn = ${fmxFile.fullyQualifiedName}`);
|
|
114
|
+
|
|
115
|
+
processComments(f, fmxFile);
|
|
116
|
+
processAliases(f, fmxFile);
|
|
117
|
+
processClasses(f, fmxFile);
|
|
118
|
+
processInterfaces(f, fmxFile);
|
|
119
|
+
processModules(f, fmxFile);
|
|
120
|
+
processVariables(f, fmxFile); // This will handle our object literal methods
|
|
121
|
+
processEnums(f, fmxFile);
|
|
122
|
+
processFunctions(f, fmxFile);
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
export function isAmbient(node: ModuleDeclaration): boolean {
|
|
129
|
+
// An ambient module has the DeclareKeyword modifier.
|
|
130
|
+
return (node.getModifiers()?.some(modifier => modifier.getKind() === SyntaxKind.DeclareKeyword)) ?? false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function isNamespace(node: ModuleDeclaration): boolean {
|
|
134
|
+
// Check if the module declaration has a namespace keyword.
|
|
135
|
+
// This approach uses the getChildren() method to inspect the syntax directly.
|
|
136
|
+
return node.getChildrenOfKind(SyntaxKind.NamespaceKeyword).length > 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Builds a Famix model for a module (also namespace)
|
|
141
|
+
* @param m A namespace
|
|
142
|
+
* @returns A Famix.Module representing the module
|
|
143
|
+
*/
|
|
144
|
+
function processModule(m: ModuleDeclaration): Famix.Module {
|
|
145
|
+
const fmxModule = entityDictionary.createOrGetFamixModule(m);
|
|
146
|
+
|
|
147
|
+
logger.debug(`module: ${m.getName()}, (${m.getType().getText()}), ${fmxModule.fullyQualifiedName}`);
|
|
148
|
+
|
|
149
|
+
processComments(m, fmxModule);
|
|
150
|
+
|
|
151
|
+
processAliases(m, fmxModule);
|
|
152
|
+
|
|
153
|
+
processClasses(m, fmxModule);
|
|
154
|
+
|
|
155
|
+
processInterfaces(m, fmxModule);
|
|
156
|
+
|
|
157
|
+
processVariables(m, fmxModule);
|
|
158
|
+
|
|
159
|
+
processEnums(m, fmxModule);
|
|
160
|
+
|
|
161
|
+
processFunctions(m, fmxModule);
|
|
162
|
+
|
|
163
|
+
processModules(m, fmxModule);
|
|
164
|
+
|
|
165
|
+
return fmxModule;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
type ContainerTypes = SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ArrowFunction;
|
|
169
|
+
|
|
170
|
+
type ScopedTypes = Famix.ScriptEntity | Famix.Module | Famix.Function | Famix.Method | Famix.Accessor;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Builds a Famix model for the aliases of a container
|
|
174
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
175
|
+
* @param fmxScope The Famix model of the container
|
|
176
|
+
*/
|
|
177
|
+
function processAliases(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
178
|
+
logger.debug(`processAliases: ---------- Finding Aliases:`);
|
|
179
|
+
m.getTypeAliases().forEach(a => {
|
|
180
|
+
const fmxAlias = processAlias(a);
|
|
181
|
+
fmxScope.addAlias(fmxAlias);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Builds a Famix model for the classes of a container
|
|
187
|
+
* @param m A container (a source file or a namespace)
|
|
188
|
+
* @param fmxScope The Famix model of the container
|
|
189
|
+
*/
|
|
190
|
+
function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
191
|
+
logger.debug(`processClasses: ---------- Finding Classes:`);
|
|
192
|
+
const classesInArrowFunctions = getClassesDeclaredInArrowFunctions(m);
|
|
193
|
+
const classes = m.getClasses().concat(classesInArrowFunctions);
|
|
194
|
+
classes.forEach(c => {
|
|
195
|
+
const fmxClass = processClass(c);
|
|
196
|
+
fmxScope.addType(fmxClass);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function getArrowFunctionClasses(f: ArrowFunction): ClassDeclaration[] {
|
|
201
|
+
const classes: ClassDeclaration[] = [];
|
|
202
|
+
|
|
203
|
+
function findClasses(node: Node) {
|
|
204
|
+
if (node.getKind() === SyntaxKind.ClassDeclaration) {
|
|
205
|
+
classes.push(node as ClassDeclaration);
|
|
206
|
+
}
|
|
207
|
+
node.getChildren().forEach(findClasses);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
findClasses(f);
|
|
211
|
+
return classes;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* ts-morph doesn't find classes in arrow functions, so we need to find them manually
|
|
216
|
+
* @param s A source file
|
|
217
|
+
* @returns the ClassDeclaration objects found in arrow functions of the source file
|
|
218
|
+
*/
|
|
219
|
+
function getClassesDeclaredInArrowFunctions(s: SourceFile | ModuleDeclaration): ClassDeclaration[] {
|
|
220
|
+
const arrowFunctions = s.getDescendantsOfKind(SyntaxKind.ArrowFunction);
|
|
221
|
+
const classesInArrowFunctions = arrowFunctions.map(f => getArrowFunctionClasses(f)).flat();
|
|
222
|
+
return classesInArrowFunctions;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Builds a Famix model for the interfaces of a container
|
|
227
|
+
* @param m A container (a source file or a namespace)
|
|
228
|
+
* @param fmxScope The Famix model of the container
|
|
229
|
+
*/
|
|
230
|
+
function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
231
|
+
logger.debug(`processInterfaces: ---------- Finding Interfaces:`);
|
|
232
|
+
m.getInterfaces().forEach(i => {
|
|
233
|
+
const fmxInterface = processInterface(i);
|
|
234
|
+
fmxScope.addType(fmxInterface);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Builds a Famix model for the variables of a container
|
|
240
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
241
|
+
* @param fmxScope The Famix model of the container
|
|
242
|
+
*/
|
|
243
|
+
function processVariables(m: ContainerTypes, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
244
|
+
logger.debug(`processVariables: ---------- Finding Variables:`);
|
|
245
|
+
m.getVariableStatements().forEach(v => {
|
|
246
|
+
const fmxVariables = processVariableStatement(v);
|
|
247
|
+
fmxVariables.forEach(fmxVariable => {
|
|
248
|
+
fmxScope.addVariable(fmxVariable);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Check each VariableDeclaration for object literal methods
|
|
252
|
+
v.getDeclarations().forEach(varDecl => {
|
|
253
|
+
const varName = varDecl.getName();
|
|
254
|
+
console.log(`Checking variable: ${varName} at pos=${varDecl.getStart()}`);
|
|
255
|
+
const initializer = varDecl.getInitializer();
|
|
256
|
+
if (initializer && Node.isObjectLiteralExpression(initializer)) {
|
|
257
|
+
initializer.getProperties().forEach(prop => {
|
|
258
|
+
if (Node.isPropertyAssignment(prop)) {
|
|
259
|
+
const nested = prop.getInitializer();
|
|
260
|
+
if (nested && Node.isObjectLiteralExpression(nested)) {
|
|
261
|
+
nested.getDescendantsOfKind(SyntaxKind.MethodDeclaration).forEach(method => {
|
|
262
|
+
console.log(`Found object literal method: ${method.getName()} at pos=${method.getStart()}`);
|
|
263
|
+
entityDictionary.createOrGetFamixMethod(method, currentCC);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Builds a Famix model for the enums of a container
|
|
275
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
276
|
+
* @param fmxScope The Famix model of the container
|
|
277
|
+
*/
|
|
278
|
+
function processEnums(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
279
|
+
logger.debug(`processEnums: ---------- Finding Enums:`);
|
|
280
|
+
m.getEnums().forEach(e => {
|
|
281
|
+
const fmxEnum = processEnum(e);
|
|
282
|
+
fmxScope.addType(fmxEnum);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Builds a Famix model for the functions of a container
|
|
288
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
289
|
+
* @param fmxScope The Famix model of the container
|
|
290
|
+
*/
|
|
291
|
+
function processFunctions(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
292
|
+
logger.debug(`Finding Functions:`);
|
|
293
|
+
m.getFunctions().forEach(f => {
|
|
294
|
+
const fmxFunction = processFunction(f);
|
|
295
|
+
fmxScope.addFunction(fmxFunction);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
//find arrow functions
|
|
299
|
+
logger.debug(`Finding Functions:`);
|
|
300
|
+
const arrowFunctions = m.getDescendantsOfKind(SyntaxKind.ArrowFunction);
|
|
301
|
+
arrowFunctions.forEach(af => {
|
|
302
|
+
const fmxFunction = processFunction(af);
|
|
303
|
+
fmxScope.addFunction(fmxFunction);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Builds a Famix model for the modules of a container.
|
|
309
|
+
* @param m A container (a source file or a namespace)
|
|
310
|
+
* @param fmxScope The Famix model of the container
|
|
311
|
+
*/
|
|
312
|
+
function processModules(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
313
|
+
logger.debug(`Finding Modules:`);
|
|
314
|
+
m.getModules().forEach(md => {
|
|
315
|
+
const fmxModule = processModule(md);
|
|
316
|
+
fmxScope.addModule(fmxModule);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Builds a Famix model for an alias
|
|
322
|
+
* @param a An alias
|
|
323
|
+
* @returns A Famix.Alias representing the alias
|
|
324
|
+
*/
|
|
325
|
+
function processAlias(a: TypeAliasDeclaration): Famix.Alias {
|
|
326
|
+
const fmxAlias = entityDictionary.createFamixAlias(a);
|
|
327
|
+
|
|
328
|
+
logger.debug(`Alias: ${a.getName()}, (${a.getType().getText()}), fqn = ${fmxAlias.fullyQualifiedName}`);
|
|
329
|
+
|
|
330
|
+
processComments(a, fmxAlias);
|
|
331
|
+
|
|
332
|
+
return fmxAlias;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Builds a Famix model for a class
|
|
337
|
+
* @param c A class
|
|
338
|
+
* @returns A Famix.Class or a Famix.ParametricClass representing the class
|
|
339
|
+
*/
|
|
340
|
+
function processClass(c: ClassDeclaration): Famix.Class | Famix.ParametricClass {
|
|
341
|
+
classes.push(c);
|
|
342
|
+
|
|
343
|
+
const fmxClass = entityDictionary.createOrGetFamixClass(c);
|
|
344
|
+
|
|
345
|
+
logger.debug(`Class: ${c.getName()}, (${c.getType().getText()}), fqn = ${fmxClass.fullyQualifiedName}`);
|
|
346
|
+
|
|
347
|
+
processComments(c, fmxClass);
|
|
348
|
+
|
|
349
|
+
processDecorators(c, fmxClass);
|
|
350
|
+
|
|
351
|
+
processStructuredType(c, fmxClass);
|
|
352
|
+
|
|
353
|
+
c.getConstructors().forEach(con => {
|
|
354
|
+
const fmxCon = processMethod(con);
|
|
355
|
+
fmxClass.addMethod(fmxCon);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
c.getGetAccessors().forEach(acc => {
|
|
359
|
+
const fmxAcc = processMethod(acc);
|
|
360
|
+
fmxClass.addMethod(fmxAcc);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
c.getSetAccessors().forEach(acc => {
|
|
364
|
+
const fmxAcc = processMethod(acc);
|
|
365
|
+
fmxClass.addMethod(fmxAcc);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
return fmxClass;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Builds a Famix model for an interface
|
|
373
|
+
* @param i An interface
|
|
374
|
+
* @returns A Famix.Interface or a Famix.ParametricInterface representing the interface
|
|
375
|
+
*/
|
|
376
|
+
function processInterface(i: InterfaceDeclaration): Famix.Interface | Famix.ParametricInterface {
|
|
377
|
+
interfaces.push(i);
|
|
378
|
+
|
|
379
|
+
const fmxInterface = entityDictionary.createOrGetFamixInterface(i);
|
|
380
|
+
|
|
381
|
+
logger.debug(`Interface: ${i.getName()}, (${i.getType().getText()}), fqn = ${fmxInterface.fullyQualifiedName}`);
|
|
382
|
+
|
|
383
|
+
processComments(i, fmxInterface);
|
|
384
|
+
|
|
385
|
+
processStructuredType(i, fmxInterface);
|
|
386
|
+
|
|
387
|
+
return fmxInterface;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Builds a Famix model for the type parameters, properties and methods of a structured type
|
|
392
|
+
* @param c A structured type (a class or an interface)
|
|
393
|
+
* @param fmxScope The Famix model of the structured type
|
|
394
|
+
*/
|
|
395
|
+
function processStructuredType(c: ClassDeclaration | InterfaceDeclaration, fmxScope: Famix.Class | Famix.ParametricClass | Famix.Interface | Famix.ParametricInterface): void {
|
|
396
|
+
logger.debug(`Finding Properties and Methods:`);
|
|
397
|
+
if (fmxScope instanceof Famix.ParametricClass || fmxScope instanceof Famix.ParametricInterface) {
|
|
398
|
+
processTypeParameters(c, fmxScope);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
c.getProperties().forEach(prop => {
|
|
402
|
+
const fmxProperty = processProperty(prop);
|
|
403
|
+
fmxScope.addProperty(fmxProperty);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
c.getMethods().forEach(m => {
|
|
407
|
+
const fmxMethod = processMethod(m);
|
|
408
|
+
fmxScope.addMethod(fmxMethod);
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Builds a Famix model for a property
|
|
414
|
+
* @param p A property
|
|
415
|
+
* @returns A Famix.Property representing the property
|
|
416
|
+
*/
|
|
417
|
+
function processProperty(p: PropertyDeclaration | PropertySignature): Famix.Property {
|
|
418
|
+
const fmxProperty = entityDictionary.createFamixProperty(p);
|
|
419
|
+
|
|
420
|
+
logger.debug(`property: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxProperty.fullyQualifiedName}`);
|
|
421
|
+
logger.debug(` ---> It's a Property${(p instanceof PropertySignature) ? "Signature" : "Declaration"}!`);
|
|
422
|
+
const ancestor = p.getFirstAncestorOrThrow();
|
|
423
|
+
logger.debug(` ---> Its first ancestor is a ${ancestor.getKindName()}`);
|
|
424
|
+
|
|
425
|
+
// decorators
|
|
426
|
+
if (!(p instanceof PropertySignature)) {
|
|
427
|
+
processDecorators(p, fmxProperty);
|
|
428
|
+
// only add access if the p's first ancestor is not a PropertyDeclaration
|
|
429
|
+
if (ancestor.getKindName() !== "PropertyDeclaration") {
|
|
430
|
+
logger.debug(`adding access to map: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxProperty.name} id: ${fmxProperty.id}`);
|
|
431
|
+
accessMap.set(fmxProperty.id, p);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
processComments(p, fmxProperty);
|
|
436
|
+
|
|
437
|
+
return fmxProperty;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Builds a Famix model for a method or an accessor
|
|
442
|
+
* @param m A method or an accessor
|
|
443
|
+
* @returns A Famix.Method or a Famix.Accessor representing the method or the accessor
|
|
444
|
+
*/
|
|
445
|
+
function processMethod(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration): Famix.Method | Famix.Accessor {
|
|
446
|
+
const fmxMethod = entityDictionary.createOrGetFamixMethod(m, currentCC);
|
|
447
|
+
|
|
448
|
+
logger.debug(`Method: ${!(m instanceof ConstructorDeclaration) ? m.getName() : "constructor"}, (${m.getType().getText()}), parent: ${(m.getParent() as ClassDeclaration | InterfaceDeclaration).getName()}, fqn = ${fmxMethod.fullyQualifiedName}`);
|
|
449
|
+
|
|
450
|
+
processComments(m, fmxMethod);
|
|
451
|
+
|
|
452
|
+
processTypeParameters(m, fmxMethod);
|
|
453
|
+
|
|
454
|
+
processParameters(m, fmxMethod);
|
|
455
|
+
|
|
456
|
+
if (!(m instanceof MethodSignature)) {
|
|
457
|
+
processAliases(m, fmxMethod);
|
|
458
|
+
|
|
459
|
+
processVariables(m, fmxMethod);
|
|
460
|
+
|
|
461
|
+
processEnums(m, fmxMethod);
|
|
462
|
+
|
|
463
|
+
processFunctions(m, fmxMethod);
|
|
464
|
+
|
|
465
|
+
processFunctionExpressions(m, fmxMethod);
|
|
466
|
+
|
|
467
|
+
methodsAndFunctionsWithId.set(fmxMethod.id, m);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (m instanceof MethodDeclaration || m instanceof GetAccessorDeclaration || m instanceof SetAccessorDeclaration) {
|
|
471
|
+
processDecorators(m, fmxMethod);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return fmxMethod;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Builds a Famix model for a function
|
|
479
|
+
* @param f A function
|
|
480
|
+
* @returns A Famix.Function representing the function
|
|
481
|
+
*/
|
|
482
|
+
function processFunction(f: FunctionDeclaration | FunctionExpression | ArrowFunction): Famix.Function {
|
|
483
|
+
|
|
484
|
+
logger.debug(`Function: ${(f instanceof ArrowFunction ? "anonymous" : f.getName() ? f.getName() : "anonymous")}, (${f.getType().getText()}), fqn = ${getFQN(f)}`);
|
|
485
|
+
|
|
486
|
+
let fmxFunction;
|
|
487
|
+
if (f instanceof ArrowFunction) {
|
|
488
|
+
fmxFunction = entityDictionary.createOrGetFamixArrowFunction(f, currentCC);
|
|
489
|
+
} else {
|
|
490
|
+
fmxFunction = entityDictionary.createOrGetFamixFunction(f, currentCC);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
processComments(f, fmxFunction);
|
|
494
|
+
|
|
495
|
+
processAliases(f, fmxFunction);
|
|
496
|
+
|
|
497
|
+
processTypeParameters(f, fmxFunction);
|
|
498
|
+
|
|
499
|
+
processParameters(f, fmxFunction);
|
|
500
|
+
|
|
501
|
+
processVariables(f, fmxFunction);
|
|
502
|
+
|
|
503
|
+
processEnums(f, fmxFunction);
|
|
504
|
+
|
|
505
|
+
processFunctions(f, fmxFunction);
|
|
506
|
+
|
|
507
|
+
if (f instanceof FunctionDeclaration && !(f.getParent() instanceof Block)) {
|
|
508
|
+
processFunctionExpressions(f, fmxFunction);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
methodsAndFunctionsWithId.set(fmxFunction.id, f);
|
|
512
|
+
|
|
513
|
+
return fmxFunction;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Builds a Famix model for the function expressions of a function or a method
|
|
518
|
+
* @param f A function or a method
|
|
519
|
+
* @param fmxScope The Famix model of the function or the method
|
|
520
|
+
*/
|
|
521
|
+
function processFunctionExpressions(f: FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
522
|
+
logger.debug(`Finding Function Expressions:`);
|
|
523
|
+
const functionExpressions = f.getDescendantsOfKind(SyntaxKind.FunctionExpression);
|
|
524
|
+
functionExpressions.forEach((func) => {
|
|
525
|
+
const fmxFunc = processFunction(func);
|
|
526
|
+
fmxScope.addFunction(fmxFunc);
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Builds a Famix model for the parameters of a method or a function
|
|
532
|
+
* @param m A method or a function
|
|
533
|
+
* @param fmxScope The Famix model of the method or the function
|
|
534
|
+
*/
|
|
535
|
+
function processParameters(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction, fmxScope: Famix.Method | Famix.Accessor | Famix.Function): void {
|
|
536
|
+
logger.debug(`Finding Parameters:`);
|
|
537
|
+
m.getParameters().forEach(param => {
|
|
538
|
+
const fmxParam = processParameter(param);
|
|
539
|
+
fmxScope.addParameter(fmxParam);
|
|
540
|
+
// Additional handling for Parameter Properties in constructors
|
|
541
|
+
if (m instanceof ConstructorDeclaration) {
|
|
542
|
+
// Check if the parameter has any visibility modifier
|
|
543
|
+
if (param.hasModifier(SyntaxKind.PrivateKeyword) || param.hasModifier(SyntaxKind.PublicKeyword) || param.hasModifier(SyntaxKind.ProtectedKeyword) || param.hasModifier(SyntaxKind.ReadonlyKeyword)) {
|
|
544
|
+
const classOfConstructor = m.getParent();
|
|
545
|
+
logger.info(`Parameter Property ${param.getName()} in constructor of ${classOfConstructor.getName()}.`);
|
|
546
|
+
// Treat the parameter as a property and add it to the class
|
|
547
|
+
const fmxProperty = processParameterAsProperty(param, classOfConstructor);
|
|
548
|
+
fmxProperty.readOnly = param.hasModifier(SyntaxKind.ReadonlyKeyword);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// This function should create a Famix.Property model from a ParameterDeclaration
|
|
556
|
+
// You'll need to implement it according to your Famix model structure
|
|
557
|
+
function processParameterAsProperty(param: ParameterDeclaration, classDecl: ClassDeclaration | ClassExpression): Famix.Property {
|
|
558
|
+
// Convert the parameter into a Property
|
|
559
|
+
const propertyRepresentation = convertParameterToPropertyRepresentation(param);
|
|
560
|
+
|
|
561
|
+
// Add the property to the class so we can have a PropertyDeclaration object
|
|
562
|
+
classDecl.addProperty(propertyRepresentation);
|
|
563
|
+
|
|
564
|
+
const property = classDecl.getProperty(propertyRepresentation.name);
|
|
565
|
+
if (!property) {
|
|
566
|
+
throw new Error(`Property ${propertyRepresentation.name} not found in class ${classDecl.getName()}`);
|
|
567
|
+
}
|
|
568
|
+
const fmxProperty = entityDictionary.createFamixProperty(property);
|
|
569
|
+
if (classDecl instanceof ClassDeclaration) {
|
|
570
|
+
const fmxClass = entityDictionary.createOrGetFamixClass(classDecl);
|
|
571
|
+
fmxClass.addProperty(fmxProperty);
|
|
572
|
+
} else {
|
|
573
|
+
throw new Error("Unexpected type ClassExpression.");
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
processComments(property, fmxProperty);
|
|
577
|
+
|
|
578
|
+
// remove the property from the class
|
|
579
|
+
property.remove();
|
|
580
|
+
|
|
581
|
+
return fmxProperty;
|
|
582
|
+
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function convertParameterToPropertyRepresentation(param: ParameterDeclaration) {
|
|
586
|
+
// Extract name
|
|
587
|
+
const paramName = param.getName();
|
|
588
|
+
|
|
589
|
+
// Extract type
|
|
590
|
+
const paramType = param.getType().getText(param);
|
|
591
|
+
|
|
592
|
+
// Determine visibility
|
|
593
|
+
let scope: Scope;
|
|
594
|
+
if (param.hasModifier(SyntaxKind.PrivateKeyword)) {
|
|
595
|
+
scope = Scope.Private;
|
|
596
|
+
} else if (param.hasModifier(SyntaxKind.ProtectedKeyword)) {
|
|
597
|
+
scope = Scope.Protected;
|
|
598
|
+
} else if (param.hasModifier(SyntaxKind.PublicKeyword)) {
|
|
599
|
+
scope = Scope.Public;
|
|
600
|
+
} else {
|
|
601
|
+
throw new Error(`Parameter property ${paramName} in constructor does not have a visibility modifier.`);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Determine if readonly
|
|
605
|
+
const isReadonly = param.hasModifier(SyntaxKind.ReadonlyKeyword);
|
|
606
|
+
|
|
607
|
+
// Create a representation of the property
|
|
608
|
+
const propertyRepresentation = {
|
|
609
|
+
name: paramName,
|
|
610
|
+
type: paramType,
|
|
611
|
+
scope: scope,
|
|
612
|
+
isReadonly: isReadonly,
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
return propertyRepresentation;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Builds a Famix model for a parameter
|
|
620
|
+
* @param paramDecl A parameter
|
|
621
|
+
* @returns A Famix.Parameter representing the parameter
|
|
622
|
+
*/
|
|
623
|
+
function processParameter(paramDecl: ParameterDeclaration): Famix.Parameter {
|
|
624
|
+
const fmxParam = entityDictionary.createOrGetFamixParameter(paramDecl); // create or GET
|
|
625
|
+
|
|
626
|
+
logger.debug(`parameter: ${paramDecl.getName()}, (${paramDecl.getType().getText()}), fqn = ${fmxParam.fullyQualifiedName}`);
|
|
627
|
+
|
|
628
|
+
processComments(paramDecl, fmxParam);
|
|
629
|
+
|
|
630
|
+
processDecorators(paramDecl, fmxParam);
|
|
631
|
+
|
|
632
|
+
const parent = paramDecl.getParent();
|
|
633
|
+
|
|
634
|
+
if (!(parent instanceof MethodSignature)) {
|
|
635
|
+
logger.debug(`adding access: ${paramDecl.getName()}, (${paramDecl.getType().getText()}) Famix ${fmxParam.name}`);
|
|
636
|
+
accessMap.set(fmxParam.id, paramDecl);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return fmxParam;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function processTypeParameters(
|
|
643
|
+
e: ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction,
|
|
644
|
+
fmxScope: Famix.ParametricClass | Famix.ParametricInterface | Famix.Method | Famix.Accessor | Famix.Function | Famix.ArrowFunction
|
|
645
|
+
): void {
|
|
646
|
+
logger.debug(`Finding Type Parameters:`);
|
|
647
|
+
const nodeStart = e.getStart();
|
|
648
|
+
|
|
649
|
+
// Check if this node has already been processed
|
|
650
|
+
if (processedNodesWithTypeParams.has(nodeStart)) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Get type parameters
|
|
655
|
+
const typeParams = e.getTypeParameters();
|
|
656
|
+
|
|
657
|
+
// Process each type parameter
|
|
658
|
+
typeParams.forEach((tp) => {
|
|
659
|
+
const fmxParam = processTypeParameter(tp);
|
|
660
|
+
fmxScope.addGenericParameter(fmxParam);
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
// Log if no type parameters were found
|
|
664
|
+
if (typeParams.length === 0) {
|
|
665
|
+
logger.debug(`[processTypeParameters] No type parameters found for this node`);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Mark this node as processed
|
|
669
|
+
processedNodesWithTypeParams.add(nodeStart);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Builds a Famix model for a type parameter
|
|
674
|
+
* @param tp A type parameter
|
|
675
|
+
* @returns A Famix.TypeParameter representing the type parameter
|
|
676
|
+
*/
|
|
677
|
+
function processTypeParameter(tp: TypeParameterDeclaration): Famix.ParameterType {
|
|
678
|
+
const fmxTypeParameter = entityDictionary.createFamixParameterType(tp);
|
|
679
|
+
logger.debug(`type parameter: ${tp.getName()}, (${tp.getType().getText()}), fqn = ${fmxTypeParameter.fullyQualifiedName}`);
|
|
680
|
+
processComments(tp, fmxTypeParameter);
|
|
681
|
+
return fmxTypeParameter;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Builds a Famix model for the variables of a variable statement
|
|
686
|
+
* @param v A variable statement
|
|
687
|
+
* @returns An array of Famix.Variable representing the variables
|
|
688
|
+
*/
|
|
689
|
+
function processVariableStatement(v: VariableStatement): Array<Famix.Variable> {
|
|
690
|
+
const fmxVariables = new Array<Famix.Variable>();
|
|
691
|
+
|
|
692
|
+
logger.debug(`Variable statement: ${v.getText()}, (${v.getType().getText()}), ${v.getDeclarationKindKeywords()[0]}, fqn = ${v.getDeclarations()[0].getName()}`);
|
|
693
|
+
|
|
694
|
+
v.getDeclarations().forEach(variable => {
|
|
695
|
+
const fmxVar = processVariable(variable);
|
|
696
|
+
processComments(v, fmxVar);
|
|
697
|
+
fmxVariables.push(fmxVar);
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
return fmxVariables;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Builds a Famix model for a variable
|
|
705
|
+
* @param v A variable
|
|
706
|
+
* @returns A Famix.Variable representing the variable
|
|
707
|
+
*/
|
|
708
|
+
function processVariable(v: VariableDeclaration): Famix.Variable {
|
|
709
|
+
const fmxVar = entityDictionary.createOrGetFamixVariable(v);
|
|
710
|
+
|
|
711
|
+
logger.debug(`variable: ${v.getName()}, (${v.getType().getText()}), ${v.getInitializer() ? "initializer: " + v.getInitializer()!.getText() : "initializer: "}, fqn = ${fmxVar.fullyQualifiedName}`);
|
|
712
|
+
|
|
713
|
+
processComments(v, fmxVar);
|
|
714
|
+
|
|
715
|
+
logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxVar.name}`);
|
|
716
|
+
accessMap.set(fmxVar.id, v);
|
|
717
|
+
|
|
718
|
+
return fmxVar;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Builds a Famix model for an enum
|
|
723
|
+
* @param e An enum
|
|
724
|
+
* @returns A Famix.Enum representing the enum
|
|
725
|
+
*/
|
|
726
|
+
function processEnum(e: EnumDeclaration): Famix.Enum {
|
|
727
|
+
const fmxEnum = entityDictionary.createOrGetFamixEnum(e);
|
|
728
|
+
|
|
729
|
+
logger.debug(`enum: ${e.getName()}, (${e.getType().getText()}), fqn = ${fmxEnum.fullyQualifiedName}`);
|
|
730
|
+
|
|
731
|
+
processComments(e, fmxEnum);
|
|
732
|
+
|
|
733
|
+
e.getMembers().forEach(m => {
|
|
734
|
+
const fmxEnumValue = processEnumValue(m);
|
|
735
|
+
fmxEnum.addValue(fmxEnumValue);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
return fmxEnum;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Builds a Famix model for an enum member
|
|
743
|
+
* @param v An enum member
|
|
744
|
+
* @returns A Famix.EnumValue representing the enum member
|
|
745
|
+
*/
|
|
746
|
+
function processEnumValue(v: EnumMember): Famix.EnumValue {
|
|
747
|
+
const fmxEnumValue = entityDictionary.createFamixEnumValue(v);
|
|
748
|
+
|
|
749
|
+
logger.debug(`enum value: ${v.getName()}, (${v.getType().getText()}), fqn = ${fmxEnumValue.fullyQualifiedName}`);
|
|
750
|
+
|
|
751
|
+
processComments(v, fmxEnumValue);
|
|
752
|
+
|
|
753
|
+
logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxEnumValue.name}`);
|
|
754
|
+
accessMap.set(fmxEnumValue.id, v);
|
|
755
|
+
|
|
756
|
+
return fmxEnumValue;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Builds a Famix model for the decorators of a class, a method, a parameter or a property
|
|
761
|
+
* @param e A class, a method, a parameter or a property
|
|
762
|
+
* @param fmxScope The Famix model of the class, the method, the parameter or the property
|
|
763
|
+
*/
|
|
764
|
+
function processDecorators(e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration, fmxScope: Famix.Class | Famix.ParametricClass | Famix.Method | Famix.Accessor | Famix.Parameter | Famix.Property): void {
|
|
765
|
+
logger.debug(`Finding Decorators:`);
|
|
766
|
+
e.getDecorators().forEach(dec => {
|
|
767
|
+
const fmxDec = processDecorator(dec, e);
|
|
768
|
+
fmxScope.addDecorator(fmxDec);
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Builds a Famix model for a decorator
|
|
774
|
+
* @param d A decorator
|
|
775
|
+
* @param e A class, a method, a parameter or a property
|
|
776
|
+
* @returns A Famix.Decorator representing the decorator
|
|
777
|
+
*/
|
|
778
|
+
function processDecorator(d: Decorator, e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration): Famix.Decorator {
|
|
779
|
+
const fmxDec = entityDictionary.createOrGetFamixDecorator(d, e);
|
|
780
|
+
|
|
781
|
+
logger.debug(`decorator: ${d.getName()}, (${d.getType().getText()}), fqn = ${fmxDec.fullyQualifiedName}`);
|
|
782
|
+
|
|
783
|
+
processComments(d, fmxDec);
|
|
784
|
+
|
|
785
|
+
return fmxDec;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Builds a Famix model for the comments
|
|
790
|
+
* @param e A ts-morph element
|
|
791
|
+
* @param fmxScope The Famix model of the named entity
|
|
792
|
+
*/
|
|
793
|
+
function processComments(e: SourceFile | ModuleDeclaration | ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ParameterDeclaration | VariableDeclaration | PropertyDeclaration | PropertySignature | Decorator | EnumDeclaration | EnumMember | TypeParameterDeclaration | VariableStatement | TypeAliasDeclaration | ArrowFunction, fmxScope: Famix.NamedEntity): void {
|
|
794
|
+
logger.debug(`Process comments:`);
|
|
795
|
+
e.getLeadingCommentRanges().forEach(c => {
|
|
796
|
+
const fmxComment = processComment(c, fmxScope);
|
|
797
|
+
logger.debug(`leading comments, addComment: '${c.getText()}'`);
|
|
798
|
+
fmxScope.addComment(fmxComment); // redundant, but just in case
|
|
799
|
+
});
|
|
800
|
+
e.getTrailingCommentRanges().forEach(c => {
|
|
801
|
+
const fmxComment = processComment(c, fmxScope);
|
|
802
|
+
logger.debug(`trailing comments, addComment: '${c.getText()}'`);
|
|
803
|
+
fmxScope.addComment(fmxComment);
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Builds a Famix model for a comment
|
|
809
|
+
* @param c A comment
|
|
810
|
+
* @param fmxScope The Famix model of the comment's container
|
|
811
|
+
* @returns A Famix.Comment representing the comment
|
|
812
|
+
*/
|
|
813
|
+
function processComment(c: CommentRange, fmxScope: Famix.NamedEntity): Famix.Comment {
|
|
814
|
+
const isJSDoc = c.getText().startsWith("/**");
|
|
815
|
+
logger.debug(`processComment: comment: ${c.getText()}, isJSDoc = ${isJSDoc}`);
|
|
816
|
+
const fmxComment = entityDictionary.createFamixComment(c, fmxScope, isJSDoc);
|
|
817
|
+
|
|
818
|
+
return fmxComment;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Builds a Famix model for the accesses on the parameters, variables, properties and enum members of the source files
|
|
823
|
+
* @param accessMap A map of parameters, variables, properties and enum members with their id
|
|
824
|
+
*/
|
|
825
|
+
export function processAccesses(accessMap: Map<FamixID, AccessibleTSMorphElement>): void {
|
|
826
|
+
logger.debug(`Creating accesses:`);
|
|
827
|
+
accessMap.forEach((v, id) => {
|
|
828
|
+
logger.debug(`Accesses to ${v.getName()}`);
|
|
829
|
+
// try {
|
|
830
|
+
const temp_nodes = v.findReferencesAsNodes() as Array<Identifier>;
|
|
831
|
+
temp_nodes.forEach(node => processNodeForAccesses(node, id));
|
|
832
|
+
// } catch (error) {
|
|
833
|
+
// logger.error(`> WARNING: got exception "${error}".\nContinuing...`);
|
|
834
|
+
// }
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Builds a Famix model for an access on a parameter, variable, property or enum member
|
|
840
|
+
* @param n A node
|
|
841
|
+
* @param id An id of a parameter, a variable, a property or an enum member
|
|
842
|
+
*/
|
|
843
|
+
function processNodeForAccesses(n: Identifier, id: number): void {
|
|
844
|
+
// try {
|
|
845
|
+
// sometimes node's first ancestor is a PropertyDeclaration, which is not an access
|
|
846
|
+
// see https://github.com/fuhrmanator/FamixTypeScriptImporter/issues/9
|
|
847
|
+
// check for a node whose first ancestor is a property declaration and bail?
|
|
848
|
+
// This may be a bug in ts-morph?
|
|
849
|
+
if (n.getFirstAncestorOrThrow().getKindName() === "PropertyDeclaration") {
|
|
850
|
+
logger.debug(`processNodeForAccesses: node kind: ${n.getKindName()}, ${n.getText()}, (${n.getType().getText()})'s first ancestor is a PropertyDeclaration. Skipping...`);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
entityDictionary.createFamixAccess(n, id);
|
|
854
|
+
logger.debug(`processNodeForAccesses: node kind: ${n.getKindName()}, ${n.getText()}, (${n.getType().getText()})`);
|
|
855
|
+
// } catch (error) {
|
|
856
|
+
// logger.error(`> Got exception "${error}".\nScopeDeclaration invalid for "${n.getSymbol().fullyQualifiedName}".\nContinuing...`);
|
|
857
|
+
// }
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
// exports has name -> Declaration -- the declaration can be used to find the FamixElement
|
|
862
|
+
|
|
863
|
+
// handle `import path = require("path")` for example
|
|
864
|
+
export function processImportClausesForImportEqualsDeclarations(sourceFiles: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
|
|
865
|
+
logger.info(`Creating import clauses from ImportEqualsDeclarations in source files:`);
|
|
866
|
+
sourceFiles.forEach(sourceFile => {
|
|
867
|
+
sourceFile.forEachDescendant(node => {
|
|
868
|
+
if (Node.isImportEqualsDeclaration(node)) {
|
|
869
|
+
// You've found an ImportEqualsDeclaration
|
|
870
|
+
logger.info("Declaration Name:", node.getName());
|
|
871
|
+
logger.info("Module Reference Text:", node.getModuleReference().getText());
|
|
872
|
+
// what's the name of the imported entity?
|
|
873
|
+
// const importedEntity = node.getName();
|
|
874
|
+
// create a famix import clause
|
|
875
|
+
const namedImport = node.getNameNode();
|
|
876
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
877
|
+
importDeclaration: node,
|
|
878
|
+
importerSourceFile: sourceFile,
|
|
879
|
+
moduleSpecifierFilePath: node.getModuleReference().getText(),
|
|
880
|
+
importElement: namedImport,
|
|
881
|
+
isInExports: exports.find(e => e.has(namedImport.getText())) !== undefined,
|
|
882
|
+
isDefaultExport: false
|
|
883
|
+
});
|
|
884
|
+
// entityDictionary.createFamixImportClause(importedEntity, importingEntity);
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Builds a Famix model for the import clauses of the source files which are modules
|
|
893
|
+
* @param modules An array of modules
|
|
894
|
+
* @param exports An array of maps of exported declarations
|
|
895
|
+
*/
|
|
896
|
+
export function processImportClausesForModules(modules: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
|
|
897
|
+
logger.info(`Creating import clauses from ${modules.length} modules:`);
|
|
898
|
+
modules.forEach(module => {
|
|
899
|
+
const modulePath = module.getFilePath();
|
|
900
|
+
module.getImportDeclarations().forEach(impDecl => {
|
|
901
|
+
logger.info(`Importing ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
902
|
+
const path = getModulePath(impDecl);
|
|
903
|
+
|
|
904
|
+
impDecl.getNamedImports().forEach(namedImport => {
|
|
905
|
+
logger.info(`Importing (named) ${namedImport.getName()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
906
|
+
const importedEntityName = namedImport.getName();
|
|
907
|
+
const importFoundInExports = isInExports(exports, importedEntityName);
|
|
908
|
+
logger.debug(`Processing ImportSpecifier: ${namedImport.getText()}, pos=${namedImport.getStart()}`);
|
|
909
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
910
|
+
importDeclaration: impDecl,
|
|
911
|
+
importerSourceFile: module,
|
|
912
|
+
moduleSpecifierFilePath: path,
|
|
913
|
+
importElement: namedImport,
|
|
914
|
+
isInExports: importFoundInExports,
|
|
915
|
+
isDefaultExport: false
|
|
916
|
+
});
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
const defaultImport = impDecl.getDefaultImport();
|
|
920
|
+
if (defaultImport !== undefined) {
|
|
921
|
+
logger.info(`Importing (default) ${defaultImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
922
|
+
logger.debug(`Processing Default Import: ${defaultImport.getText()}, pos=${defaultImport.getStart()}`);
|
|
923
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
924
|
+
importDeclaration: impDecl,
|
|
925
|
+
importerSourceFile: module,
|
|
926
|
+
moduleSpecifierFilePath: path,
|
|
927
|
+
importElement: defaultImport,
|
|
928
|
+
isInExports: false,
|
|
929
|
+
isDefaultExport: true
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const namespaceImport = impDecl.getNamespaceImport();
|
|
934
|
+
if (namespaceImport !== undefined) {
|
|
935
|
+
logger.info(`Importing (namespace) ${namespaceImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
936
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
937
|
+
importDeclaration: impDecl,
|
|
938
|
+
importerSourceFile: module,
|
|
939
|
+
moduleSpecifierFilePath: path,
|
|
940
|
+
importElement: namespaceImport,
|
|
941
|
+
isInExports: false,
|
|
942
|
+
isDefaultExport: false
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function isInExports(exports: ReadonlyMap<string, ExportedDeclarations[]>[], importedEntityName: string) {
|
|
950
|
+
let importFoundInExports = false;
|
|
951
|
+
exports.forEach(e => {
|
|
952
|
+
if (e.has(importedEntityName)) {
|
|
953
|
+
importFoundInExports = true;
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
return importFoundInExports;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/**
|
|
960
|
+
* Builds a Famix model for the inheritances of the classes and interfaces of the source files
|
|
961
|
+
* @param classes An array of classes
|
|
962
|
+
* @param interfaces An array of interfaces
|
|
963
|
+
*/
|
|
964
|
+
export function processInheritances(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[]): void {
|
|
965
|
+
logger.info(`Creating inheritances:`);
|
|
966
|
+
classes.forEach(cls => {
|
|
967
|
+
logger.debug(`Checking class inheritance for ${cls.getName()}`);
|
|
968
|
+
const baseClass = cls.getBaseClass();
|
|
969
|
+
if (baseClass !== undefined) {
|
|
970
|
+
entityDictionary.createOrGetFamixInheritance(cls, baseClass);
|
|
971
|
+
logger.debug(`class: ${cls.getName()}, (${cls.getType().getText()}), extClass: ${baseClass.getName()}, (${baseClass.getType().getText()})`);
|
|
972
|
+
} // this is false when the class extends an undefined class
|
|
973
|
+
else {
|
|
974
|
+
// check for "extends" of unresolved class
|
|
975
|
+
const undefinedExtendedClass = cls.getExtends();
|
|
976
|
+
if (undefinedExtendedClass) {
|
|
977
|
+
entityDictionary.createOrGetFamixInheritance(cls, undefinedExtendedClass);
|
|
978
|
+
logger.debug(`class: ${cls.getName()}, (${cls.getType().getText()}), undefinedExtendedClass: ${undefinedExtendedClass.getText()}`);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
logger.debug(`Checking interface inheritance for ${cls.getName()}`);
|
|
983
|
+
const implementedInterfaces = getImplementedOrExtendedInterfaces(interfaces, cls);
|
|
984
|
+
implementedInterfaces.forEach(implementedIF => {
|
|
985
|
+
entityDictionary.createOrGetFamixInheritance(cls, implementedIF);
|
|
986
|
+
logger.debug(`class: ${cls.getName()}, (${cls.getType().getText()}), impInter: ${(implementedIF instanceof InterfaceDeclaration) ? implementedIF.getName() : implementedIF.getExpression().getText()}, (${(implementedIF instanceof InterfaceDeclaration) ? implementedIF.getType().getText() : implementedIF.getExpression().getText()})`);
|
|
987
|
+
});
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
interfaces.forEach(interFace => {
|
|
991
|
+
try {
|
|
992
|
+
logger.debug(`Checking interface inheritance for ${interFace.getName()}`);
|
|
993
|
+
const extendedInterfaces = getImplementedOrExtendedInterfaces(interfaces, interFace);
|
|
994
|
+
extendedInterfaces.forEach(extendedInterface => {
|
|
995
|
+
entityDictionary.createOrGetFamixInheritance(interFace, extendedInterface);
|
|
996
|
+
|
|
997
|
+
logger.debug(`interFace: ${interFace.getName()}, (${interFace.getType().getText()}), extendedInterface: ${(extendedInterface instanceof InterfaceDeclaration) ? extendedInterface.getName() : extendedInterface.getExpression().getText()}, (${(extendedInterface instanceof InterfaceDeclaration) ? extendedInterface.getType().getText() : extendedInterface.getExpression().getText()})`);
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
catch (error) {
|
|
1001
|
+
logger.error(`> WARNING: got exception ${error}. Continuing...`);
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Builds a Famix model for the invocations of the methods and functions of the source files
|
|
1008
|
+
* @param methodsAndFunctionsWithId A map of methods and functions with their id
|
|
1009
|
+
*/
|
|
1010
|
+
export function processInvocations(methodsAndFunctionsWithId: Map<number, InvocableType>): void {
|
|
1011
|
+
logger.info(`Creating invocations:`);
|
|
1012
|
+
methodsAndFunctionsWithId.forEach((invocable, id) => {
|
|
1013
|
+
if (!(invocable instanceof ArrowFunction)) { // ArrowFunctions are not directly invoked
|
|
1014
|
+
logger.debug(`Invocations to ${(invocable instanceof MethodDeclaration || invocable instanceof GetAccessorDeclaration || invocable instanceof SetAccessorDeclaration || invocable instanceof FunctionDeclaration) ? invocable.getName() : ((invocable instanceof ConstructorDeclaration) ? 'constructor' : (invocable.getName() ? invocable.getName() : 'anonymous'))} (${invocable.getType().getText()})`);
|
|
1015
|
+
try {
|
|
1016
|
+
const nodesReferencingInvocable = invocable.findReferencesAsNodes() as Array<Identifier>;
|
|
1017
|
+
nodesReferencingInvocable.forEach(
|
|
1018
|
+
nodeReferencingInvocable => processNodeForInvocations(nodeReferencingInvocable, invocable, id));
|
|
1019
|
+
} catch (error) {
|
|
1020
|
+
logger.error(`> WARNING: got exception ${error}. Continuing...`);
|
|
1021
|
+
}
|
|
1022
|
+
} else {
|
|
1023
|
+
logger.debug(`Skipping invocation to ArrowFunction: ${(invocable.getBodyText())}`);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Builds a Famix model for an invocation of a method or a function
|
|
1030
|
+
* @param nodeReferencingInvocable A node
|
|
1031
|
+
* @param invocable A method or a function
|
|
1032
|
+
* @param id The id of the method or the function
|
|
1033
|
+
*/
|
|
1034
|
+
function processNodeForInvocations(nodeReferencingInvocable: Identifier, invocable: InvocableType, id: number): void {
|
|
1035
|
+
try {
|
|
1036
|
+
entityDictionary.createFamixInvocation(nodeReferencingInvocable, invocable, id);
|
|
1037
|
+
logger.debug(`node: ${nodeReferencingInvocable.getKindName()}, (${nodeReferencingInvocable.getType().getText()})`);
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${nodeReferencingInvocable.getSymbol()!.getFullyQualifiedName()}. Continuing...`);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* Builds a Famix model for the inheritances of the classes and interfaces of the source files
|
|
1045
|
+
* @param classes An array of classes
|
|
1046
|
+
* @param interfaces An array of interfaces
|
|
1047
|
+
*/
|
|
1048
|
+
export function processConcretisations(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[], functions: Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction>): void {
|
|
1049
|
+
logger.info(`processConcretisations: Creating concretisations:`);
|
|
1050
|
+
classes.forEach(cls => {
|
|
1051
|
+
logger.debug(`processConcretisations: Checking class concretisation for ${cls.getName()}`);
|
|
1052
|
+
entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(cls);
|
|
1053
|
+
entityDictionary.createFamixConcretisationGenericInstantiation(cls);
|
|
1054
|
+
entityDictionary.createFamixConcretisationInterfaceClass(cls);
|
|
1055
|
+
entityDictionary.createFamixConcretisationTypeInstanciation(cls);
|
|
1056
|
+
|
|
1057
|
+
});
|
|
1058
|
+
interfaces.forEach(inter => {
|
|
1059
|
+
logger.debug(`processConcretisations: Checking interface concretisation for ${inter.getName()}`);
|
|
1060
|
+
entityDictionary.createFamixConcretisationTypeInstanciation(inter);
|
|
1061
|
+
entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(inter);
|
|
1062
|
+
});
|
|
1063
|
+
functions.forEach(func => {
|
|
1064
|
+
if(func instanceof FunctionDeclaration || func instanceof MethodDeclaration ){
|
|
1065
|
+
logger.debug(`processConcretisations: Checking Method concretisation`);
|
|
1066
|
+
entityDictionary.createFamixConcretisationFunctionInstantiation(func);
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
}
|