ts2famix 2.0.3 → 2.0.4
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 +19 -9
- package/dist/analyze_functions/process_functions.js +127 -67
- package/dist/famix_functions/EntityDictionary.js +803 -356
- package/dist/famix_functions/helpers_creation.js +35 -19
- package/dist/fqn.js +384 -18
- package/dist/lib/famix/famix_repository.js +76 -2
- package/dist/lib/famix/index.js +18 -8
- package/dist/refactorer/refactor-getter-setter.js +18 -8
- package/dist/ts2famix-cli-wrapper.js +18 -8
- package/dist/ts2famix-cli.js +18 -8
- package/dist/ts2famix-tsconfig.js +18 -8
- package/doc-uml/famix-typescript-model.puml +29 -17
- package/doc-uml/famix-typescript-model.svg +1 -1
- package/eslint.config.mjs +28 -0
- package/jest.config.json +1 -1
- package/package.json +14 -10
- package/src/analyze.ts +1 -1
- package/src/analyze_functions/process_functions.ts +168 -118
- package/src/famix_functions/EntityDictionary.ts +909 -441
- package/src/famix_functions/helpers_creation.ts +23 -15
- package/src/fqn.ts +450 -50
- package/src/lib/famix/famix_repository.ts +46 -1
- package/tsconfig.json +1 -0
package/src/analyze.ts
CHANGED
|
@@ -6,7 +6,7 @@ import * as processFunctions from "./analyze_functions/process_functions";
|
|
|
6
6
|
import { EntityDictionary } from "./famix_functions/EntityDictionary";
|
|
7
7
|
import path from "path";
|
|
8
8
|
|
|
9
|
-
export const logger = new Logger({ name: "ts2famix", minLevel:
|
|
9
|
+
export const logger = new Logger({ name: "ts2famix", minLevel: 2 });
|
|
10
10
|
export const config = { "expectGraphemes": false };
|
|
11
11
|
export const entityDictionary = new EntityDictionary();
|
|
12
12
|
|
|
@@ -2,13 +2,14 @@ import { ClassDeclaration, MethodDeclaration, VariableStatement, FunctionDeclara
|
|
|
2
2
|
import * as Famix from "../lib/famix/model/famix";
|
|
3
3
|
import { calculate } from "../lib/ts-complex/cyclomatic-service";
|
|
4
4
|
import * as fs from 'fs';
|
|
5
|
-
import { logger
|
|
5
|
+
import { logger, entityDictionary } from "../analyze";
|
|
6
6
|
import { getFQN } from "../fqn";
|
|
7
|
+
import { InvocableType } from "src/famix_functions/EntityDictionary";
|
|
7
8
|
|
|
8
9
|
export type AccessibleTSMorphElement = ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember;
|
|
9
10
|
export type FamixID = number;
|
|
10
11
|
|
|
11
|
-
export const methodsAndFunctionsWithId = new Map<number,
|
|
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
|
|
12
13
|
|
|
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
|
|
14
15
|
export const classes = new Array<ClassDeclaration>(); // Array of all the classes of the source files
|
|
@@ -16,6 +17,7 @@ export const interfaces = new Array<InterfaceDeclaration>(); // Array of all the
|
|
|
16
17
|
export const modules = new Array<SourceFile>(); // Array of all the source files which are modules
|
|
17
18
|
export const listOfExportMaps = new Array<ReadonlyMap<string, ExportedDeclarations[]>>(); // Array of all the export maps
|
|
18
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
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Checks if the file has any imports or exports to be considered a module
|
|
@@ -47,6 +49,7 @@ export function getModulePath(importDecl: ImportDeclaration): string {
|
|
|
47
49
|
return path;
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
|
|
50
53
|
/**
|
|
51
54
|
* Gets the interfaces implemented or extended by a class or an interface
|
|
52
55
|
* @param interfaces An array of interfaces
|
|
@@ -77,19 +80,15 @@ export function getImplementedOrExtendedInterfaces(interfaces: Array<InterfaceDe
|
|
|
77
80
|
return implementedOrExtendedInterfaces;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
/**
|
|
81
|
-
* Builds a Famix model for an array of source files
|
|
82
|
-
* @param sourceFiles An array of source files
|
|
83
|
-
*/
|
|
84
83
|
export function processFiles(sourceFiles: Array<SourceFile>): void {
|
|
85
84
|
sourceFiles.forEach(file => {
|
|
86
85
|
logger.info(`File: >>>>>>>>>> ${file.getFilePath()}`);
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
if (fs.existsSync(file.getFilePath()))
|
|
87
|
+
if (fs.existsSync(file.getFilePath())) {
|
|
90
88
|
currentCC = calculate(file.getFilePath());
|
|
91
|
-
else
|
|
89
|
+
} else {
|
|
92
90
|
currentCC = {};
|
|
91
|
+
}
|
|
93
92
|
|
|
94
93
|
processFile(file);
|
|
95
94
|
});
|
|
@@ -114,22 +113,18 @@ function processFile(f: SourceFile): void {
|
|
|
114
113
|
logger.debug(`processFile: file: ${f.getBaseName()}, fqn = ${fmxFile.fullyQualifiedName}`);
|
|
115
114
|
|
|
116
115
|
processComments(f, fmxFile);
|
|
117
|
-
|
|
118
116
|
processAliases(f, fmxFile);
|
|
119
|
-
|
|
120
117
|
processClasses(f, fmxFile);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
processVariables(f, fmxFile);
|
|
125
|
-
|
|
118
|
+
processInterfaces(f, fmxFile);
|
|
119
|
+
processModules(f, fmxFile);
|
|
120
|
+
processVariables(f, fmxFile); // This will handle our object literal methods
|
|
126
121
|
processEnums(f, fmxFile);
|
|
127
|
-
|
|
128
122
|
processFunctions(f, fmxFile);
|
|
123
|
+
|
|
129
124
|
|
|
130
|
-
processModules(f, fmxFile);
|
|
131
125
|
}
|
|
132
126
|
|
|
127
|
+
|
|
133
128
|
export function isAmbient(node: ModuleDeclaration): boolean {
|
|
134
129
|
// An ambient module has the DeclareKeyword modifier.
|
|
135
130
|
return (node.getModifiers()?.some(modifier => modifier.getKind() === SyntaxKind.DeclareKeyword)) ?? false;
|
|
@@ -162,7 +157,7 @@ function processModule(m: ModuleDeclaration): Famix.Module {
|
|
|
162
157
|
processVariables(m, fmxModule);
|
|
163
158
|
|
|
164
159
|
processEnums(m, fmxModule);
|
|
165
|
-
|
|
160
|
+
|
|
166
161
|
processFunctions(m, fmxModule);
|
|
167
162
|
|
|
168
163
|
processModules(m, fmxModule);
|
|
@@ -192,7 +187,7 @@ function processAliases(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
|
192
187
|
* @param m A container (a source file or a namespace)
|
|
193
188
|
* @param fmxScope The Famix model of the container
|
|
194
189
|
*/
|
|
195
|
-
function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module
|
|
190
|
+
function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
196
191
|
logger.debug(`processClasses: ---------- Finding Classes:`);
|
|
197
192
|
const classesInArrowFunctions = getClassesDeclaredInArrowFunctions(m);
|
|
198
193
|
const classes = m.getClasses().concat(classesInArrowFunctions);
|
|
@@ -205,7 +200,7 @@ function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.Scrip
|
|
|
205
200
|
function getArrowFunctionClasses(f: ArrowFunction): ClassDeclaration[] {
|
|
206
201
|
const classes: ClassDeclaration[] = [];
|
|
207
202
|
|
|
208
|
-
function findClasses(node:
|
|
203
|
+
function findClasses(node: Node) {
|
|
209
204
|
if (node.getKind() === SyntaxKind.ClassDeclaration) {
|
|
210
205
|
classes.push(node as ClassDeclaration);
|
|
211
206
|
}
|
|
@@ -232,7 +227,7 @@ function getClassesDeclaredInArrowFunctions(s: SourceFile | ModuleDeclaration):
|
|
|
232
227
|
* @param m A container (a source file or a namespace)
|
|
233
228
|
* @param fmxScope The Famix model of the container
|
|
234
229
|
*/
|
|
235
|
-
function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module
|
|
230
|
+
function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
236
231
|
logger.debug(`processInterfaces: ---------- Finding Interfaces:`);
|
|
237
232
|
m.getInterfaces().forEach(i => {
|
|
238
233
|
const fmxInterface = processInterface(i);
|
|
@@ -252,6 +247,26 @@ function processVariables(m: ContainerTypes, fmxScope: Famix.ScriptEntity | Fami
|
|
|
252
247
|
fmxVariables.forEach(fmxVariable => {
|
|
253
248
|
fmxScope.addVariable(fmxVariable);
|
|
254
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
|
+
});
|
|
255
270
|
});
|
|
256
271
|
}
|
|
257
272
|
|
|
@@ -286,7 +301,7 @@ function processFunctions(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
|
286
301
|
arrowFunctions.forEach(af => {
|
|
287
302
|
const fmxFunction = processFunction(af);
|
|
288
303
|
fmxScope.addFunction(fmxFunction);
|
|
289
|
-
})
|
|
304
|
+
});
|
|
290
305
|
}
|
|
291
306
|
|
|
292
307
|
/**
|
|
@@ -294,7 +309,7 @@ function processFunctions(m: ContainerTypes, fmxScope: ScopedTypes): void {
|
|
|
294
309
|
* @param m A container (a source file or a namespace)
|
|
295
310
|
* @param fmxScope The Famix model of the container
|
|
296
311
|
*/
|
|
297
|
-
function processModules(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module
|
|
312
|
+
function processModules(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module): void {
|
|
298
313
|
logger.debug(`Finding Modules:`);
|
|
299
314
|
m.getModules().forEach(md => {
|
|
300
315
|
const fmxModule = processModule(md);
|
|
@@ -344,7 +359,7 @@ function processClass(c: ClassDeclaration): Famix.Class | Famix.ParametricClass
|
|
|
344
359
|
const fmxAcc = processMethod(acc);
|
|
345
360
|
fmxClass.addMethod(fmxAcc);
|
|
346
361
|
});
|
|
347
|
-
|
|
362
|
+
|
|
348
363
|
c.getSetAccessors().forEach(acc => {
|
|
349
364
|
const fmxAcc = processMethod(acc);
|
|
350
365
|
fmxClass.addMethod(fmxAcc);
|
|
@@ -469,8 +484,8 @@ function processFunction(f: FunctionDeclaration | FunctionExpression | ArrowFunc
|
|
|
469
484
|
logger.debug(`Function: ${(f instanceof ArrowFunction ? "anonymous" : f.getName() ? f.getName() : "anonymous")}, (${f.getType().getText()}), fqn = ${getFQN(f)}`);
|
|
470
485
|
|
|
471
486
|
let fmxFunction;
|
|
472
|
-
if(
|
|
473
|
-
fmxFunction = entityDictionary.
|
|
487
|
+
if (f instanceof ArrowFunction) {
|
|
488
|
+
fmxFunction = entityDictionary.createOrGetFamixArrowFunction(f, currentCC);
|
|
474
489
|
} else {
|
|
475
490
|
fmxFunction = entityDictionary.createOrGetFamixFunction(f, currentCC);
|
|
476
491
|
}
|
|
@@ -554,7 +569,7 @@ function processParameterAsProperty(param: ParameterDeclaration, classDecl: Clas
|
|
|
554
569
|
if (classDecl instanceof ClassDeclaration) {
|
|
555
570
|
const fmxClass = entityDictionary.createOrGetFamixClass(classDecl);
|
|
556
571
|
fmxClass.addProperty(fmxProperty);
|
|
557
|
-
} else {
|
|
572
|
+
} else {
|
|
558
573
|
throw new Error("Unexpected type ClassExpression.");
|
|
559
574
|
}
|
|
560
575
|
|
|
@@ -606,7 +621,7 @@ function convertParameterToPropertyRepresentation(param: ParameterDeclaration) {
|
|
|
606
621
|
* @returns A Famix.Parameter representing the parameter
|
|
607
622
|
*/
|
|
608
623
|
function processParameter(paramDecl: ParameterDeclaration): Famix.Parameter {
|
|
609
|
-
const fmxParam = entityDictionary.
|
|
624
|
+
const fmxParam = entityDictionary.createOrGetFamixParameter(paramDecl); // create or GET
|
|
610
625
|
|
|
611
626
|
logger.debug(`parameter: ${paramDecl.getName()}, (${paramDecl.getType().getText()}), fqn = ${fmxParam.fullyQualifiedName}`);
|
|
612
627
|
|
|
@@ -624,17 +639,34 @@ function processParameter(paramDecl: ParameterDeclaration): Famix.Parameter {
|
|
|
624
639
|
return fmxParam;
|
|
625
640
|
}
|
|
626
641
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
*/
|
|
632
|
-
function processTypeParameters(e: ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression |ArrowFunction, fmxScope: Famix.ParametricClass | Famix.ParametricInterface | Famix.Method | Famix.Accessor | Famix.Function | Famix.ArrowFunction): void {
|
|
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 {
|
|
633
646
|
logger.debug(`Finding Type Parameters:`);
|
|
634
|
-
e.
|
|
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) => {
|
|
635
659
|
const fmxParam = processTypeParameter(tp);
|
|
636
660
|
fmxScope.addGenericParameter(fmxParam);
|
|
637
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);
|
|
638
670
|
}
|
|
639
671
|
|
|
640
672
|
/**
|
|
@@ -644,11 +676,8 @@ function processTypeParameters(e: ClassDeclaration | InterfaceDeclaration | Meth
|
|
|
644
676
|
*/
|
|
645
677
|
function processTypeParameter(tp: TypeParameterDeclaration): Famix.ParameterType {
|
|
646
678
|
const fmxTypeParameter = entityDictionary.createFamixParameterType(tp);
|
|
647
|
-
|
|
648
679
|
logger.debug(`type parameter: ${tp.getName()}, (${tp.getType().getText()}), fqn = ${fmxTypeParameter.fullyQualifiedName}`);
|
|
649
|
-
|
|
650
680
|
processComments(tp, fmxTypeParameter);
|
|
651
|
-
|
|
652
681
|
return fmxTypeParameter;
|
|
653
682
|
}
|
|
654
683
|
|
|
@@ -666,7 +695,7 @@ function processVariableStatement(v: VariableStatement): Array<Famix.Variable> {
|
|
|
666
695
|
const fmxVar = processVariable(variable);
|
|
667
696
|
processComments(v, fmxVar);
|
|
668
697
|
fmxVariables.push(fmxVar);
|
|
669
|
-
});
|
|
698
|
+
});
|
|
670
699
|
|
|
671
700
|
return fmxVariables;
|
|
672
701
|
}
|
|
@@ -677,7 +706,7 @@ function processVariableStatement(v: VariableStatement): Array<Famix.Variable> {
|
|
|
677
706
|
* @returns A Famix.Variable representing the variable
|
|
678
707
|
*/
|
|
679
708
|
function processVariable(v: VariableDeclaration): Famix.Variable {
|
|
680
|
-
const fmxVar = entityDictionary.
|
|
709
|
+
const fmxVar = entityDictionary.createOrGetFamixVariable(v);
|
|
681
710
|
|
|
682
711
|
logger.debug(`variable: ${v.getName()}, (${v.getType().getText()}), ${v.getInitializer() ? "initializer: " + v.getInitializer()!.getText() : "initializer: "}, fqn = ${fmxVar.fullyQualifiedName}`);
|
|
683
712
|
|
|
@@ -695,7 +724,7 @@ function processVariable(v: VariableDeclaration): Famix.Variable {
|
|
|
695
724
|
* @returns A Famix.Enum representing the enum
|
|
696
725
|
*/
|
|
697
726
|
function processEnum(e: EnumDeclaration): Famix.Enum {
|
|
698
|
-
const fmxEnum = entityDictionary.
|
|
727
|
+
const fmxEnum = entityDictionary.createOrGetFamixEnum(e);
|
|
699
728
|
|
|
700
729
|
logger.debug(`enum: ${e.getName()}, (${e.getType().getText()}), fqn = ${fmxEnum.fullyQualifiedName}`);
|
|
701
730
|
|
|
@@ -798,8 +827,8 @@ export function processAccesses(accessMap: Map<FamixID, AccessibleTSMorphElement
|
|
|
798
827
|
accessMap.forEach((v, id) => {
|
|
799
828
|
logger.debug(`Accesses to ${v.getName()}`);
|
|
800
829
|
// try {
|
|
801
|
-
|
|
802
|
-
|
|
830
|
+
const temp_nodes = v.findReferencesAsNodes() as Array<Identifier>;
|
|
831
|
+
temp_nodes.forEach(node => processNodeForAccesses(node, id));
|
|
803
832
|
// } catch (error) {
|
|
804
833
|
// logger.error(`> WARNING: got exception "${error}".\nContinuing...`);
|
|
805
834
|
// }
|
|
@@ -813,16 +842,16 @@ export function processAccesses(accessMap: Map<FamixID, AccessibleTSMorphElement
|
|
|
813
842
|
*/
|
|
814
843
|
function processNodeForAccesses(n: Identifier, id: number): void {
|
|
815
844
|
// try {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
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()})`);
|
|
826
855
|
// } catch (error) {
|
|
827
856
|
// logger.error(`> Got exception "${error}".\nScopeDeclaration invalid for "${n.getSymbol().fullyQualifiedName}".\nContinuing...`);
|
|
828
857
|
// }
|
|
@@ -844,12 +873,14 @@ export function processImportClausesForImportEqualsDeclarations(sourceFiles: Arr
|
|
|
844
873
|
// const importedEntity = node.getName();
|
|
845
874
|
// create a famix import clause
|
|
846
875
|
const namedImport = node.getNameNode();
|
|
847
|
-
entityDictionary.
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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
|
+
});
|
|
853
884
|
// entityDictionary.createFamixImportClause(importedEntity, importingEntity);
|
|
854
885
|
}
|
|
855
886
|
});
|
|
@@ -865,7 +896,7 @@ export function processImportClausesForImportEqualsDeclarations(sourceFiles: Arr
|
|
|
865
896
|
export function processImportClausesForModules(modules: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
|
|
866
897
|
logger.info(`Creating import clauses from ${modules.length} modules:`);
|
|
867
898
|
modules.forEach(module => {
|
|
868
|
-
const modulePath = module.getFilePath()
|
|
899
|
+
const modulePath = module.getFilePath();
|
|
869
900
|
module.getImportDeclarations().forEach(impDecl => {
|
|
870
901
|
logger.info(`Importing ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
871
902
|
const path = getModulePath(impDecl);
|
|
@@ -873,39 +904,45 @@ export function processImportClausesForModules(modules: Array<SourceFile>, expor
|
|
|
873
904
|
impDecl.getNamedImports().forEach(namedImport => {
|
|
874
905
|
logger.info(`Importing (named) ${namedImport.getName()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
875
906
|
const importedEntityName = namedImport.getName();
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
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
|
+
});
|
|
883
917
|
});
|
|
884
918
|
|
|
885
919
|
const defaultImport = impDecl.getDefaultImport();
|
|
886
920
|
if (defaultImport !== undefined) {
|
|
887
921
|
logger.info(`Importing (default) ${defaultImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
888
|
-
|
|
889
|
-
entityDictionary.
|
|
922
|
+
logger.debug(`Processing Default Import: ${defaultImport.getText()}, pos=${defaultImport.getStart()}`);
|
|
923
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
924
|
+
importDeclaration: impDecl,
|
|
890
925
|
importerSourceFile: module,
|
|
891
926
|
moduleSpecifierFilePath: path,
|
|
892
927
|
importElement: defaultImport,
|
|
893
928
|
isInExports: false,
|
|
894
|
-
isDefaultExport: true
|
|
929
|
+
isDefaultExport: true
|
|
930
|
+
});
|
|
895
931
|
}
|
|
896
932
|
|
|
897
933
|
const namespaceImport = impDecl.getNamespaceImport();
|
|
898
934
|
if (namespaceImport !== undefined) {
|
|
899
935
|
logger.info(`Importing (namespace) ${namespaceImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
|
|
900
|
-
entityDictionary.
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
936
|
+
entityDictionary.oldCreateOrGetFamixImportClause({
|
|
937
|
+
importDeclaration: impDecl,
|
|
938
|
+
importerSourceFile: module,
|
|
939
|
+
moduleSpecifierFilePath: path,
|
|
940
|
+
importElement: namespaceImport,
|
|
941
|
+
isInExports: false,
|
|
942
|
+
isDefaultExport: false
|
|
943
|
+
});
|
|
907
944
|
}
|
|
908
|
-
});
|
|
945
|
+
});
|
|
909
946
|
});
|
|
910
947
|
}
|
|
911
948
|
|
|
@@ -925,33 +962,44 @@ function isInExports(exports: ReadonlyMap<string, ExportedDeclarations[]>[], imp
|
|
|
925
962
|
* @param interfaces An array of interfaces
|
|
926
963
|
*/
|
|
927
964
|
export function processInheritances(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[]): void {
|
|
928
|
-
logger.info(`
|
|
965
|
+
logger.info(`Creating inheritances:`);
|
|
929
966
|
classes.forEach(cls => {
|
|
930
|
-
logger.debug(`
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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
|
+
}
|
|
942
981
|
|
|
943
|
-
logger.debug(`
|
|
944
|
-
|
|
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
|
+
});
|
|
945
988
|
});
|
|
946
989
|
|
|
947
|
-
interfaces.forEach(
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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);
|
|
952
996
|
|
|
953
|
-
|
|
954
|
-
|
|
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
|
+
}
|
|
955
1003
|
});
|
|
956
1004
|
}
|
|
957
1005
|
|
|
@@ -959,34 +1007,36 @@ export function processInheritances(classes: ClassDeclaration[], interfaces: Int
|
|
|
959
1007
|
* Builds a Famix model for the invocations of the methods and functions of the source files
|
|
960
1008
|
* @param methodsAndFunctionsWithId A map of methods and functions with their id
|
|
961
1009
|
*/
|
|
962
|
-
export function processInvocations(methodsAndFunctionsWithId: Map<number,
|
|
1010
|
+
export function processInvocations(methodsAndFunctionsWithId: Map<number, InvocableType>): void {
|
|
963
1011
|
logger.info(`Creating invocations:`);
|
|
964
|
-
methodsAndFunctionsWithId.forEach((
|
|
965
|
-
if (!(
|
|
966
|
-
logger.debug(`Invocations to ${(
|
|
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()})`);
|
|
967
1015
|
try {
|
|
968
|
-
const
|
|
969
|
-
|
|
1016
|
+
const nodesReferencingInvocable = invocable.findReferencesAsNodes() as Array<Identifier>;
|
|
1017
|
+
nodesReferencingInvocable.forEach(
|
|
1018
|
+
nodeReferencingInvocable => processNodeForInvocations(nodeReferencingInvocable, invocable, id));
|
|
970
1019
|
} catch (error) {
|
|
971
1020
|
logger.error(`> WARNING: got exception ${error}. Continuing...`);
|
|
972
1021
|
}
|
|
1022
|
+
} else {
|
|
1023
|
+
logger.debug(`Skipping invocation to ArrowFunction: ${(invocable.getBodyText())}`);
|
|
973
1024
|
}
|
|
974
1025
|
});
|
|
975
1026
|
}
|
|
976
1027
|
|
|
977
1028
|
/**
|
|
978
1029
|
* Builds a Famix model for an invocation of a method or a function
|
|
979
|
-
* @param
|
|
980
|
-
* @param
|
|
1030
|
+
* @param nodeReferencingInvocable A node
|
|
1031
|
+
* @param invocable A method or a function
|
|
981
1032
|
* @param id The id of the method or the function
|
|
982
1033
|
*/
|
|
983
|
-
function processNodeForInvocations(
|
|
1034
|
+
function processNodeForInvocations(nodeReferencingInvocable: Identifier, invocable: InvocableType, id: number): void {
|
|
984
1035
|
try {
|
|
985
|
-
entityDictionary.createFamixInvocation(
|
|
986
|
-
|
|
987
|
-
logger.debug(`node: node, (${n.getType().getText()})`);
|
|
1036
|
+
entityDictionary.createFamixInvocation(nodeReferencingInvocable, invocable, id);
|
|
1037
|
+
logger.debug(`node: ${nodeReferencingInvocable.getKindName()}, (${nodeReferencingInvocable.getType().getText()})`);
|
|
988
1038
|
} catch (error) {
|
|
989
|
-
logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${
|
|
1039
|
+
logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${nodeReferencingInvocable.getSymbol()!.getFullyQualifiedName()}. Continuing...`);
|
|
990
1040
|
}
|
|
991
1041
|
}
|
|
992
1042
|
|
|
@@ -1002,18 +1052,18 @@ export function processConcretisations(classes: ClassDeclaration[], interfaces:
|
|
|
1002
1052
|
entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(cls);
|
|
1003
1053
|
entityDictionary.createFamixConcretisationGenericInstantiation(cls);
|
|
1004
1054
|
entityDictionary.createFamixConcretisationInterfaceClass(cls);
|
|
1005
|
-
entityDictionary.createFamixConcretisationTypeInstanciation(cls);
|
|
1055
|
+
entityDictionary.createFamixConcretisationTypeInstanciation(cls);
|
|
1006
1056
|
|
|
1007
1057
|
});
|
|
1008
1058
|
interfaces.forEach(inter => {
|
|
1009
1059
|
logger.debug(`processConcretisations: Checking interface concretisation for ${inter.getName()}`);
|
|
1010
|
-
entityDictionary.createFamixConcretisationTypeInstanciation(inter);
|
|
1011
|
-
entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(inter)
|
|
1060
|
+
entityDictionary.createFamixConcretisationTypeInstanciation(inter);
|
|
1061
|
+
entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(inter);
|
|
1012
1062
|
});
|
|
1013
1063
|
functions.forEach(func => {
|
|
1014
1064
|
if(func instanceof FunctionDeclaration || func instanceof MethodDeclaration ){
|
|
1015
1065
|
logger.debug(`processConcretisations: Checking Method concretisation`);
|
|
1016
1066
|
entityDictionary.createFamixConcretisationFunctionInstantiation(func);
|
|
1017
1067
|
}
|
|
1018
|
-
})
|
|
1068
|
+
});
|
|
1019
1069
|
}
|