ts2famix 1.0.8 → 1.0.9
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/metrics.ts +23 -0
- package/package.json +1 -1
- package/src/analyze.ts +33 -29
- package/src/analyze_functions/processFiles.ts +6 -2
- package/src/analyze_functions/processInheritances.ts +1 -1
- package/src/famix_functions/famix_functions.ts +24 -21
- package/src/famix_functions/famix_functions_associations.ts +22 -15
package/metrics.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class ForMetrics {
|
|
2
|
+
public methodCyclomaticOne() {}
|
|
3
|
+
|
|
4
|
+
public methodCyclomaticFour() {
|
|
5
|
+
// make higher cyclomatic complexity
|
|
6
|
+
for (let i = 0; i < 50; i++) { // 2
|
|
7
|
+
for (let j = 0; j < 50; j++) { // 3
|
|
8
|
+
if (i < 10) {} // 4
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function functionCyclomaticOne() {}
|
|
15
|
+
|
|
16
|
+
function functionCyclomaticFour() {
|
|
17
|
+
// make higher cyclomatic complexity
|
|
18
|
+
for (let i = 0; i < 50; i++) { // 2
|
|
19
|
+
for (let j = 0; j < 50; j++) { // 3
|
|
20
|
+
if (i < 10) {} // 4
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
package/package.json
CHANGED
package/src/analyze.ts
CHANGED
|
@@ -27,44 +27,47 @@ export class Importer {
|
|
|
27
27
|
* @returns The Famix repository containing the Famix model
|
|
28
28
|
*/
|
|
29
29
|
public famixRepFromPaths(paths: Array<string>): FamixRepository {
|
|
30
|
-
let famixRep: FamixRepository;
|
|
31
30
|
|
|
32
|
-
try {
|
|
33
|
-
|
|
31
|
+
// try {
|
|
32
|
+
console.info(`famixRepFromPaths: paths: ${paths}`);
|
|
33
|
+
this.project.addSourceFilesAtPaths(paths);
|
|
34
|
+
this.processEntities(this.project);
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const exports = this.processFiles.getExports();
|
|
44
|
-
|
|
45
|
-
this.processImportClauses.processImportClauses(modules, exports);
|
|
46
|
-
this.processAccesses.processAccesses(accesses);
|
|
47
|
-
this.processInvocations.processInvocations(methodsAndFunctionsWithId);
|
|
48
|
-
this.processInheritances.processInheritances(classes, interfaces);
|
|
49
|
-
|
|
50
|
-
famixRep = this.famixFunctions.getFamixRepository();
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
console.error(`> ERROR: got exception ${error}. Exiting...`);
|
|
54
|
-
console.error(error.message);
|
|
55
|
-
console.error(error.stack);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
36
|
+
const famixRep = this.famixFunctions.getFamixRepository();
|
|
37
|
+
// }
|
|
38
|
+
// catch (error) {
|
|
39
|
+
// console.error(`> ERROR: got exception ${error}. Exiting...`);
|
|
40
|
+
// console.error(error.message);
|
|
41
|
+
// console.error(error.stack);
|
|
42
|
+
// process.exit(1);
|
|
43
|
+
// }
|
|
58
44
|
|
|
59
45
|
return famixRep;
|
|
60
46
|
}
|
|
61
47
|
|
|
48
|
+
private processEntities(project) {
|
|
49
|
+
this.processFiles.processFiles(project.getSourceFiles());
|
|
50
|
+
const accesses = this.processFiles.getAccesses();
|
|
51
|
+
const methodsAndFunctionsWithId = this.processFiles.getMethodsAndFunctionsWithId();
|
|
52
|
+
const classes = this.processFiles.getClasses();
|
|
53
|
+
const interfaces = this.processFiles.getInterfaces();
|
|
54
|
+
const modules = this.processFiles.getModules();
|
|
55
|
+
const exports = this.processFiles.getExports();
|
|
56
|
+
|
|
57
|
+
this.processImportClauses.processImportClauses(modules, exports);
|
|
58
|
+
this.processAccesses.processAccesses(accesses);
|
|
59
|
+
this.processInvocations.processInvocations(methodsAndFunctionsWithId);
|
|
60
|
+
this.processInheritances.processInheritances(classes, interfaces);
|
|
61
|
+
}
|
|
62
|
+
|
|
62
63
|
/**
|
|
63
64
|
* Main method for tests
|
|
65
|
+
*
|
|
64
66
|
* @param filename The name of the file to analyze
|
|
65
67
|
* @param source A TypeScript source code
|
|
66
68
|
* @returns The Famix repository containing the Famix model
|
|
67
69
|
*/
|
|
70
|
+
// TODO: this is slow because it writes the source code to a file and then reads it again - it's possible to just pass the source code to the ts-morph project
|
|
68
71
|
public famixRepFromSource(filename: string, source: string): FamixRepository {
|
|
69
72
|
const filePath = `./test_src/${filename}.ts`;
|
|
70
73
|
|
|
@@ -81,10 +84,11 @@ export class Importer {
|
|
|
81
84
|
* @returns The Famix repository containing the Famix model
|
|
82
85
|
*/
|
|
83
86
|
public famixRepFromProject(project: Project): FamixRepository {
|
|
84
|
-
const sourceFileNames = project.getSourceFiles().map(f => f.getFilePath()) as Array<string>;
|
|
87
|
+
//const sourceFileNames = project.getSourceFiles().map(f => f.getFilePath()) as Array<string>;
|
|
85
88
|
|
|
86
|
-
const famixRep = this.famixRepFromPaths(sourceFileNames);
|
|
89
|
+
//const famixRep = this.famixRepFromPaths(sourceFileNames);
|
|
90
|
+
this.processEntities(project);
|
|
87
91
|
|
|
88
|
-
return
|
|
92
|
+
return this.famixFunctions.getFamixRepository();
|
|
89
93
|
}
|
|
90
94
|
}
|
|
@@ -2,6 +2,7 @@ import { ClassDeclaration, MethodDeclaration, VariableStatement, FunctionDeclara
|
|
|
2
2
|
import * as Famix from "../lib/famix/src/model/famix";
|
|
3
3
|
import { FamixFunctions } from "../famix_functions/famix_functions";
|
|
4
4
|
import { calculate } from "../lib/ts-complex/cyclomatic-service";
|
|
5
|
+
import * as fs from 'fs';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* This class is used to build a Famix model for an array of source files
|
|
@@ -33,8 +34,11 @@ export class ProcessFiles {
|
|
|
33
34
|
sourceFiles.forEach(file => {
|
|
34
35
|
console.info(`processFiles: File: >>>>>>>>>> ${file.getBaseName()}`);
|
|
35
36
|
|
|
36
|
-
// Computes the cyclomatic complexity metrics for the current source file
|
|
37
|
-
|
|
37
|
+
// Computes the cyclomatic complexity metrics for the current source file if it exists (i.e. if it is not from a jest test)
|
|
38
|
+
if (fs.existsSync(file.getFilePath()))
|
|
39
|
+
this.currentCC = calculate(file.getFilePath());
|
|
40
|
+
else
|
|
41
|
+
this.currentCC = 0;
|
|
38
42
|
|
|
39
43
|
this.processFile(file);
|
|
40
44
|
});
|
|
@@ -21,7 +21,7 @@ export class ProcessInheritances {
|
|
|
21
21
|
* @param classes An array of classes
|
|
22
22
|
* @param interfaces An array of interfaces
|
|
23
23
|
*/
|
|
24
|
-
public processInheritances(classes:
|
|
24
|
+
public processInheritances(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[]): void {
|
|
25
25
|
console.info(`processInheritances: Creating inheritances:`);
|
|
26
26
|
classes.forEach(cls => {
|
|
27
27
|
console.info(`processInheritances: Checking class inheritance for ${cls.getName()}`);
|
|
@@ -13,13 +13,13 @@ export class FamixFunctions {
|
|
|
13
13
|
|
|
14
14
|
private famixRep = new FamixRepository(); // The Famix repository
|
|
15
15
|
private FQNFunctions = new FQNFunctions(); // The fully qualified name functions
|
|
16
|
-
private
|
|
17
|
-
private
|
|
18
|
-
private
|
|
19
|
-
private
|
|
20
|
-
private
|
|
16
|
+
private fmxAliasMap = new Map<string, Famix.Alias>(); // Maps the alias names to their Famix model
|
|
17
|
+
private fmxClassMap = new Map<string, Famix.Class | Famix.ParameterizableClass>(); // Maps the fully qualifiedclass names to their Famix model
|
|
18
|
+
private fmxInterfaceMap = new Map<string, Famix.Interface | Famix.ParameterizableInterface>(); // Maps the interface names to their Famix model
|
|
19
|
+
private fmxNamespaceMap = new Map<string, Famix.Namespace>(); // Maps the namespace names to their Famix model
|
|
20
|
+
private fmxFileMap = new Map<string, Famix.ScriptEntity | Famix.Module>(); // Maps the source file names to their Famix model
|
|
21
21
|
private famixFunctionsIndex = new FamixFunctionsIndex(this.famixRep); // FamixFunctionsIndex object, it contains all the functions needed to create Famix index file anchors
|
|
22
|
-
private famixFunctionsAssociations = new FamixFunctionsAssociations(this.famixRep, this.
|
|
22
|
+
private famixFunctionsAssociations = new FamixFunctionsAssociations(this.famixRep, this.fmxClassMap, this.fmxInterfaceMap); // FamixFunctionsAssociations object, it contains all the functions needed to create Famix associations
|
|
23
23
|
private famixFunctionsTypes = new FamixFunctionsTypes(this.famixRep); // FamixFunctionsTypes object, it contains all the functions needed to create Famix types
|
|
24
24
|
private UNKNOWN_VALUE = '(unknown due to parsing error)'; // The value to use when a name is not usable
|
|
25
25
|
|
|
@@ -40,7 +40,7 @@ export class FamixFunctions {
|
|
|
40
40
|
public createOrGetFamixFile(f: SourceFile, isModule: boolean): Famix.ScriptEntity | Famix.Module {
|
|
41
41
|
let fmxFile: Famix.ScriptEntity | Famix.Module;
|
|
42
42
|
const fileName = f.getBaseName();
|
|
43
|
-
if (!this.
|
|
43
|
+
if (!this.fmxFileMap.has(fileName)) {
|
|
44
44
|
if (isModule) {
|
|
45
45
|
fmxFile = new Famix.Module(this.famixRep);
|
|
46
46
|
}
|
|
@@ -53,10 +53,10 @@ export class FamixFunctions {
|
|
|
53
53
|
|
|
54
54
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(f, fmxFile);
|
|
55
55
|
|
|
56
|
-
this.
|
|
56
|
+
this.fmxFileMap.set(fileName, fmxFile);
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
|
-
fmxFile = this.
|
|
59
|
+
fmxFile = this.fmxFileMap.get(fileName);
|
|
60
60
|
}
|
|
61
61
|
return fmxFile;
|
|
62
62
|
}
|
|
@@ -69,16 +69,16 @@ export class FamixFunctions {
|
|
|
69
69
|
public createOrGetFamixNamespace(m: ModuleDeclaration): Famix.Namespace {
|
|
70
70
|
let fmxNamespace: Famix.Namespace;
|
|
71
71
|
const namespaceName = m.getName();
|
|
72
|
-
if (!this.
|
|
72
|
+
if (!this.fmxNamespaceMap.has(namespaceName)) {
|
|
73
73
|
fmxNamespace = new Famix.Namespace(this.famixRep);
|
|
74
74
|
fmxNamespace.setName(namespaceName);
|
|
75
75
|
|
|
76
76
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(m, fmxNamespace);
|
|
77
77
|
|
|
78
|
-
this.
|
|
78
|
+
this.fmxNamespaceMap.set(namespaceName, fmxNamespace);
|
|
79
79
|
}
|
|
80
80
|
else {
|
|
81
|
-
fmxNamespace = this.
|
|
81
|
+
fmxNamespace = this.fmxNamespaceMap.get(namespaceName);
|
|
82
82
|
}
|
|
83
83
|
return fmxNamespace;
|
|
84
84
|
}
|
|
@@ -91,7 +91,7 @@ export class FamixFunctions {
|
|
|
91
91
|
public createFamixAlias(a: TypeAliasDeclaration): Famix.Alias {
|
|
92
92
|
let fmxAlias: Famix.Alias;
|
|
93
93
|
const aliasName = a.getName();
|
|
94
|
-
if (!this.
|
|
94
|
+
if (!this.fmxAliasMap.has(aliasName)) {
|
|
95
95
|
fmxAlias = new Famix.Alias(this.famixRep);
|
|
96
96
|
fmxAlias.setName(a.getName());
|
|
97
97
|
|
|
@@ -100,10 +100,10 @@ export class FamixFunctions {
|
|
|
100
100
|
|
|
101
101
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(a, fmxAlias);
|
|
102
102
|
|
|
103
|
-
this.
|
|
103
|
+
this.fmxAliasMap.set(aliasName, fmxAlias);
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
|
-
fmxAlias = this.
|
|
106
|
+
fmxAlias = this.fmxAliasMap.get(aliasName);
|
|
107
107
|
}
|
|
108
108
|
return fmxAlias;
|
|
109
109
|
}
|
|
@@ -116,8 +116,9 @@ export class FamixFunctions {
|
|
|
116
116
|
public createOrGetFamixClass(cls: ClassDeclaration): Famix.Class | Famix.ParameterizableClass {
|
|
117
117
|
let fmxClass: Famix.Class | Famix.ParameterizableClass;
|
|
118
118
|
const isAbstract = cls.isAbstract();
|
|
119
|
+
const classFullyQualifiedName = this.FQNFunctions.getFQN(cls);
|
|
119
120
|
const clsName = cls.getName();
|
|
120
|
-
if (!this.
|
|
121
|
+
if (!this.fmxClassMap.has(classFullyQualifiedName)) {
|
|
121
122
|
const isGeneric = cls.getTypeParameters().length;
|
|
122
123
|
if (isGeneric) {
|
|
123
124
|
fmxClass = new Famix.ParameterizableClass(this.famixRep);
|
|
@@ -127,14 +128,15 @@ export class FamixFunctions {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
fmxClass.setName(clsName);
|
|
131
|
+
fmxClass.setFullyQualifiedName(classFullyQualifiedName);
|
|
130
132
|
fmxClass.setIsAbstract(isAbstract);
|
|
131
133
|
|
|
132
134
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(cls, fmxClass);
|
|
133
135
|
|
|
134
|
-
this.
|
|
136
|
+
this.fmxClassMap.set(classFullyQualifiedName, fmxClass);
|
|
135
137
|
}
|
|
136
138
|
else {
|
|
137
|
-
fmxClass = this.
|
|
139
|
+
fmxClass = this.fmxClassMap.get(classFullyQualifiedName) as (Famix.Class | Famix.ParameterizableClass);
|
|
138
140
|
}
|
|
139
141
|
return fmxClass;
|
|
140
142
|
}
|
|
@@ -147,7 +149,8 @@ export class FamixFunctions {
|
|
|
147
149
|
public createOrGetFamixInterface(inter: InterfaceDeclaration): Famix.Interface | Famix.ParameterizableInterface {
|
|
148
150
|
let fmxInterface: Famix.Interface | Famix.ParameterizableInterface;
|
|
149
151
|
const interName = inter.getName();
|
|
150
|
-
|
|
152
|
+
const interFullyQualifiedName = this.FQNFunctions.getFQN(inter);
|
|
153
|
+
if (!this.fmxInterfaceMap.has(interName)) {
|
|
151
154
|
const isGeneric = inter.getTypeParameters().length;
|
|
152
155
|
if (isGeneric) {
|
|
153
156
|
fmxInterface = new Famix.ParameterizableInterface(this.famixRep);
|
|
@@ -160,10 +163,10 @@ export class FamixFunctions {
|
|
|
160
163
|
|
|
161
164
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(inter, fmxInterface);
|
|
162
165
|
|
|
163
|
-
this.
|
|
166
|
+
this.fmxInterfaceMap.set(interFullyQualifiedName, fmxInterface);
|
|
164
167
|
}
|
|
165
168
|
else {
|
|
166
|
-
fmxInterface = this.
|
|
169
|
+
fmxInterface = this.fmxInterfaceMap.get(interName) as (Famix.Interface | Famix.ParameterizableInterface);
|
|
167
170
|
}
|
|
168
171
|
return fmxInterface;
|
|
169
172
|
}
|
|
@@ -11,20 +11,20 @@ export class FamixFunctionsAssociations {
|
|
|
11
11
|
|
|
12
12
|
private famixRep: FamixRepository; // The Famix repository
|
|
13
13
|
private FQNFunctions = new FQNFunctions(); // The fully qualified name functions
|
|
14
|
-
private
|
|
15
|
-
private
|
|
14
|
+
private famixClassMap: Map<string, Famix.Class | Famix.ParameterizableClass>; // Maps the class names to their Famix model
|
|
15
|
+
private famixInterfaceMap: Map<string, Famix.Interface | Famix.ParameterizableInterface>; // Maps the interface names to their Famix model
|
|
16
16
|
private famixFunctionsIndex: FamixFunctionsIndex; // FamixFunctionsIndex object, it contains all the functions needed to create Famix index file anchors
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Initializes the FamixFunctionsAssociations object
|
|
20
20
|
* @param famixRep The Famix repository
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
21
|
+
* @param fmxClassMap The map of the class names and their Famix model
|
|
22
|
+
* @param fmxInterfaceMap The map of the interface names and their Famix model
|
|
23
23
|
*/
|
|
24
|
-
constructor(famixRep: FamixRepository,
|
|
24
|
+
constructor(famixRep: FamixRepository, fmxClassMap: Map<string, Famix.Class | Famix.ParameterizableClass>, fmxInterfaceMap: Map<string, Famix.Interface | Famix.ParameterizableInterface>) {
|
|
25
25
|
this.famixRep = famixRep;
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
26
|
+
this.famixClassMap = fmxClassMap;
|
|
27
|
+
this.famixInterfaceMap = fmxInterfaceMap;
|
|
28
28
|
this.famixFunctionsIndex = new FamixFunctionsIndex(famixRep);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -76,42 +76,49 @@ export class FamixFunctionsAssociations {
|
|
|
76
76
|
*/
|
|
77
77
|
public createFamixInheritance(cls: ClassDeclaration | InterfaceDeclaration, inhClass: ClassDeclaration | InterfaceDeclaration | ExpressionWithTypeArguments): void {
|
|
78
78
|
const fmxInheritance = new Famix.Inheritance(this.famixRep);
|
|
79
|
-
const clsName = cls.getName();
|
|
80
|
-
|
|
79
|
+
// const clsName = cls.getName();
|
|
80
|
+
const classFullyQualifiedName = this.FQNFunctions.getFQN(cls);
|
|
81
|
+
console.info(`createFamixInheritance: classFullyQualifiedName: class fqn = ${classFullyQualifiedName}`);
|
|
81
82
|
let subClass: Famix.Class | Famix.Interface;
|
|
82
83
|
if (cls instanceof ClassDeclaration) {
|
|
83
|
-
subClass = this.
|
|
84
|
+
subClass = this.famixClassMap.get(classFullyQualifiedName);
|
|
84
85
|
}
|
|
85
86
|
else {
|
|
86
|
-
subClass = this.
|
|
87
|
+
subClass = this.famixInterfaceMap.get(classFullyQualifiedName);
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
let inhClassName: string;
|
|
91
|
+
let inhClassFullyQualifiedName: string;
|
|
90
92
|
let superClass: Famix.Class | Famix.Interface;
|
|
91
93
|
if (inhClass instanceof ClassDeclaration || inhClass instanceof InterfaceDeclaration) {
|
|
92
94
|
inhClassName = inhClass.getName();
|
|
95
|
+
inhClassFullyQualifiedName = this.FQNFunctions.getFQN(inhClass);
|
|
93
96
|
if (inhClass instanceof ClassDeclaration) {
|
|
94
|
-
superClass = this.
|
|
97
|
+
superClass = this.famixClassMap.get(inhClassFullyQualifiedName);
|
|
95
98
|
}
|
|
96
99
|
else {
|
|
97
|
-
superClass = this.
|
|
100
|
+
superClass = this.famixInterfaceMap.get(inhClassFullyQualifiedName);
|
|
98
101
|
}
|
|
99
102
|
}
|
|
100
103
|
else {
|
|
104
|
+
// inhClass is an ExpressionWithTypeArguments
|
|
101
105
|
inhClassName = inhClass.getExpression().getText();
|
|
106
|
+
// what is inhClassFullyQualifiedName? TODO
|
|
107
|
+
inhClassFullyQualifiedName = 'Undefined_Scope_from_importer.' + inhClassName;
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
if (superClass === undefined) {
|
|
105
111
|
if (inhClass instanceof ClassDeclaration) {
|
|
106
112
|
superClass = new Famix.Class(this.famixRep);
|
|
107
|
-
this.
|
|
113
|
+
this.famixClassMap.set(inhClassFullyQualifiedName, superClass);
|
|
108
114
|
}
|
|
109
115
|
else {
|
|
110
116
|
superClass = new Famix.Interface(this.famixRep);
|
|
111
|
-
this.
|
|
117
|
+
this.famixInterfaceMap.set(inhClassFullyQualifiedName, superClass);
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
superClass.setName(inhClassName);
|
|
121
|
+
superClass.setFullyQualifiedName(inhClassFullyQualifiedName);
|
|
115
122
|
superClass.setIsStub(true);
|
|
116
123
|
|
|
117
124
|
this.famixFunctionsIndex.makeFamixIndexFileAnchor(inhClass, superClass);
|