ts2famix 1.3.1 → 1.4.1
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/dist/analyze.js +38 -27
- package/dist/analyze_functions/process_functions.js +723 -0
- package/dist/famix_functions/EntityDictionary.js +798 -0
- package/dist/famix_functions/helpers_creation.js +97 -0
- package/dist/fqn.js +106 -95
- package/dist/lib/famix/src/famix_base_element.js +8 -4
- package/dist/lib/famix/src/famix_repository.js +32 -15
- package/dist/lib/ts-complex/cyclomatic-service.js +2 -3
- package/doc-uml/metamodel-full.svg +1 -0
- package/doc-uml/metamodel.svg +1 -0
- package/package.json +1 -1
- package/plantuml.jar +0 -0
- package/src/analyze.ts +48 -29
- package/src/analyze_functions/process_functions.ts +838 -0
- package/src/famix_functions/EntityDictionary.ts +915 -0
- package/src/famix_functions/helpers_creation.ts +77 -0
- package/src/fqn.ts +101 -92
- package/src/lib/famix/src/famix_base_element.ts +9 -5
- package/src/lib/famix/src/famix_repository.ts +45 -23
- package/src/lib/ts-complex/cyclomatic-service.ts +2 -4
- package/src/ts2famix-cli.ts +1 -0
- package/dist/analyze_functions/processAccesses.js +0 -56
- package/dist/analyze_functions/processFiles.js +0 -554
- package/dist/analyze_functions/processImportClauses.js +0 -88
- package/dist/analyze_functions/processInheritances.js +0 -74
- package/dist/analyze_functions/processInvocations.js +0 -50
- package/dist/famix_functions/famix_functions.js +0 -523
- package/dist/famix_functions/famix_functions_associations.js +0 -238
- package/dist/famix_functions/famix_functions_index.js +0 -135
- package/dist/famix_functions/famix_functions_types.js +0 -115
- package/docs/.gitkeep +0 -0
- package/src/analyze_functions/processAccesses.ts +0 -58
- package/src/analyze_functions/processFiles.ts +0 -667
- package/src/analyze_functions/processImportClauses.ts +0 -95
- package/src/analyze_functions/processInheritances.ts +0 -85
- package/src/analyze_functions/processInvocations.ts +0 -52
- package/src/famix_functions/famix_functions.ts +0 -562
- package/src/famix_functions/famix_functions_associations.ts +0 -242
- package/src/famix_functions/famix_functions_index.ts +0 -120
- package/src/famix_functions/famix_functions_types.ts +0 -106
|
@@ -0,0 +1,838 @@
|
|
|
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 } from "ts-morph";
|
|
2
|
+
import * as Famix from "../lib/famix/src/model/famix";
|
|
3
|
+
import { calculate } from "../lib/ts-complex/cyclomatic-service";
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import { logger , entityDictionary } from "../analyze";
|
|
6
|
+
|
|
7
|
+
export const methodsAndFunctionsWithId = new Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression>(); // Maps the Famix method, constructor, getter, setter and function ids to their ts-morph method, constructor, getter, setter or function object
|
|
8
|
+
export const accessMap = new Map<number, ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember>(); // Maps the Famix parameter, variable, property and enum value ids to their ts-morph parameter, variable, property or enum member object
|
|
9
|
+
export const classes = new Array<ClassDeclaration>(); // Array of all the classes of the source files
|
|
10
|
+
export const interfaces = new Array<InterfaceDeclaration>(); // Array of all the interfaces of the source files
|
|
11
|
+
export const modules = new Array<SourceFile>(); // Array of all the source files which are modules
|
|
12
|
+
export const exportedMap = new Array<ReadonlyMap<string, ExportedDeclarations[]>>(); // Array of all the exports
|
|
13
|
+
export let currentCC: unknown; // Stores the cyclomatic complexity metrics for the current source file
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Checks if the file has any imports or exports to be considered a module
|
|
17
|
+
* @param sourceFile A source file
|
|
18
|
+
* @returns A boolean indicating if the file is a module
|
|
19
|
+
*/
|
|
20
|
+
function ismodule(sourceFile: SourceFile): boolean {
|
|
21
|
+
return sourceFile.getImportDeclarations().length > 0 || sourceFile.getExportedDeclarations().size > 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Gets the path of a module to be imported
|
|
26
|
+
* @param i An import declaration
|
|
27
|
+
* @returns The path of the module to be imported
|
|
28
|
+
*/
|
|
29
|
+
export function getModulePath(i: ImportDeclaration): string {
|
|
30
|
+
let path: string;
|
|
31
|
+
if (i.getModuleSpecifierSourceFile() === undefined) {
|
|
32
|
+
if (i.getModuleSpecifierValue().substring(i.getModuleSpecifierValue().length - 3) === ".ts") {
|
|
33
|
+
path = i.getModuleSpecifierValue();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
path = i.getModuleSpecifierValue() + ".ts";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
path = i.getModuleSpecifierSourceFile().getFilePath();
|
|
41
|
+
}
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Gets the interfaces implemented or extended by a class or an interface
|
|
47
|
+
* @param interfaces An array of interfaces
|
|
48
|
+
* @param subClass A class or an interface
|
|
49
|
+
* @returns An array of InterfaceDeclaration and ExpressionWithTypeArguments containing the interfaces implemented or extended by the subClass
|
|
50
|
+
*/
|
|
51
|
+
export function getImplementedOrExtendedInterfaces(interfaces: Array<InterfaceDeclaration>, subClass: ClassDeclaration | InterfaceDeclaration): Array<InterfaceDeclaration | ExpressionWithTypeArguments> {
|
|
52
|
+
let impOrExtInterfaces: Array<ExpressionWithTypeArguments>;
|
|
53
|
+
if (subClass instanceof ClassDeclaration) {
|
|
54
|
+
impOrExtInterfaces = subClass.getImplements();
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
impOrExtInterfaces = subClass.getExtends();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const interfacesNames = interfaces.map(i => i.getName());
|
|
61
|
+
const implementedOrExtendedInterfaces = new Array<InterfaceDeclaration | ExpressionWithTypeArguments>();
|
|
62
|
+
|
|
63
|
+
impOrExtInterfaces.forEach(i => {
|
|
64
|
+
if (interfacesNames.includes(i.getExpression().getText())) {
|
|
65
|
+
implementedOrExtendedInterfaces.push(interfaces[interfacesNames.indexOf(i.getExpression().getText())]);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
implementedOrExtendedInterfaces.push(i);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return implementedOrExtendedInterfaces;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Builds a Famix model for an array of source files
|
|
77
|
+
* @param sourceFiles An array of source files
|
|
78
|
+
*/
|
|
79
|
+
export function processFiles(sourceFiles: Array<SourceFile>): void {
|
|
80
|
+
sourceFiles.forEach(file => {
|
|
81
|
+
logger.info(`File: >>>>>>>>>> ${file.getFilePath()}`);
|
|
82
|
+
|
|
83
|
+
// Computes the cyclomatic complexity metrics for the current source file if it exists (i.e. if it is not from a jest test)
|
|
84
|
+
if (fs.existsSync(file.getFilePath()))
|
|
85
|
+
currentCC = calculate(file.getFilePath());
|
|
86
|
+
else
|
|
87
|
+
currentCC = 0;
|
|
88
|
+
|
|
89
|
+
processFile(file);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Builds a Famix model for a source file
|
|
95
|
+
* @param f A source file
|
|
96
|
+
*/
|
|
97
|
+
function processFile(f: SourceFile): void {
|
|
98
|
+
const isModule = ismodule(f);
|
|
99
|
+
|
|
100
|
+
if (isModule) {
|
|
101
|
+
modules.push(f);
|
|
102
|
+
exportedMap.push(f.getExportedDeclarations());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const fmxFile = entityDictionary.createOrGetFamixFile(f, isModule);
|
|
106
|
+
|
|
107
|
+
logger.debug(`processFile: file: ${f.getBaseName()}, fqn = ${fmxFile.getFullyQualifiedName()}`);
|
|
108
|
+
|
|
109
|
+
processComments(f, fmxFile);
|
|
110
|
+
|
|
111
|
+
processAliases(f, fmxFile);
|
|
112
|
+
|
|
113
|
+
processClasses(f, fmxFile);
|
|
114
|
+
|
|
115
|
+
processInterfaces(f, fmxFile);
|
|
116
|
+
|
|
117
|
+
processVariables(f, fmxFile);
|
|
118
|
+
|
|
119
|
+
processEnums(f, fmxFile);
|
|
120
|
+
|
|
121
|
+
processFunctions(f, fmxFile);
|
|
122
|
+
|
|
123
|
+
processNamespaces(f, fmxFile);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Builds a Famix model for a namespace
|
|
128
|
+
* @param m A namespace
|
|
129
|
+
* @returns A Famix.Namespace representing the namespace
|
|
130
|
+
*/
|
|
131
|
+
function processNamespace(m: ModuleDeclaration): Famix.Namespace {
|
|
132
|
+
const fmxNamespace = entityDictionary.createOrGetFamixNamespace(m);
|
|
133
|
+
|
|
134
|
+
logger.debug(`processNamespace: namespace: ${m.getName()}, (${m.getType().getText()}), ${fmxNamespace.getFullyQualifiedName()}`);
|
|
135
|
+
|
|
136
|
+
processComments(m, fmxNamespace);
|
|
137
|
+
|
|
138
|
+
processAliases(m, fmxNamespace);
|
|
139
|
+
|
|
140
|
+
processClasses(m, fmxNamespace);
|
|
141
|
+
|
|
142
|
+
processInterfaces(m, fmxNamespace);
|
|
143
|
+
|
|
144
|
+
processVariables(m, fmxNamespace);
|
|
145
|
+
|
|
146
|
+
processEnums(m, fmxNamespace);
|
|
147
|
+
|
|
148
|
+
processFunctions(m, fmxNamespace);
|
|
149
|
+
|
|
150
|
+
processNamespaces(m, fmxNamespace);
|
|
151
|
+
|
|
152
|
+
return fmxNamespace;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Builds a Famix model for the aliases of a container
|
|
157
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
158
|
+
* @param fmxScope The Famix model of the container
|
|
159
|
+
*/
|
|
160
|
+
function processAliases(m: SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace | Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
161
|
+
logger.debug(`processAliases: ---------- Finding Aliases:`);
|
|
162
|
+
m.getTypeAliases().forEach(a => {
|
|
163
|
+
const fmxAlias = processAlias(a);
|
|
164
|
+
fmxScope.addAlias(fmxAlias);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Builds a Famix model for the classes of a container
|
|
170
|
+
* @param m A container (a source file or a namespace)
|
|
171
|
+
* @param fmxScope The Famix model of the container
|
|
172
|
+
*/
|
|
173
|
+
function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
|
|
174
|
+
logger.debug(`processClasses: ---------- Finding Classes:`);
|
|
175
|
+
m.getClasses().forEach(c => {
|
|
176
|
+
const fmxClass = processClass(c);
|
|
177
|
+
fmxScope.addType(fmxClass);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Builds a Famix model for the interfaces of a container
|
|
183
|
+
* @param m A container (a source file or a namespace)
|
|
184
|
+
* @param fmxScope The Famix model of the container
|
|
185
|
+
*/
|
|
186
|
+
function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
|
|
187
|
+
logger.debug(`processInterfaces: ---------- Finding Interfaces:`);
|
|
188
|
+
m.getInterfaces().forEach(i => {
|
|
189
|
+
const fmxInterface = processInterface(i);
|
|
190
|
+
fmxScope.addType(fmxInterface);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Builds a Famix model for the variables of a container
|
|
196
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
197
|
+
* @param fmxScope The Famix model of the container
|
|
198
|
+
*/
|
|
199
|
+
function processVariables(m: SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace | Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
200
|
+
logger.debug(`processVariables: ---------- Finding Variables:`);
|
|
201
|
+
m.getVariableStatements().forEach(v => {
|
|
202
|
+
const fmxVariables = processVariableStatement(v);
|
|
203
|
+
fmxVariables.forEach(fmxVariable => {
|
|
204
|
+
fmxScope.addVariable(fmxVariable);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Builds a Famix model for the enums of a container
|
|
211
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
212
|
+
* @param fmxScope The Famix model of the container
|
|
213
|
+
*/
|
|
214
|
+
function processEnums(m: SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace | Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
215
|
+
logger.debug(`processEnums: ---------- Finding Enums:`);
|
|
216
|
+
m.getEnums().forEach(e => {
|
|
217
|
+
const fmxEnum = processEnum(e);
|
|
218
|
+
fmxScope.addType(fmxEnum);
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Builds a Famix model for the functions of a container
|
|
224
|
+
* @param m A container (a source file, a namespace, a function or a method)
|
|
225
|
+
* @param fmxScope The Famix model of the container
|
|
226
|
+
*/
|
|
227
|
+
function processFunctions(m: SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace | Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
228
|
+
logger.debug(`Finding Functions:`);
|
|
229
|
+
m.getFunctions().forEach(f => {
|
|
230
|
+
const fmxFunction = processFunction(f);
|
|
231
|
+
fmxScope.addFunction(fmxFunction);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Builds a Famix model for the namespaces of a container
|
|
237
|
+
* @param m A container (a source file or a namespace)
|
|
238
|
+
* @param fmxScope The Famix model of the container
|
|
239
|
+
*/
|
|
240
|
+
function processNamespaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
|
|
241
|
+
logger.debug(`Finding Namespaces:`);
|
|
242
|
+
m.getModules().forEach(md => {
|
|
243
|
+
const fmxNsp = processNamespace(md);
|
|
244
|
+
fmxScope.addNamespace(fmxNsp);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Builds a Famix model for an alias
|
|
250
|
+
* @param a An alias
|
|
251
|
+
* @returns A Famix.Alias representing the alias
|
|
252
|
+
*/
|
|
253
|
+
function processAlias(a: TypeAliasDeclaration): Famix.Alias {
|
|
254
|
+
const fmxAlias = entityDictionary.createFamixAlias(a);
|
|
255
|
+
|
|
256
|
+
logger.debug(`Alias: ${a.getName()}, (${a.getType().getText()}), fqn = ${fmxAlias.getFullyQualifiedName()}`);
|
|
257
|
+
|
|
258
|
+
processComments(a, fmxAlias);
|
|
259
|
+
|
|
260
|
+
return fmxAlias;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Builds a Famix model for a class
|
|
265
|
+
* @param c A class
|
|
266
|
+
* @returns A Famix.Class or a Famix.ParameterizableClass representing the class
|
|
267
|
+
*/
|
|
268
|
+
function processClass(c: ClassDeclaration): Famix.Class | Famix.ParameterizableClass {
|
|
269
|
+
classes.push(c);
|
|
270
|
+
|
|
271
|
+
const fmxClass = entityDictionary.createOrGetFamixClass(c);
|
|
272
|
+
|
|
273
|
+
logger.debug(`Class: ${c.getName()}, (${c.getType().getText()}), fqn = ${fmxClass.getFullyQualifiedName()}`);
|
|
274
|
+
|
|
275
|
+
processComments(c, fmxClass);
|
|
276
|
+
|
|
277
|
+
processDecorators(c, fmxClass);
|
|
278
|
+
|
|
279
|
+
processStructuredType(c, fmxClass);
|
|
280
|
+
|
|
281
|
+
c.getConstructors().forEach(con => {
|
|
282
|
+
const fmxCon = processMethod(con);
|
|
283
|
+
fmxClass.addMethod(fmxCon);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
c.getGetAccessors().forEach(acc => {
|
|
287
|
+
const fmxAcc = processMethod(acc);
|
|
288
|
+
fmxClass.addMethod(fmxAcc);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
c.getSetAccessors().forEach(acc => {
|
|
292
|
+
const fmxAcc = processMethod(acc);
|
|
293
|
+
fmxClass.addMethod(fmxAcc);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
return fmxClass;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Builds a Famix model for an interface
|
|
301
|
+
* @param i An interface
|
|
302
|
+
* @returns A Famix.Interface or a Famix.ParameterizableInterface representing the interface
|
|
303
|
+
*/
|
|
304
|
+
function processInterface(i: InterfaceDeclaration): Famix.Interface | Famix.ParameterizableInterface {
|
|
305
|
+
interfaces.push(i);
|
|
306
|
+
|
|
307
|
+
const fmxInterface = entityDictionary.createOrGetFamixInterface(i);
|
|
308
|
+
|
|
309
|
+
logger.debug(`Interface: ${i.getName()}, (${i.getType().getText()}), fqn = ${fmxInterface.getFullyQualifiedName()}`);
|
|
310
|
+
|
|
311
|
+
processComments(i, fmxInterface);
|
|
312
|
+
|
|
313
|
+
processStructuredType(i, fmxInterface);
|
|
314
|
+
|
|
315
|
+
return fmxInterface;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Builds a Famix model for the type parameters, properties and methods of a structured type
|
|
320
|
+
* @param c A structured type (a class or an interface)
|
|
321
|
+
* @param fmxScope The Famix model of the structured type
|
|
322
|
+
*/
|
|
323
|
+
function processStructuredType(c: ClassDeclaration | InterfaceDeclaration, fmxScope: Famix.Class | Famix.ParameterizableClass | Famix.Interface | Famix.ParameterizableInterface): void {
|
|
324
|
+
logger.debug(`Finding Properties and Methods:`);
|
|
325
|
+
if (fmxScope instanceof Famix.ParameterizableClass || fmxScope instanceof Famix.ParameterizableInterface) {
|
|
326
|
+
processTypeParameters(c, fmxScope);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
c.getProperties().forEach(prop => {
|
|
330
|
+
const fmxProperty = processProperty(prop);
|
|
331
|
+
fmxScope.addProperty(fmxProperty);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
c.getMethods().forEach(m => {
|
|
335
|
+
const fmxMethod = processMethod(m);
|
|
336
|
+
fmxScope.addMethod(fmxMethod);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Builds a Famix model for a property
|
|
342
|
+
* @param p A property
|
|
343
|
+
* @returns A Famix.Property representing the property
|
|
344
|
+
*/
|
|
345
|
+
function processProperty(p: PropertyDeclaration | PropertySignature): Famix.Property {
|
|
346
|
+
const fmxProperty = entityDictionary.createFamixProperty(p);
|
|
347
|
+
|
|
348
|
+
logger.debug(`property: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxProperty.getFullyQualifiedName()}`);
|
|
349
|
+
logger.debug(` ---> It's a Property${(p instanceof PropertySignature) ? "Signature" : "Declaration"}!`);
|
|
350
|
+
const ancestor = p.getFirstAncestorOrThrow();
|
|
351
|
+
logger.debug(` ---> Its first ancestor is a ${ancestor.getKindName()}`);
|
|
352
|
+
|
|
353
|
+
if (!(p instanceof PropertySignature)) {
|
|
354
|
+
processDecorators(p, fmxProperty);
|
|
355
|
+
// only add access if the p's first ancestor is not a PropertyDeclaration
|
|
356
|
+
if (ancestor.getKindName() !== "PropertyDeclaration") {
|
|
357
|
+
logger.debug(`adding access: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxProperty.getName()}`);
|
|
358
|
+
accessMap.set(fmxProperty.id, p);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
processComments(p, fmxProperty);
|
|
363
|
+
|
|
364
|
+
return fmxProperty;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Builds a Famix model for a method or an accessor
|
|
369
|
+
* @param m A method or an accessor
|
|
370
|
+
* @returns A Famix.Method or a Famix.Accessor representing the method or the accessor
|
|
371
|
+
*/
|
|
372
|
+
function processMethod(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration): Famix.Method | Famix.Accessor {
|
|
373
|
+
const fmxMethod = entityDictionary.createFamixMethod(m, currentCC);
|
|
374
|
+
|
|
375
|
+
logger.debug(`Method: ${!(m instanceof ConstructorDeclaration) ? m.getName() : "constructor"}, (${m.getType().getText()}), parent: ${(m.getParent() as ClassDeclaration | InterfaceDeclaration).getName()}, fqn = ${fmxMethod.getFullyQualifiedName()}`);
|
|
376
|
+
|
|
377
|
+
processComments(m, fmxMethod);
|
|
378
|
+
|
|
379
|
+
processTypeParameters(m, fmxMethod);
|
|
380
|
+
|
|
381
|
+
processParameters(m, fmxMethod);
|
|
382
|
+
|
|
383
|
+
if (!(m instanceof MethodSignature)) {
|
|
384
|
+
processAliases(m, fmxMethod);
|
|
385
|
+
|
|
386
|
+
processVariables(m, fmxMethod);
|
|
387
|
+
|
|
388
|
+
processEnums(m, fmxMethod);
|
|
389
|
+
|
|
390
|
+
processFunctions(m, fmxMethod);
|
|
391
|
+
|
|
392
|
+
processFunctionExpressions(m, fmxMethod);
|
|
393
|
+
|
|
394
|
+
methodsAndFunctionsWithId.set(fmxMethod.id, m);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (m instanceof MethodDeclaration || m instanceof GetAccessorDeclaration || m instanceof SetAccessorDeclaration) {
|
|
398
|
+
processDecorators(m, fmxMethod);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return fmxMethod;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Builds a Famix model for a function
|
|
406
|
+
* @param f A function
|
|
407
|
+
* @returns A Famix.Function representing the function
|
|
408
|
+
*/
|
|
409
|
+
function processFunction(f: FunctionDeclaration | FunctionExpression): Famix.Function {
|
|
410
|
+
const fmxFunction = entityDictionary.createFamixFunction(f, currentCC);
|
|
411
|
+
|
|
412
|
+
logger.debug(`Function: ${(f.getName()) ? f.getName() : "anonymous"}, (${f.getType().getText()}), fqn = ${fmxFunction.getFullyQualifiedName()}`);
|
|
413
|
+
|
|
414
|
+
processComments(f, fmxFunction);
|
|
415
|
+
|
|
416
|
+
processAliases(f, fmxFunction);
|
|
417
|
+
|
|
418
|
+
processTypeParameters(f, fmxFunction);
|
|
419
|
+
|
|
420
|
+
processParameters(f, fmxFunction);
|
|
421
|
+
|
|
422
|
+
processVariables(f, fmxFunction);
|
|
423
|
+
|
|
424
|
+
processEnums(f, fmxFunction);
|
|
425
|
+
|
|
426
|
+
processFunctions(f, fmxFunction);
|
|
427
|
+
|
|
428
|
+
if (f instanceof FunctionDeclaration && !(f.getParent() instanceof Block)) {
|
|
429
|
+
processFunctionExpressions(f, fmxFunction);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
methodsAndFunctionsWithId.set(fmxFunction.id, f);
|
|
433
|
+
|
|
434
|
+
return fmxFunction;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Builds a Famix model for the function expressions of a function or a method
|
|
439
|
+
* @param f A function or a method
|
|
440
|
+
* @param fmxScope The Famix model of the function or the method
|
|
441
|
+
*/
|
|
442
|
+
function processFunctionExpressions(f: FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration, fmxScope: Famix.Function | Famix.Method | Famix.Accessor): void {
|
|
443
|
+
logger.debug(`Finding Function Expressions:`);
|
|
444
|
+
const functionExpressions = f.getDescendantsOfKind(SyntaxKind.FunctionExpression);
|
|
445
|
+
functionExpressions.forEach((func) => {
|
|
446
|
+
const fmxFunc = processFunction(func);
|
|
447
|
+
fmxScope.addFunction(fmxFunc);
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Builds a Famix model for the parameters of a method or a function
|
|
453
|
+
* @param m A method or a function
|
|
454
|
+
* @param fmxScope The Famix model of the method or the function
|
|
455
|
+
*/
|
|
456
|
+
function processParameters(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression, fmxScope: Famix.Method | Famix.Accessor | Famix.Function): void {
|
|
457
|
+
logger.debug(`Finding Parameters:`);
|
|
458
|
+
m.getParameters().forEach(param => {
|
|
459
|
+
const fmxParam = processParameter(param);
|
|
460
|
+
fmxScope.addParameter(fmxParam);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Builds a Famix model for a parameter
|
|
466
|
+
* @param p A parameter
|
|
467
|
+
* @returns A Famix.Parameter representing the parameter
|
|
468
|
+
*/
|
|
469
|
+
function processParameter(p: ParameterDeclaration): Famix.Parameter {
|
|
470
|
+
const fmxParam = entityDictionary.createFamixParameter(p);
|
|
471
|
+
|
|
472
|
+
logger.debug(`parameter: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxParam.getFullyQualifiedName()}`);
|
|
473
|
+
|
|
474
|
+
processComments(p, fmxParam);
|
|
475
|
+
|
|
476
|
+
processDecorators(p, fmxParam);
|
|
477
|
+
|
|
478
|
+
const parent = p.getParent();
|
|
479
|
+
|
|
480
|
+
if (!(parent instanceof MethodSignature)) {
|
|
481
|
+
logger.debug(`adding access: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxParam.getName()}`);
|
|
482
|
+
accessMap.set(fmxParam.id, p);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return fmxParam;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Builds a Famix model for the type parameters of a class, an interface, a method or a function
|
|
490
|
+
* @param e A class, an interface, a method or a function
|
|
491
|
+
* @param fmxScope The Famix model of the class, the interface, the method or the function
|
|
492
|
+
*/
|
|
493
|
+
function processTypeParameters(e: ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression, fmxScope: Famix.ParameterizableClass | Famix.ParameterizableInterface | Famix.Method | Famix.Accessor | Famix.Function): void {
|
|
494
|
+
logger.debug(`Finding Type Parameters:`);
|
|
495
|
+
e.getTypeParameters().forEach(tp => {
|
|
496
|
+
const fmxParam = processTypeParameter(tp);
|
|
497
|
+
fmxScope.addParameterType(fmxParam);
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Builds a Famix model for a type parameter
|
|
503
|
+
* @param tp A type parameter
|
|
504
|
+
* @returns A Famix.TypeParameter representing the type parameter
|
|
505
|
+
*/
|
|
506
|
+
function processTypeParameter(tp: TypeParameterDeclaration): Famix.ParameterType {
|
|
507
|
+
const fmxTypeParameter = entityDictionary.createFamixParameterType(tp);
|
|
508
|
+
|
|
509
|
+
logger.debug(`type parameter: ${tp.getName()}, (${tp.getType().getText()}), fqn = ${fmxTypeParameter.getFullyQualifiedName()}`);
|
|
510
|
+
|
|
511
|
+
processComments(tp, fmxTypeParameter);
|
|
512
|
+
|
|
513
|
+
return fmxTypeParameter;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Builds a Famix model for the variables of a variable statement
|
|
518
|
+
* @param v A variable statement
|
|
519
|
+
* @returns An array of Famix.Variable representing the variables
|
|
520
|
+
*/
|
|
521
|
+
function processVariableStatement(v: VariableStatement): Array<Famix.Variable> {
|
|
522
|
+
const fmxVariables = new Array<Famix.Variable>();
|
|
523
|
+
|
|
524
|
+
logger.debug(`Variable statement: ${v.getText()}, (${v.getType().getText()}), ${v.getDeclarationKindKeywords()[0]}, fqn = ${v.getDeclarations()[0].getName()}`);
|
|
525
|
+
|
|
526
|
+
v.getDeclarations().forEach(variable => {
|
|
527
|
+
const fmxVar = processVariable(variable);
|
|
528
|
+
processComments(v, fmxVar);
|
|
529
|
+
fmxVariables.push(fmxVar);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
return fmxVariables;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Builds a Famix model for a variable
|
|
537
|
+
* @param v A variable
|
|
538
|
+
* @returns A Famix.Variable representing the variable
|
|
539
|
+
*/
|
|
540
|
+
function processVariable(v: VariableDeclaration): Famix.Variable {
|
|
541
|
+
const fmxVar = entityDictionary.createFamixVariable(v);
|
|
542
|
+
|
|
543
|
+
logger.debug(`variable: ${v.getName()}, (${v.getType().getText()}), ${v.getInitializer() ? "initializer: " + v.getInitializer().getText() : "initializer: "}, fqn = ${fmxVar.getFullyQualifiedName()}`);
|
|
544
|
+
|
|
545
|
+
processComments(v, fmxVar);
|
|
546
|
+
|
|
547
|
+
logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxVar.getName()}`);
|
|
548
|
+
accessMap.set(fmxVar.id, v);
|
|
549
|
+
|
|
550
|
+
return fmxVar;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Builds a Famix model for an enum
|
|
555
|
+
* @param e An enum
|
|
556
|
+
* @returns A Famix.Enum representing the enum
|
|
557
|
+
*/
|
|
558
|
+
function processEnum(e: EnumDeclaration): Famix.Enum {
|
|
559
|
+
const fmxEnum = entityDictionary.createFamixEnum(e);
|
|
560
|
+
|
|
561
|
+
logger.debug(`enum: ${e.getName()}, (${e.getType().getText()}), fqn = ${fmxEnum.getFullyQualifiedName()}`);
|
|
562
|
+
|
|
563
|
+
processComments(e, fmxEnum);
|
|
564
|
+
|
|
565
|
+
e.getMembers().forEach(m => {
|
|
566
|
+
const fmxEnumValue = processEnumValue(m);
|
|
567
|
+
fmxEnum.addValue(fmxEnumValue);
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
return fmxEnum;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Builds a Famix model for an enum member
|
|
575
|
+
* @param v An enum member
|
|
576
|
+
* @returns A Famix.EnumValue representing the enum member
|
|
577
|
+
*/
|
|
578
|
+
function processEnumValue(v: EnumMember): Famix.EnumValue {
|
|
579
|
+
const fmxEnumValue = entityDictionary.createFamixEnumValue(v);
|
|
580
|
+
|
|
581
|
+
logger.debug(`enum value: ${v.getName()}, (${v.getType().getText()}), fqn = ${fmxEnumValue.getFullyQualifiedName()}`);
|
|
582
|
+
|
|
583
|
+
processComments(v, fmxEnumValue);
|
|
584
|
+
|
|
585
|
+
logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxEnumValue.getName()}`);
|
|
586
|
+
accessMap.set(fmxEnumValue.id, v);
|
|
587
|
+
|
|
588
|
+
return fmxEnumValue;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Builds a Famix model for the decorators of a class, a method, a parameter or a property
|
|
593
|
+
* @param e A class, a method, a parameter or a property
|
|
594
|
+
* @param fmxScope The Famix model of the class, the method, the parameter or the property
|
|
595
|
+
*/
|
|
596
|
+
function processDecorators(e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration, fmxScope: Famix.Class | Famix.ParameterizableClass | Famix.Method | Famix.Accessor | Famix.Parameter | Famix.Property): void {
|
|
597
|
+
logger.debug(`Finding Decorators:`);
|
|
598
|
+
e.getDecorators().forEach(dec => {
|
|
599
|
+
const fmxDec = processDecorator(dec, e);
|
|
600
|
+
fmxScope.addDecorator(fmxDec);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Builds a Famix model for a decorator
|
|
606
|
+
* @param d A decorator
|
|
607
|
+
* @param e A class, a method, a parameter or a property
|
|
608
|
+
* @returns A Famix.Decorator representing the decorator
|
|
609
|
+
*/
|
|
610
|
+
function processDecorator(d: Decorator, e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration): Famix.Decorator {
|
|
611
|
+
const fmxDec = entityDictionary.createOrGetFamixDecorator(d, e);
|
|
612
|
+
|
|
613
|
+
logger.debug(`decorator: ${d.getName()}, (${d.getType().getText()}), fqn = ${fmxDec.getFullyQualifiedName()}`);
|
|
614
|
+
|
|
615
|
+
processComments(d, fmxDec);
|
|
616
|
+
|
|
617
|
+
return fmxDec;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Builds a Famix model for the comments
|
|
622
|
+
* @param e A ts-morph element
|
|
623
|
+
* @param fmxScope The Famix model of the named entity
|
|
624
|
+
*/
|
|
625
|
+
function processComments(e: SourceFile | ModuleDeclaration | ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ParameterDeclaration | VariableDeclaration | PropertyDeclaration | PropertySignature | Decorator | EnumDeclaration | EnumMember | TypeParameterDeclaration | VariableStatement | TypeAliasDeclaration, fmxScope: Famix.NamedEntity): void {
|
|
626
|
+
logger.debug(`Process comments:`);
|
|
627
|
+
e.getLeadingCommentRanges().forEach(c => {
|
|
628
|
+
const fmxComment = processComment(c, fmxScope);
|
|
629
|
+
logger.debug(`leading comments, addComment: '${c.getText()}'`);
|
|
630
|
+
fmxScope.addComment(fmxComment); // redundant, but just in case
|
|
631
|
+
});
|
|
632
|
+
e.getTrailingCommentRanges().forEach(c => {
|
|
633
|
+
const fmxComment = processComment(c, fmxScope);
|
|
634
|
+
logger.debug(`trailing comments, addComment: '${c.getText()}'`);
|
|
635
|
+
fmxScope.addComment(fmxComment);
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Builds a Famix model for a comment
|
|
641
|
+
* @param c A comment
|
|
642
|
+
* @param fmxScope The Famix model of the comment's container
|
|
643
|
+
* @returns A Famix.Comment representing the comment
|
|
644
|
+
*/
|
|
645
|
+
function processComment(c: CommentRange, fmxScope: Famix.NamedEntity): Famix.Comment {
|
|
646
|
+
const isJSDoc = c.getText().startsWith("/**");
|
|
647
|
+
logger.debug(`processComment: comment: ${c.getText()}, isJSDoc = ${isJSDoc}`);
|
|
648
|
+
const fmxComment = entityDictionary.createFamixComment(c, fmxScope, isJSDoc);
|
|
649
|
+
|
|
650
|
+
return fmxComment;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Builds a Famix model for the accesses on the parameters, variables, properties and enum members of the source files
|
|
655
|
+
* @param accessMap A map of parameters, variables, properties and enum members with their id
|
|
656
|
+
*/
|
|
657
|
+
export function processAccesses(accessMap: Map<number, ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember>): void {
|
|
658
|
+
logger.debug(`processAccesses: Creating accesses:`);
|
|
659
|
+
accessMap.forEach((v, id) => {
|
|
660
|
+
logger.debug(`processAccesses: Accesses to ${v.getName()}`);
|
|
661
|
+
try {
|
|
662
|
+
const temp_nodes = v.findReferencesAsNodes() as Array<Identifier>;
|
|
663
|
+
temp_nodes.forEach(node => processNodeForAccesses(node, id));
|
|
664
|
+
} catch (error) {
|
|
665
|
+
logger.error(`> WARNING: got exception ${error}. Continuing...`);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Builds a Famix model for an access on a parameter, variable, property or enum member
|
|
672
|
+
* @param n A node
|
|
673
|
+
* @param id An id of a parameter, a variable, a property or an enum member
|
|
674
|
+
*/
|
|
675
|
+
function processNodeForAccesses(n: Identifier, id: number): void {
|
|
676
|
+
try {
|
|
677
|
+
// sometimes node's first ancestor is a PropertyDeclaration, which is not an access
|
|
678
|
+
// see https://github.com/fuhrmanator/FamixTypeScriptImporter/issues/9
|
|
679
|
+
// check for a node whose first ancestor is a property declaration and bail?
|
|
680
|
+
// This may be a bug in ts-morph?
|
|
681
|
+
if (n.getFirstAncestorOrThrow().getKindName() === "PropertyDeclaration") {
|
|
682
|
+
logger.debug(`processNodeForAccesses: node kind: ${n.getKindName()}, ${n.getText()}, (${n.getType().getText()})'s first ancestor is a PropertyDeclaration. Skipping...`);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
entityDictionary.createFamixAccess(n, id);
|
|
686
|
+
logger.debug(`processNodeForAccesses: node kind: ${n.getKindName()}, ${n.getText()}, (${n.getType().getText()})`);
|
|
687
|
+
} catch (error) {
|
|
688
|
+
logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${n.getSymbol().getFullyQualifiedName()}. Continuing...`);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
export function processImportClausesForImportEqualsDeclarations(sourceFiles: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
|
|
693
|
+
logger.info(`Creating import clauses from ImportEqualsDeclarations in source files:`);
|
|
694
|
+
sourceFiles.forEach(sourceFile => {
|
|
695
|
+
sourceFile.forEachDescendant(node => {
|
|
696
|
+
if (Node.isImportEqualsDeclaration(node)) {
|
|
697
|
+
// You've found an ImportEqualsDeclaration
|
|
698
|
+
logger.info("Declaration Name:", node.getName());
|
|
699
|
+
logger.info("Module Reference Text:", node.getModuleReference().getText());
|
|
700
|
+
// create a famix import clause
|
|
701
|
+
const namedImport = node.getNameNode();
|
|
702
|
+
entityDictionary.createFamixImportClause({importDeclaration: node,
|
|
703
|
+
importer: sourceFile,
|
|
704
|
+
moduleSpecifierFilePath: node.getModuleReference().getText(),
|
|
705
|
+
importElement: namedImport,
|
|
706
|
+
isInExports: exports.find(e => e.has(namedImport.getText())) !== undefined,
|
|
707
|
+
isDefaultExport: false});
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
);
|
|
712
|
+
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Builds a Famix model for the import clauses of the source files which are modules
|
|
717
|
+
* @param modules An array of modules
|
|
718
|
+
* @param exports An array of maps of exported declarations
|
|
719
|
+
*/
|
|
720
|
+
export function processImportClausesForModules(modules: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
|
|
721
|
+
logger.info(`Creating import clauses from ${modules.length} modules:`);
|
|
722
|
+
modules.forEach(module => {
|
|
723
|
+
module.getImportDeclarations().forEach(impDecl => {
|
|
724
|
+
logger.debug(`Importing ${impDecl.getModuleSpecifierValue()}`);
|
|
725
|
+
const path = getModulePath(impDecl);
|
|
726
|
+
|
|
727
|
+
impDecl.getNamedImports().forEach(namedImport => {
|
|
728
|
+
logger.debug(`Importing (named) ${namedImport.getName()} from ${impDecl.getModuleSpecifierValue()}`);
|
|
729
|
+
const importedEntityName = namedImport.getName();
|
|
730
|
+
let importFoundInExports = false;
|
|
731
|
+
exports.forEach(e => {
|
|
732
|
+
if (e.has(importedEntityName)) {
|
|
733
|
+
importFoundInExports = true;
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
entityDictionary.createFamixImportClause({importDeclaration: impDecl,
|
|
737
|
+
importer: module,
|
|
738
|
+
moduleSpecifierFilePath: path,
|
|
739
|
+
importElement: namedImport,
|
|
740
|
+
isInExports: importFoundInExports,
|
|
741
|
+
isDefaultExport: false});
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
const defaultImport = impDecl.getDefaultImport();
|
|
745
|
+
if (defaultImport !== undefined) {
|
|
746
|
+
logger.debug(`Importing (default) ${defaultImport.getText()} from ${impDecl.getModuleSpecifierValue()}`);
|
|
747
|
+
// call with module, impDecl.getModuleSpecifierValue(), path, defaultImport, false, true
|
|
748
|
+
entityDictionary.createFamixImportClause({importDeclaration: impDecl,
|
|
749
|
+
importer: module,
|
|
750
|
+
moduleSpecifierFilePath: path,
|
|
751
|
+
importElement: defaultImport,
|
|
752
|
+
isInExports: false,
|
|
753
|
+
isDefaultExport: true});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const namespaceImport = impDecl.getNamespaceImport();
|
|
757
|
+
if (namespaceImport !== undefined) {
|
|
758
|
+
logger.debug(`Importing (namespace) ${namespaceImport.getText()} from ${impDecl.getModuleSpecifierValue()}`);
|
|
759
|
+
entityDictionary.createFamixImportClause({importDeclaration: impDecl,
|
|
760
|
+
importer: module,
|
|
761
|
+
moduleSpecifierFilePath: path,
|
|
762
|
+
importElement: namespaceImport,
|
|
763
|
+
isInExports: false,
|
|
764
|
+
isDefaultExport: false});
|
|
765
|
+
// entityDictionary.createFamixImportClause(module, impDecl.getModuleSpecifierValue(), path, namespaceImport, false, false);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Builds a Famix model for the inheritances of the classes and interfaces of the source files
|
|
773
|
+
* @param classes An array of classes
|
|
774
|
+
* @param interfaces An array of interfaces
|
|
775
|
+
*/
|
|
776
|
+
export function processInheritances(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[]): void {
|
|
777
|
+
logger.info(`processInheritances: Creating inheritances:`);
|
|
778
|
+
classes.forEach(cls => {
|
|
779
|
+
logger.debug(`processInheritances: Checking class inheritance for ${cls.getName()}`);
|
|
780
|
+
const extClass = cls.getBaseClass();
|
|
781
|
+
if (extClass !== undefined) {
|
|
782
|
+
entityDictionary.createFamixInheritance(cls, extClass);
|
|
783
|
+
|
|
784
|
+
logger.debug(`processInheritances: class: ${cls.getName()}, (${cls.getType().getText()}), extClass: ${extClass.getName()}, (${extClass.getType().getText()})`);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
logger.debug(`processInheritances: Checking interface inheritance for ${cls.getName()}`);
|
|
788
|
+
const implementedInterfaces = getImplementedOrExtendedInterfaces(interfaces, cls);
|
|
789
|
+
implementedInterfaces.forEach(impInter => {
|
|
790
|
+
entityDictionary.createFamixInheritance(cls, impInter);
|
|
791
|
+
|
|
792
|
+
logger.debug(`processInheritances: class: ${cls.getName()}, (${cls.getType().getText()}), impInter: ${(impInter instanceof InterfaceDeclaration) ? impInter.getName() : impInter.getExpression().getText()}, (${(impInter instanceof InterfaceDeclaration) ? impInter.getType().getText() : impInter.getExpression().getText()})`);
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
interfaces.forEach(inter => {
|
|
797
|
+
logger.debug(`processInheritances: Checking interface inheritance for ${inter.getName()}`);
|
|
798
|
+
const extendedInterfaces = getImplementedOrExtendedInterfaces(interfaces, inter);
|
|
799
|
+
extendedInterfaces.forEach(extInter => {
|
|
800
|
+
entityDictionary.createFamixInheritance(inter, extInter);
|
|
801
|
+
|
|
802
|
+
logger.debug(`processInheritances: inter: ${inter.getName()}, (${inter.getType().getText()}), extInter: ${(extInter instanceof InterfaceDeclaration) ? extInter.getName() : extInter.getExpression().getText()}, (${(extInter instanceof InterfaceDeclaration) ? extInter.getType().getText() : extInter.getExpression().getText()})`);
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Builds a Famix model for the invocations of the methods and functions of the source files
|
|
809
|
+
* @param methodsAndFunctionsWithId A map of methods and functions with their id
|
|
810
|
+
*/
|
|
811
|
+
export function processInvocations(methodsAndFunctionsWithId: Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression>): void {
|
|
812
|
+
logger.info(`Creating invocations:`);
|
|
813
|
+
methodsAndFunctionsWithId.forEach((m, id) => {
|
|
814
|
+
logger.debug(`Invocations to ${(m instanceof MethodDeclaration || m instanceof GetAccessorDeclaration || m instanceof SetAccessorDeclaration || m instanceof FunctionDeclaration) ? m.getName() : ((m instanceof ConstructorDeclaration) ? 'constructor' : (m.getName() ? m.getName() : 'anonymous'))}`);
|
|
815
|
+
try {
|
|
816
|
+
const temp_nodes = m.findReferencesAsNodes() as Array<Identifier>;
|
|
817
|
+
temp_nodes.forEach(node => processNodeForInvocations(node, m, id));
|
|
818
|
+
} catch (error) {
|
|
819
|
+
logger.error(`> WARNING: got exception ${error}. Continuing...`);
|
|
820
|
+
}
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
/**
|
|
825
|
+
* Builds a Famix model for an invocation of a method or a function
|
|
826
|
+
* @param n A node
|
|
827
|
+
* @param m A method or a function
|
|
828
|
+
* @param id The id of the method or the function
|
|
829
|
+
*/
|
|
830
|
+
function processNodeForInvocations(n: Identifier, m: MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression, id: number): void {
|
|
831
|
+
try {
|
|
832
|
+
entityDictionary.createFamixInvocation(n, m, id);
|
|
833
|
+
|
|
834
|
+
logger.debug(`node: node, (${n.getType().getText()})`);
|
|
835
|
+
} catch (error) {
|
|
836
|
+
logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${n.getSymbol().getFullyQualifiedName()}. Continuing...`);
|
|
837
|
+
}
|
|
838
|
+
}
|