ts2famix 1.4.1 → 2.0.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.
Files changed (210) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +30 -61
  3. package/dist/analyze.js +4 -2
  4. package/dist/analyze_functions/process_functions.js +285 -131
  5. package/dist/famix_functions/EntityDictionary.js +864 -231
  6. package/dist/famix_functions/helpers_creation.js +61 -10
  7. package/dist/fqn.js +160 -111
  8. package/dist/lib/famix/famix_JSON_exporter.js +55 -0
  9. package/dist/lib/famix/famix_base_element.js +18 -0
  10. package/dist/lib/famix/famix_repository.js +224 -0
  11. package/dist/lib/famix/{src/index.js → index.js} +1 -0
  12. package/dist/lib/famix/model/famix/access.js +40 -0
  13. package/dist/lib/famix/model/famix/accessor.js +17 -0
  14. package/dist/lib/famix/model/famix/alias.js +33 -0
  15. package/dist/lib/famix/model/famix/arrow_function.js +17 -0
  16. package/dist/lib/famix/model/famix/behavioral_entity.js +79 -0
  17. package/dist/lib/famix/model/famix/class.js +71 -0
  18. package/dist/lib/famix/model/famix/comment.js +39 -0
  19. package/dist/lib/famix/model/famix/concretisation.js +31 -0
  20. package/dist/lib/famix/model/famix/container_entity.js +126 -0
  21. package/dist/lib/famix/model/famix/decorator.js +32 -0
  22. package/dist/lib/famix/model/famix/entity.js +17 -0
  23. package/dist/lib/famix/model/famix/enum.js +31 -0
  24. package/dist/lib/famix/model/famix/enum_value.js +25 -0
  25. package/dist/lib/famix/model/famix/function.js +17 -0
  26. package/dist/lib/famix/model/famix/import_clause.js +41 -0
  27. package/dist/lib/famix/model/famix/index.js +86 -0
  28. package/dist/lib/famix/model/famix/indexed_file_anchor.js +38 -0
  29. package/dist/lib/famix/model/famix/inheritance.js +33 -0
  30. package/dist/lib/famix/model/famix/interface.js +64 -0
  31. package/dist/lib/famix/model/famix/invocation.js +54 -0
  32. package/dist/lib/famix/model/famix/method.js +67 -0
  33. package/dist/lib/famix/model/famix/module.js +60 -0
  34. package/dist/lib/famix/model/famix/named_entity.js +78 -0
  35. package/dist/lib/famix/model/famix/parameter.js +25 -0
  36. package/dist/lib/famix/model/famix/parameter_concretisation.js +44 -0
  37. package/dist/lib/famix/model/famix/parameter_type.js +45 -0
  38. package/dist/lib/famix/model/famix/parametric_arrow_function.js +31 -0
  39. package/dist/lib/famix/model/famix/parametric_class.js +44 -0
  40. package/dist/lib/famix/model/famix/parametric_function.js +31 -0
  41. package/dist/lib/famix/model/famix/parametric_interface.js +44 -0
  42. package/dist/lib/famix/model/famix/parametric_method.js +31 -0
  43. package/dist/lib/famix/model/famix/primitive_type.js +17 -0
  44. package/dist/lib/famix/model/famix/property.js +73 -0
  45. package/dist/lib/famix/model/famix/reference.js +33 -0
  46. package/dist/lib/famix/model/famix/scoping_entity.js +36 -0
  47. package/dist/lib/famix/model/famix/script_entity.js +29 -0
  48. package/dist/lib/famix/model/famix/source_anchor.js +27 -0
  49. package/dist/lib/famix/model/famix/source_language.js +35 -0
  50. package/dist/lib/famix/model/famix/sourced_entity.js +60 -0
  51. package/dist/lib/famix/model/famix/structural_entity.js +39 -0
  52. package/dist/lib/famix/model/famix/type.js +73 -0
  53. package/dist/lib/famix/model/famix/variable.js +24 -0
  54. package/dist/lib/ts-complex/cyclomatic-service.js +3 -3
  55. package/dist/refactorer/refactor-getter-setter.js +142 -0
  56. package/dist/ts2famix-cli-wrapper.js +42 -0
  57. package/dist/ts2famix-cli.js +8 -1
  58. package/dist/ts2famix-tsconfig.js +1 -0
  59. package/doc-uml/famix-typescript-model.puml +608 -0
  60. package/doc-uml/famix-typescript-model.svg +1 -0
  61. package/jest.config.json +2 -1
  62. package/package.json +13 -12
  63. package/src/analyze.ts +24 -23
  64. package/src/analyze_functions/process_functions.ts +310 -129
  65. package/src/famix_functions/EntityDictionary.ts +949 -271
  66. package/src/famix_functions/helpers_creation.ts +64 -6
  67. package/src/fqn.ts +169 -96
  68. package/{dist/lib/famix/src/famix_JSON_exporter.js → src/lib/famix/famix_JSON_exporter.ts} +16 -14
  69. package/src/lib/famix/famix_base_element.ts +22 -0
  70. package/{dist/lib/famix/src/famix_repository.js → src/lib/famix/famix_repository.ts} +96 -75
  71. package/src/lib/famix/model/famix/access.ts +50 -0
  72. package/src/lib/famix/model/famix/alias.ts +39 -0
  73. package/src/lib/famix/{src/model/famix/implicit_variable.ts → model/famix/arrow_function.ts} +3 -3
  74. package/src/lib/famix/model/famix/behavioral_entity.ts +97 -0
  75. package/src/lib/famix/model/famix/class.ts +85 -0
  76. package/src/lib/famix/model/famix/comment.ts +47 -0
  77. package/src/lib/famix/model/famix/concretisation.ts +40 -0
  78. package/src/lib/famix/model/famix/container_entity.ts +160 -0
  79. package/src/lib/famix/model/famix/decorator.ts +37 -0
  80. package/src/lib/famix/model/famix/enum.ts +30 -0
  81. package/src/lib/famix/model/famix/enum_value.ts +28 -0
  82. package/src/lib/famix/model/famix/import_clause.ts +51 -0
  83. package/src/lib/famix/{src/model → model}/famix/index.ts +8 -7
  84. package/src/lib/famix/model/famix/indexed_file_anchor.ts +46 -0
  85. package/src/lib/famix/model/famix/inheritance.ts +40 -0
  86. package/src/lib/famix/model/famix/interface.ts +75 -0
  87. package/src/lib/famix/model/famix/invocation.ts +65 -0
  88. package/src/lib/famix/model/famix/method.ts +89 -0
  89. package/src/lib/famix/model/famix/module.ts +71 -0
  90. package/src/lib/famix/model/famix/named_entity.ts +95 -0
  91. package/src/lib/famix/{src/model → model}/famix/parameter.ts +11 -12
  92. package/src/lib/famix/model/famix/parameter_concretisation.ts +51 -0
  93. package/src/lib/famix/model/famix/parameter_type.ts +58 -0
  94. package/src/lib/famix/model/famix/parametric_arrow_function.ts +32 -0
  95. package/src/lib/famix/model/famix/parametric_class.ts +49 -0
  96. package/src/lib/famix/model/famix/parametric_function.ts +32 -0
  97. package/src/lib/famix/model/famix/parametric_interface.ts +49 -0
  98. package/src/lib/famix/model/famix/parametric_method.ts +32 -0
  99. package/src/lib/famix/model/famix/primitive_type.ts +15 -0
  100. package/src/lib/famix/model/famix/property.ts +94 -0
  101. package/src/lib/famix/model/famix/reference.ts +40 -0
  102. package/src/lib/famix/model/famix/scoping_entity.ts +35 -0
  103. package/src/lib/famix/model/famix/script_entity.ts +34 -0
  104. package/src/lib/famix/model/famix/source_anchor.ts +30 -0
  105. package/src/lib/famix/model/famix/source_language.ts +35 -0
  106. package/src/lib/famix/model/famix/sourced_entity.ts +70 -0
  107. package/src/lib/famix/model/famix/structural_entity.ts +43 -0
  108. package/src/lib/famix/model/famix/type.ts +87 -0
  109. package/src/lib/famix/model/famix/variable.ts +27 -0
  110. package/src/lib/famix/package.json +1 -1
  111. package/src/lib/ts-complex/cyclomatic-service.ts +10 -10
  112. package/src/refactorer/refactor-getter-setter.ts +140 -0
  113. package/src/ts2famix-cli-wrapper.ts +21 -0
  114. package/src/ts2famix-cli.ts +8 -2
  115. package/tsconfig.check-tests.json +14 -0
  116. package/tsconfig.json +71 -69
  117. package/dist/famix2puml.js +0 -125
  118. package/dist/lib/famix/src/famix_base_element.js +0 -17
  119. package/dist/lib/famix/src/model/famix/access.js +0 -39
  120. package/dist/lib/famix/src/model/famix/accessor.js +0 -16
  121. package/dist/lib/famix/src/model/famix/alias.js +0 -32
  122. package/dist/lib/famix/src/model/famix/association.js +0 -36
  123. package/dist/lib/famix/src/model/famix/behavioral_entity.js +0 -81
  124. package/dist/lib/famix/src/model/famix/class.js +0 -70
  125. package/dist/lib/famix/src/model/famix/comment.js +0 -38
  126. package/dist/lib/famix/src/model/famix/container_entity.js +0 -125
  127. package/dist/lib/famix/src/model/famix/decorator.js +0 -31
  128. package/dist/lib/famix/src/model/famix/entity.js +0 -16
  129. package/dist/lib/famix/src/model/famix/enum.js +0 -30
  130. package/dist/lib/famix/src/model/famix/enum_value.js +0 -24
  131. package/dist/lib/famix/src/model/famix/function.js +0 -16
  132. package/dist/lib/famix/src/model/famix/implicit_variable.js +0 -16
  133. package/dist/lib/famix/src/model/famix/import_clause.js +0 -39
  134. package/dist/lib/famix/src/model/famix/index.js +0 -83
  135. package/dist/lib/famix/src/model/famix/indexed_file_anchor.js +0 -51
  136. package/dist/lib/famix/src/model/famix/inheritance.js +0 -32
  137. package/dist/lib/famix/src/model/famix/interface.js +0 -63
  138. package/dist/lib/famix/src/model/famix/invocation.js +0 -53
  139. package/dist/lib/famix/src/model/famix/method.js +0 -66
  140. package/dist/lib/famix/src/model/famix/module.js +0 -31
  141. package/dist/lib/famix/src/model/famix/named_entity.js +0 -77
  142. package/dist/lib/famix/src/model/famix/namespace.js +0 -24
  143. package/dist/lib/famix/src/model/famix/parameter.js +0 -24
  144. package/dist/lib/famix/src/model/famix/parameter_type.js +0 -24
  145. package/dist/lib/famix/src/model/famix/parameterizable_class.js +0 -30
  146. package/dist/lib/famix/src/model/famix/parameterizable_interface.js +0 -30
  147. package/dist/lib/famix/src/model/famix/parameterized_type.js +0 -36
  148. package/dist/lib/famix/src/model/famix/primitive_type.js +0 -16
  149. package/dist/lib/famix/src/model/famix/property.js +0 -44
  150. package/dist/lib/famix/src/model/famix/reference.js +0 -32
  151. package/dist/lib/famix/src/model/famix/scoping_entity.js +0 -35
  152. package/dist/lib/famix/src/model/famix/script_entity.js +0 -30
  153. package/dist/lib/famix/src/model/famix/source_anchor.js +0 -26
  154. package/dist/lib/famix/src/model/famix/source_language.js +0 -35
  155. package/dist/lib/famix/src/model/famix/sourced_entity.js +0 -59
  156. package/dist/lib/famix/src/model/famix/structural_entity.js +0 -38
  157. package/dist/lib/famix/src/model/famix/text_anchor.js +0 -37
  158. package/dist/lib/famix/src/model/famix/type.js +0 -71
  159. package/dist/lib/famix/src/model/famix/variable.js +0 -23
  160. package/doc-uml/metamodel-full.svg +0 -1
  161. package/doc-uml/metamodel.svg +0 -1
  162. package/jest.config-old.ts +0 -199
  163. package/plantuml.jar +0 -0
  164. package/src/famix2puml.ts +0 -119
  165. package/src/lib/famix/package-lock.json +0 -301
  166. package/src/lib/famix/readme.md +0 -5
  167. package/src/lib/famix/src/famix_JSON_exporter.ts +0 -56
  168. package/src/lib/famix/src/famix_base_element.ts +0 -22
  169. package/src/lib/famix/src/famix_repository.ts +0 -243
  170. package/src/lib/famix/src/model/famix/access.ts +0 -53
  171. package/src/lib/famix/src/model/famix/alias.ts +0 -41
  172. package/src/lib/famix/src/model/famix/association.ts +0 -44
  173. package/src/lib/famix/src/model/famix/behavioral_entity.ts +0 -107
  174. package/src/lib/famix/src/model/famix/class.ts +0 -86
  175. package/src/lib/famix/src/model/famix/comment.ts +0 -50
  176. package/src/lib/famix/src/model/famix/container_entity.ts +0 -165
  177. package/src/lib/famix/src/model/famix/decorator.ts +0 -39
  178. package/src/lib/famix/src/model/famix/enum.ts +0 -31
  179. package/src/lib/famix/src/model/famix/enum_value.ts +0 -29
  180. package/src/lib/famix/src/model/famix/import_clause.ts +0 -53
  181. package/src/lib/famix/src/model/famix/indexed_file_anchor.ts +0 -71
  182. package/src/lib/famix/src/model/famix/inheritance.ts +0 -42
  183. package/src/lib/famix/src/model/famix/interface.ts +0 -75
  184. package/src/lib/famix/src/model/famix/invocation.ts +0 -68
  185. package/src/lib/famix/src/model/famix/method.ts +0 -96
  186. package/src/lib/famix/src/model/famix/module.ts +0 -31
  187. package/src/lib/famix/src/model/famix/named_entity.ts +0 -98
  188. package/src/lib/famix/src/model/famix/namespace.ts +0 -28
  189. package/src/lib/famix/src/model/famix/parameter_type.ts +0 -33
  190. package/src/lib/famix/src/model/famix/parameterizable_class.ts +0 -31
  191. package/src/lib/famix/src/model/famix/parameterizable_interface.ts +0 -31
  192. package/src/lib/famix/src/model/famix/parameterized_type.ts +0 -40
  193. package/src/lib/famix/src/model/famix/primitive_type.ts +0 -15
  194. package/src/lib/famix/src/model/famix/property.ts +0 -54
  195. package/src/lib/famix/src/model/famix/reference.ts +0 -42
  196. package/src/lib/famix/src/model/famix/scoping_entity.ts +0 -35
  197. package/src/lib/famix/src/model/famix/script_entity.ts +0 -38
  198. package/src/lib/famix/src/model/famix/source_anchor.ts +0 -31
  199. package/src/lib/famix/src/model/famix/source_language.ts +0 -37
  200. package/src/lib/famix/src/model/famix/sourced_entity.ts +0 -73
  201. package/src/lib/famix/src/model/famix/structural_entity.ts +0 -44
  202. package/src/lib/famix/src/model/famix/text_anchor.ts +0 -49
  203. package/src/lib/famix/src/model/famix/type.ts +0 -88
  204. package/src/lib/famix/src/model/famix/variable.ts +0 -28
  205. package/src/lib/famix/tsconfig.json +0 -27
  206. package/src/lib/famix/tslint.json +0 -15
  207. /package/src/lib/famix/{src/index.ts → index.ts} +0 -0
  208. /package/src/lib/famix/{src/model → model}/famix/accessor.ts +0 -0
  209. /package/src/lib/famix/{src/model → model}/famix/entity.ts +0 -0
  210. /package/src/lib/famix/{src/model → model}/famix/function.ts +0 -0
@@ -1,43 +1,48 @@
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";
1
+ import { ClassDeclaration, MethodDeclaration, VariableStatement, FunctionDeclaration, VariableDeclaration, InterfaceDeclaration, ParameterDeclaration, ConstructorDeclaration, MethodSignature, SourceFile, ModuleDeclaration, PropertyDeclaration, PropertySignature, Decorator, GetAccessorDeclaration, SetAccessorDeclaration, ExportedDeclarations, CommentRange, EnumDeclaration, EnumMember, TypeParameterDeclaration, TypeAliasDeclaration, SyntaxKind, FunctionExpression, Block, Identifier, ExpressionWithTypeArguments, ImportDeclaration, Node, ArrowFunction, Scope, ClassExpression } from "ts-morph";
2
+ import * as Famix from "../lib/famix/model/famix";
3
3
  import { calculate } from "../lib/ts-complex/cyclomatic-service";
4
4
  import * as fs from 'fs';
5
5
  import { logger , entityDictionary } from "../analyze";
6
+ import { getFQN } from "../fqn";
6
7
 
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
8
+ export type AccessibleTSMorphElement = ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember;
9
+ export type FamixID = number;
10
+
11
+ export const methodsAndFunctionsWithId = new Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction>(); // Maps the Famix method, constructor, getter, setter and function ids to their ts-morph method, constructor, getter, setter or function object
12
+
13
+ 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
9
14
  export const classes = new Array<ClassDeclaration>(); // Array of all the classes of the source files
10
15
  export const interfaces = new Array<InterfaceDeclaration>(); // Array of all the interfaces of the source files
11
16
  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
17
+ export const listOfExportMaps = new Array<ReadonlyMap<string, ExportedDeclarations[]>>(); // Array of all the export maps
18
+ export let currentCC: { [key: string]: number }; // Stores the cyclomatic complexity metrics for the current source file
14
19
 
15
20
  /**
16
21
  * Checks if the file has any imports or exports to be considered a module
17
22
  * @param sourceFile A source file
18
23
  * @returns A boolean indicating if the file is a module
19
24
  */
20
- function ismodule(sourceFile: SourceFile): boolean {
25
+ function isSourceFileAModule(sourceFile: SourceFile): boolean {
21
26
  return sourceFile.getImportDeclarations().length > 0 || sourceFile.getExportedDeclarations().size > 0;
22
27
  }
23
28
 
24
29
  /**
25
30
  * Gets the path of a module to be imported
26
- * @param i An import declaration
31
+ * @param importDecl An import declaration
27
32
  * @returns The path of the module to be imported
28
33
  */
29
- export function getModulePath(i: ImportDeclaration): string {
34
+ export function getModulePath(importDecl: ImportDeclaration): string {
30
35
  let path: string;
31
- if (i.getModuleSpecifierSourceFile() === undefined) {
32
- if (i.getModuleSpecifierValue().substring(i.getModuleSpecifierValue().length - 3) === ".ts") {
33
- path = i.getModuleSpecifierValue();
36
+ if (importDecl.getModuleSpecifierSourceFile() === undefined) {
37
+ if (importDecl.getModuleSpecifierValue().substring(importDecl.getModuleSpecifierValue().length - 3) === ".ts") {
38
+ path = importDecl.getModuleSpecifierValue();
34
39
  }
35
40
  else {
36
- path = i.getModuleSpecifierValue() + ".ts";
41
+ path = importDecl.getModuleSpecifierValue() + ".ts";
37
42
  }
38
43
  }
39
44
  else {
40
- path = i.getModuleSpecifierSourceFile().getFilePath();
45
+ path = importDecl.getModuleSpecifierSourceFile()!.getFilePath();
41
46
  }
42
47
  return path;
43
48
  }
@@ -84,7 +89,7 @@ export function processFiles(sourceFiles: Array<SourceFile>): void {
84
89
  if (fs.existsSync(file.getFilePath()))
85
90
  currentCC = calculate(file.getFilePath());
86
91
  else
87
- currentCC = 0;
92
+ currentCC = {};
88
93
 
89
94
  processFile(file);
90
95
  });
@@ -95,16 +100,18 @@ export function processFiles(sourceFiles: Array<SourceFile>): void {
95
100
  * @param f A source file
96
101
  */
97
102
  function processFile(f: SourceFile): void {
98
- const isModule = ismodule(f);
103
+ const isModule = isSourceFileAModule(f);
99
104
 
100
105
  if (isModule) {
101
106
  modules.push(f);
102
- exportedMap.push(f.getExportedDeclarations());
103
107
  }
104
108
 
109
+ const exportMap = f.getExportedDeclarations();
110
+ if (exportMap) listOfExportMaps.push(exportMap);
111
+
105
112
  const fmxFile = entityDictionary.createOrGetFamixFile(f, isModule);
106
113
 
107
- logger.debug(`processFile: file: ${f.getBaseName()}, fqn = ${fmxFile.getFullyQualifiedName()}`);
114
+ logger.debug(`processFile: file: ${f.getBaseName()}, fqn = ${fmxFile.fullyQualifiedName}`);
108
115
 
109
116
  processComments(f, fmxFile);
110
117
 
@@ -120,44 +127,59 @@ function processFile(f: SourceFile): void {
120
127
 
121
128
  processFunctions(f, fmxFile);
122
129
 
123
- processNamespaces(f, fmxFile);
130
+ processModules(f, fmxFile);
131
+ }
132
+
133
+ export function isAmbient(node: ModuleDeclaration): boolean {
134
+ // An ambient module has the DeclareKeyword modifier.
135
+ return (node.getModifiers()?.some(modifier => modifier.getKind() === SyntaxKind.DeclareKeyword)) ?? false;
136
+ }
137
+
138
+ export function isNamespace(node: ModuleDeclaration): boolean {
139
+ // Check if the module declaration has a namespace keyword.
140
+ // This approach uses the getChildren() method to inspect the syntax directly.
141
+ return node.getChildrenOfKind(SyntaxKind.NamespaceKeyword).length > 0;
124
142
  }
125
143
 
126
144
  /**
127
- * Builds a Famix model for a namespace
145
+ * Builds a Famix model for a module (also namespace)
128
146
  * @param m A namespace
129
- * @returns A Famix.Namespace representing the namespace
147
+ * @returns A Famix.Module representing the module
130
148
  */
131
- function processNamespace(m: ModuleDeclaration): Famix.Namespace {
132
- const fmxNamespace = entityDictionary.createOrGetFamixNamespace(m);
149
+ function processModule(m: ModuleDeclaration): Famix.Module {
150
+ const fmxModule = entityDictionary.createOrGetFamixModule(m);
133
151
 
134
- logger.debug(`processNamespace: namespace: ${m.getName()}, (${m.getType().getText()}), ${fmxNamespace.getFullyQualifiedName()}`);
152
+ logger.debug(`module: ${m.getName()}, (${m.getType().getText()}), ${fmxModule.fullyQualifiedName}`);
135
153
 
136
- processComments(m, fmxNamespace);
154
+ processComments(m, fmxModule);
137
155
 
138
- processAliases(m, fmxNamespace);
156
+ processAliases(m, fmxModule);
139
157
 
140
- processClasses(m, fmxNamespace);
158
+ processClasses(m, fmxModule);
141
159
 
142
- processInterfaces(m, fmxNamespace);
160
+ processInterfaces(m, fmxModule);
143
161
 
144
- processVariables(m, fmxNamespace);
162
+ processVariables(m, fmxModule);
145
163
 
146
- processEnums(m, fmxNamespace);
164
+ processEnums(m, fmxModule);
147
165
 
148
- processFunctions(m, fmxNamespace);
166
+ processFunctions(m, fmxModule);
149
167
 
150
- processNamespaces(m, fmxNamespace);
168
+ processModules(m, fmxModule);
151
169
 
152
- return fmxNamespace;
170
+ return fmxModule;
153
171
  }
154
172
 
173
+ type ContainerTypes = SourceFile | ModuleDeclaration | FunctionDeclaration | FunctionExpression | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ArrowFunction;
174
+
175
+ type ScopedTypes = Famix.ScriptEntity | Famix.Module | Famix.Function | Famix.Method | Famix.Accessor;
176
+
155
177
  /**
156
178
  * Builds a Famix model for the aliases of a container
157
179
  * @param m A container (a source file, a namespace, a function or a method)
158
180
  * @param fmxScope The Famix model of the container
159
181
  */
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 {
182
+ function processAliases(m: ContainerTypes, fmxScope: ScopedTypes): void {
161
183
  logger.debug(`processAliases: ---------- Finding Aliases:`);
162
184
  m.getTypeAliases().forEach(a => {
163
185
  const fmxAlias = processAlias(a);
@@ -170,20 +192,47 @@ function processAliases(m: SourceFile | ModuleDeclaration | FunctionDeclaration
170
192
  * @param m A container (a source file or a namespace)
171
193
  * @param fmxScope The Famix model of the container
172
194
  */
173
- function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
195
+ function processClasses(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module ): void {
174
196
  logger.debug(`processClasses: ---------- Finding Classes:`);
175
- m.getClasses().forEach(c => {
197
+ const classesInArrowFunctions = getClassesDeclaredInArrowFunctions(m);
198
+ const classes = m.getClasses().concat(classesInArrowFunctions);
199
+ classes.forEach(c => {
176
200
  const fmxClass = processClass(c);
177
201
  fmxScope.addType(fmxClass);
178
202
  });
179
203
  }
180
204
 
205
+ function getArrowFunctionClasses(f: ArrowFunction): ClassDeclaration[] {
206
+ const classes: ClassDeclaration[] = [];
207
+
208
+ function findClasses(node: any) {
209
+ if (node.getKind() === SyntaxKind.ClassDeclaration) {
210
+ classes.push(node as ClassDeclaration);
211
+ }
212
+ node.getChildren().forEach(findClasses);
213
+ }
214
+
215
+ findClasses(f);
216
+ return classes;
217
+ }
218
+
219
+ /**
220
+ * ts-morph doesn't find classes in arrow functions, so we need to find them manually
221
+ * @param s A source file
222
+ * @returns the ClassDeclaration objects found in arrow functions of the source file
223
+ */
224
+ function getClassesDeclaredInArrowFunctions(s: SourceFile | ModuleDeclaration): ClassDeclaration[] {
225
+ const arrowFunctions = s.getDescendantsOfKind(SyntaxKind.ArrowFunction);
226
+ const classesInArrowFunctions = arrowFunctions.map(f => getArrowFunctionClasses(f)).flat();
227
+ return classesInArrowFunctions;
228
+ }
229
+
181
230
  /**
182
231
  * Builds a Famix model for the interfaces of a container
183
232
  * @param m A container (a source file or a namespace)
184
233
  * @param fmxScope The Famix model of the container
185
234
  */
186
- function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
235
+ function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module ): void {
187
236
  logger.debug(`processInterfaces: ---------- Finding Interfaces:`);
188
237
  m.getInterfaces().forEach(i => {
189
238
  const fmxInterface = processInterface(i);
@@ -196,7 +245,7 @@ function processInterfaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.Sc
196
245
  * @param m A container (a source file, a namespace, a function or a method)
197
246
  * @param fmxScope The Famix model of the container
198
247
  */
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 {
248
+ function processVariables(m: ContainerTypes, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Function | Famix.Method | Famix.Accessor): void {
200
249
  logger.debug(`processVariables: ---------- Finding Variables:`);
201
250
  m.getVariableStatements().forEach(v => {
202
251
  const fmxVariables = processVariableStatement(v);
@@ -211,7 +260,7 @@ function processVariables(m: SourceFile | ModuleDeclaration | FunctionDeclaratio
211
260
  * @param m A container (a source file, a namespace, a function or a method)
212
261
  * @param fmxScope The Famix model of the container
213
262
  */
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 {
263
+ function processEnums(m: ContainerTypes, fmxScope: ScopedTypes): void {
215
264
  logger.debug(`processEnums: ---------- Finding Enums:`);
216
265
  m.getEnums().forEach(e => {
217
266
  const fmxEnum = processEnum(e);
@@ -224,24 +273,32 @@ function processEnums(m: SourceFile | ModuleDeclaration | FunctionDeclaration |
224
273
  * @param m A container (a source file, a namespace, a function or a method)
225
274
  * @param fmxScope The Famix model of the container
226
275
  */
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 {
276
+ function processFunctions(m: ContainerTypes, fmxScope: ScopedTypes): void {
228
277
  logger.debug(`Finding Functions:`);
229
278
  m.getFunctions().forEach(f => {
230
279
  const fmxFunction = processFunction(f);
231
280
  fmxScope.addFunction(fmxFunction);
232
281
  });
282
+
283
+ //find arrow functions
284
+ logger.debug(`Finding Functions:`);
285
+ const arrowFunctions = m.getDescendantsOfKind(SyntaxKind.ArrowFunction);
286
+ arrowFunctions.forEach(af => {
287
+ const fmxFunction = processFunction(af);
288
+ fmxScope.addFunction(fmxFunction);
289
+ })
233
290
  }
234
291
 
235
292
  /**
236
- * Builds a Famix model for the namespaces of a container
293
+ * Builds a Famix model for the modules of a container.
237
294
  * @param m A container (a source file or a namespace)
238
295
  * @param fmxScope The Famix model of the container
239
296
  */
240
- function processNamespaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module | Famix.Namespace): void {
241
- logger.debug(`Finding Namespaces:`);
297
+ function processModules(m: SourceFile | ModuleDeclaration, fmxScope: Famix.ScriptEntity | Famix.Module ): void {
298
+ logger.debug(`Finding Modules:`);
242
299
  m.getModules().forEach(md => {
243
- const fmxNsp = processNamespace(md);
244
- fmxScope.addNamespace(fmxNsp);
300
+ const fmxModule = processModule(md);
301
+ fmxScope.addModule(fmxModule);
245
302
  });
246
303
  }
247
304
 
@@ -253,7 +310,7 @@ function processNamespaces(m: SourceFile | ModuleDeclaration, fmxScope: Famix.Sc
253
310
  function processAlias(a: TypeAliasDeclaration): Famix.Alias {
254
311
  const fmxAlias = entityDictionary.createFamixAlias(a);
255
312
 
256
- logger.debug(`Alias: ${a.getName()}, (${a.getType().getText()}), fqn = ${fmxAlias.getFullyQualifiedName()}`);
313
+ logger.debug(`Alias: ${a.getName()}, (${a.getType().getText()}), fqn = ${fmxAlias.fullyQualifiedName}`);
257
314
 
258
315
  processComments(a, fmxAlias);
259
316
 
@@ -263,14 +320,14 @@ function processAlias(a: TypeAliasDeclaration): Famix.Alias {
263
320
  /**
264
321
  * Builds a Famix model for a class
265
322
  * @param c A class
266
- * @returns A Famix.Class or a Famix.ParameterizableClass representing the class
323
+ * @returns A Famix.Class or a Famix.ParametricClass representing the class
267
324
  */
268
- function processClass(c: ClassDeclaration): Famix.Class | Famix.ParameterizableClass {
325
+ function processClass(c: ClassDeclaration): Famix.Class | Famix.ParametricClass {
269
326
  classes.push(c);
270
327
 
271
328
  const fmxClass = entityDictionary.createOrGetFamixClass(c);
272
329
 
273
- logger.debug(`Class: ${c.getName()}, (${c.getType().getText()}), fqn = ${fmxClass.getFullyQualifiedName()}`);
330
+ logger.debug(`Class: ${c.getName()}, (${c.getType().getText()}), fqn = ${fmxClass.fullyQualifiedName}`);
274
331
 
275
332
  processComments(c, fmxClass);
276
333
 
@@ -299,14 +356,14 @@ function processClass(c: ClassDeclaration): Famix.Class | Famix.ParameterizableC
299
356
  /**
300
357
  * Builds a Famix model for an interface
301
358
  * @param i An interface
302
- * @returns A Famix.Interface or a Famix.ParameterizableInterface representing the interface
359
+ * @returns A Famix.Interface or a Famix.ParametricInterface representing the interface
303
360
  */
304
- function processInterface(i: InterfaceDeclaration): Famix.Interface | Famix.ParameterizableInterface {
361
+ function processInterface(i: InterfaceDeclaration): Famix.Interface | Famix.ParametricInterface {
305
362
  interfaces.push(i);
306
363
 
307
364
  const fmxInterface = entityDictionary.createOrGetFamixInterface(i);
308
365
 
309
- logger.debug(`Interface: ${i.getName()}, (${i.getType().getText()}), fqn = ${fmxInterface.getFullyQualifiedName()}`);
366
+ logger.debug(`Interface: ${i.getName()}, (${i.getType().getText()}), fqn = ${fmxInterface.fullyQualifiedName}`);
310
367
 
311
368
  processComments(i, fmxInterface);
312
369
 
@@ -320,9 +377,9 @@ function processInterface(i: InterfaceDeclaration): Famix.Interface | Famix.Para
320
377
  * @param c A structured type (a class or an interface)
321
378
  * @param fmxScope The Famix model of the structured type
322
379
  */
323
- function processStructuredType(c: ClassDeclaration | InterfaceDeclaration, fmxScope: Famix.Class | Famix.ParameterizableClass | Famix.Interface | Famix.ParameterizableInterface): void {
380
+ function processStructuredType(c: ClassDeclaration | InterfaceDeclaration, fmxScope: Famix.Class | Famix.ParametricClass | Famix.Interface | Famix.ParametricInterface): void {
324
381
  logger.debug(`Finding Properties and Methods:`);
325
- if (fmxScope instanceof Famix.ParameterizableClass || fmxScope instanceof Famix.ParameterizableInterface) {
382
+ if (fmxScope instanceof Famix.ParametricClass || fmxScope instanceof Famix.ParametricInterface) {
326
383
  processTypeParameters(c, fmxScope);
327
384
  }
328
385
 
@@ -345,16 +402,17 @@ function processStructuredType(c: ClassDeclaration | InterfaceDeclaration, fmxSc
345
402
  function processProperty(p: PropertyDeclaration | PropertySignature): Famix.Property {
346
403
  const fmxProperty = entityDictionary.createFamixProperty(p);
347
404
 
348
- logger.debug(`property: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxProperty.getFullyQualifiedName()}`);
405
+ logger.debug(`property: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxProperty.fullyQualifiedName}`);
349
406
  logger.debug(` ---> It's a Property${(p instanceof PropertySignature) ? "Signature" : "Declaration"}!`);
350
407
  const ancestor = p.getFirstAncestorOrThrow();
351
408
  logger.debug(` ---> Its first ancestor is a ${ancestor.getKindName()}`);
352
409
 
410
+ // decorators
353
411
  if (!(p instanceof PropertySignature)) {
354
412
  processDecorators(p, fmxProperty);
355
413
  // only add access if the p's first ancestor is not a PropertyDeclaration
356
414
  if (ancestor.getKindName() !== "PropertyDeclaration") {
357
- logger.debug(`adding access: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxProperty.getName()}`);
415
+ logger.debug(`adding access to map: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxProperty.name} id: ${fmxProperty.id}`);
358
416
  accessMap.set(fmxProperty.id, p);
359
417
  }
360
418
  }
@@ -370,9 +428,9 @@ function processProperty(p: PropertyDeclaration | PropertySignature): Famix.Prop
370
428
  * @returns A Famix.Method or a Famix.Accessor representing the method or the accessor
371
429
  */
372
430
  function processMethod(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration): Famix.Method | Famix.Accessor {
373
- const fmxMethod = entityDictionary.createFamixMethod(m, currentCC);
431
+ const fmxMethod = entityDictionary.createOrGetFamixMethod(m, currentCC);
374
432
 
375
- logger.debug(`Method: ${!(m instanceof ConstructorDeclaration) ? m.getName() : "constructor"}, (${m.getType().getText()}), parent: ${(m.getParent() as ClassDeclaration | InterfaceDeclaration).getName()}, fqn = ${fmxMethod.getFullyQualifiedName()}`);
433
+ logger.debug(`Method: ${!(m instanceof ConstructorDeclaration) ? m.getName() : "constructor"}, (${m.getType().getText()}), parent: ${(m.getParent() as ClassDeclaration | InterfaceDeclaration).getName()}, fqn = ${fmxMethod.fullyQualifiedName}`);
376
434
 
377
435
  processComments(m, fmxMethod);
378
436
 
@@ -406,10 +464,16 @@ function processMethod(m: MethodDeclaration | ConstructorDeclaration | MethodSig
406
464
  * @param f A function
407
465
  * @returns A Famix.Function representing the function
408
466
  */
409
- function processFunction(f: FunctionDeclaration | FunctionExpression): Famix.Function {
410
- const fmxFunction = entityDictionary.createFamixFunction(f, currentCC);
467
+ function processFunction(f: FunctionDeclaration | FunctionExpression | ArrowFunction): Famix.Function {
411
468
 
412
- logger.debug(`Function: ${(f.getName()) ? f.getName() : "anonymous"}, (${f.getType().getText()}), fqn = ${fmxFunction.getFullyQualifiedName()}`);
469
+ logger.debug(`Function: ${(f instanceof ArrowFunction ? "anonymous" : f.getName() ? f.getName() : "anonymous")}, (${f.getType().getText()}), fqn = ${getFQN(f)}`);
470
+
471
+ let fmxFunction;
472
+ if( f instanceof ArrowFunction) {
473
+ fmxFunction = entityDictionary.createFamixArrowFunction(f, currentCC);
474
+ } else {
475
+ fmxFunction = entityDictionary.createOrGetFamixFunction(f, currentCC);
476
+ }
413
477
 
414
478
  processComments(f, fmxFunction);
415
479
 
@@ -453,33 +517,108 @@ function processFunctionExpressions(f: FunctionDeclaration | MethodDeclaration |
453
517
  * @param m A method or a function
454
518
  * @param fmxScope The Famix model of the method or the function
455
519
  */
456
- function processParameters(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression, fmxScope: Famix.Method | Famix.Accessor | Famix.Function): void {
520
+ function processParameters(m: MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction, fmxScope: Famix.Method | Famix.Accessor | Famix.Function): void {
457
521
  logger.debug(`Finding Parameters:`);
458
522
  m.getParameters().forEach(param => {
459
523
  const fmxParam = processParameter(param);
460
524
  fmxScope.addParameter(fmxParam);
525
+ // Additional handling for Parameter Properties in constructors
526
+ if (m instanceof ConstructorDeclaration) {
527
+ // Check if the parameter has any visibility modifier
528
+ if (param.hasModifier(SyntaxKind.PrivateKeyword) || param.hasModifier(SyntaxKind.PublicKeyword) || param.hasModifier(SyntaxKind.ProtectedKeyword) || param.hasModifier(SyntaxKind.ReadonlyKeyword)) {
529
+ const classOfConstructor = m.getParent();
530
+ logger.info(`Parameter Property ${param.getName()} in constructor of ${classOfConstructor.getName()}.`);
531
+ // Treat the parameter as a property and add it to the class
532
+ const fmxProperty = processParameterAsProperty(param, classOfConstructor);
533
+ fmxProperty.readOnly = param.hasModifier(SyntaxKind.ReadonlyKeyword);
534
+ }
535
+ }
536
+
461
537
  });
462
538
  }
463
539
 
540
+ // This function should create a Famix.Property model from a ParameterDeclaration
541
+ // You'll need to implement it according to your Famix model structure
542
+ function processParameterAsProperty(param: ParameterDeclaration, classDecl: ClassDeclaration | ClassExpression): Famix.Property {
543
+ // Convert the parameter into a Property
544
+ const propertyRepresentation = convertParameterToPropertyRepresentation(param);
545
+
546
+ // Add the property to the class so we can have a PropertyDeclaration object
547
+ classDecl.addProperty(propertyRepresentation);
548
+
549
+ const property = classDecl.getProperty(propertyRepresentation.name);
550
+ if (!property) {
551
+ throw new Error(`Property ${propertyRepresentation.name} not found in class ${classDecl.getName()}`);
552
+ }
553
+ const fmxProperty = entityDictionary.createFamixProperty(property);
554
+ if (classDecl instanceof ClassDeclaration) {
555
+ const fmxClass = entityDictionary.createOrGetFamixClass(classDecl);
556
+ fmxClass.addProperty(fmxProperty);
557
+ } else {
558
+ throw new Error("Unexpected type ClassExpression.");
559
+ }
560
+
561
+ processComments(property, fmxProperty);
562
+
563
+ // remove the property from the class
564
+ property.remove();
565
+
566
+ return fmxProperty;
567
+
568
+ }
569
+
570
+ function convertParameterToPropertyRepresentation(param: ParameterDeclaration) {
571
+ // Extract name
572
+ const paramName = param.getName();
573
+
574
+ // Extract type
575
+ const paramType = param.getType().getText(param);
576
+
577
+ // Determine visibility
578
+ let scope: Scope;
579
+ if (param.hasModifier(SyntaxKind.PrivateKeyword)) {
580
+ scope = Scope.Private;
581
+ } else if (param.hasModifier(SyntaxKind.ProtectedKeyword)) {
582
+ scope = Scope.Protected;
583
+ } else if (param.hasModifier(SyntaxKind.PublicKeyword)) {
584
+ scope = Scope.Public;
585
+ } else {
586
+ throw new Error(`Parameter property ${paramName} in constructor does not have a visibility modifier.`);
587
+ }
588
+
589
+ // Determine if readonly
590
+ const isReadonly = param.hasModifier(SyntaxKind.ReadonlyKeyword);
591
+
592
+ // Create a representation of the property
593
+ const propertyRepresentation = {
594
+ name: paramName,
595
+ type: paramType,
596
+ scope: scope,
597
+ isReadonly: isReadonly,
598
+ };
599
+
600
+ return propertyRepresentation;
601
+ }
602
+
464
603
  /**
465
604
  * Builds a Famix model for a parameter
466
- * @param p A parameter
605
+ * @param paramDecl A parameter
467
606
  * @returns A Famix.Parameter representing the parameter
468
607
  */
469
- function processParameter(p: ParameterDeclaration): Famix.Parameter {
470
- const fmxParam = entityDictionary.createFamixParameter(p);
608
+ function processParameter(paramDecl: ParameterDeclaration): Famix.Parameter {
609
+ const fmxParam = entityDictionary.createFamixParameter(paramDecl);
471
610
 
472
- logger.debug(`parameter: ${p.getName()}, (${p.getType().getText()}), fqn = ${fmxParam.getFullyQualifiedName()}`);
611
+ logger.debug(`parameter: ${paramDecl.getName()}, (${paramDecl.getType().getText()}), fqn = ${fmxParam.fullyQualifiedName}`);
473
612
 
474
- processComments(p, fmxParam);
613
+ processComments(paramDecl, fmxParam);
475
614
 
476
- processDecorators(p, fmxParam);
615
+ processDecorators(paramDecl, fmxParam);
477
616
 
478
- const parent = p.getParent();
617
+ const parent = paramDecl.getParent();
479
618
 
480
619
  if (!(parent instanceof MethodSignature)) {
481
- logger.debug(`adding access: ${p.getName()}, (${p.getType().getText()}) Famix ${fmxParam.getName()}`);
482
- accessMap.set(fmxParam.id, p);
620
+ logger.debug(`adding access: ${paramDecl.getName()}, (${paramDecl.getType().getText()}) Famix ${fmxParam.name}`);
621
+ accessMap.set(fmxParam.id, paramDecl);
483
622
  }
484
623
 
485
624
  return fmxParam;
@@ -490,11 +629,11 @@ function processParameter(p: ParameterDeclaration): Famix.Parameter {
490
629
  * @param e A class, an interface, a method or a function
491
630
  * @param fmxScope The Famix model of the class, the interface, the method or the function
492
631
  */
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 {
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 {
494
633
  logger.debug(`Finding Type Parameters:`);
495
634
  e.getTypeParameters().forEach(tp => {
496
635
  const fmxParam = processTypeParameter(tp);
497
- fmxScope.addParameterType(fmxParam);
636
+ fmxScope.addGenericParameter(fmxParam);
498
637
  });
499
638
  }
500
639
 
@@ -506,7 +645,7 @@ function processTypeParameters(e: ClassDeclaration | InterfaceDeclaration | Meth
506
645
  function processTypeParameter(tp: TypeParameterDeclaration): Famix.ParameterType {
507
646
  const fmxTypeParameter = entityDictionary.createFamixParameterType(tp);
508
647
 
509
- logger.debug(`type parameter: ${tp.getName()}, (${tp.getType().getText()}), fqn = ${fmxTypeParameter.getFullyQualifiedName()}`);
648
+ logger.debug(`type parameter: ${tp.getName()}, (${tp.getType().getText()}), fqn = ${fmxTypeParameter.fullyQualifiedName}`);
510
649
 
511
650
  processComments(tp, fmxTypeParameter);
512
651
 
@@ -540,11 +679,11 @@ function processVariableStatement(v: VariableStatement): Array<Famix.Variable> {
540
679
  function processVariable(v: VariableDeclaration): Famix.Variable {
541
680
  const fmxVar = entityDictionary.createFamixVariable(v);
542
681
 
543
- logger.debug(`variable: ${v.getName()}, (${v.getType().getText()}), ${v.getInitializer() ? "initializer: " + v.getInitializer().getText() : "initializer: "}, fqn = ${fmxVar.getFullyQualifiedName()}`);
682
+ logger.debug(`variable: ${v.getName()}, (${v.getType().getText()}), ${v.getInitializer() ? "initializer: " + v.getInitializer()!.getText() : "initializer: "}, fqn = ${fmxVar.fullyQualifiedName}`);
544
683
 
545
684
  processComments(v, fmxVar);
546
685
 
547
- logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxVar.getName()}`);
686
+ logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxVar.name}`);
548
687
  accessMap.set(fmxVar.id, v);
549
688
 
550
689
  return fmxVar;
@@ -558,7 +697,7 @@ function processVariable(v: VariableDeclaration): Famix.Variable {
558
697
  function processEnum(e: EnumDeclaration): Famix.Enum {
559
698
  const fmxEnum = entityDictionary.createFamixEnum(e);
560
699
 
561
- logger.debug(`enum: ${e.getName()}, (${e.getType().getText()}), fqn = ${fmxEnum.getFullyQualifiedName()}`);
700
+ logger.debug(`enum: ${e.getName()}, (${e.getType().getText()}), fqn = ${fmxEnum.fullyQualifiedName}`);
562
701
 
563
702
  processComments(e, fmxEnum);
564
703
 
@@ -578,11 +717,11 @@ function processEnum(e: EnumDeclaration): Famix.Enum {
578
717
  function processEnumValue(v: EnumMember): Famix.EnumValue {
579
718
  const fmxEnumValue = entityDictionary.createFamixEnumValue(v);
580
719
 
581
- logger.debug(`enum value: ${v.getName()}, (${v.getType().getText()}), fqn = ${fmxEnumValue.getFullyQualifiedName()}`);
720
+ logger.debug(`enum value: ${v.getName()}, (${v.getType().getText()}), fqn = ${fmxEnumValue.fullyQualifiedName}`);
582
721
 
583
722
  processComments(v, fmxEnumValue);
584
723
 
585
- logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxEnumValue.getName()}`);
724
+ logger.debug(`adding access: ${v.getName()}, (${v.getType().getText()}) Famix ${fmxEnumValue.name}`);
586
725
  accessMap.set(fmxEnumValue.id, v);
587
726
 
588
727
  return fmxEnumValue;
@@ -593,7 +732,7 @@ function processEnumValue(v: EnumMember): Famix.EnumValue {
593
732
  * @param e A class, a method, a parameter or a property
594
733
  * @param fmxScope The Famix model of the class, the method, the parameter or the property
595
734
  */
596
- function processDecorators(e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration, fmxScope: Famix.Class | Famix.ParameterizableClass | Famix.Method | Famix.Accessor | Famix.Parameter | Famix.Property): void {
735
+ function processDecorators(e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration, fmxScope: Famix.Class | Famix.ParametricClass | Famix.Method | Famix.Accessor | Famix.Parameter | Famix.Property): void {
597
736
  logger.debug(`Finding Decorators:`);
598
737
  e.getDecorators().forEach(dec => {
599
738
  const fmxDec = processDecorator(dec, e);
@@ -610,7 +749,7 @@ function processDecorators(e: ClassDeclaration | MethodDeclaration | GetAccessor
610
749
  function processDecorator(d: Decorator, e: ClassDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ParameterDeclaration | PropertyDeclaration): Famix.Decorator {
611
750
  const fmxDec = entityDictionary.createOrGetFamixDecorator(d, e);
612
751
 
613
- logger.debug(`decorator: ${d.getName()}, (${d.getType().getText()}), fqn = ${fmxDec.getFullyQualifiedName()}`);
752
+ logger.debug(`decorator: ${d.getName()}, (${d.getType().getText()}), fqn = ${fmxDec.fullyQualifiedName}`);
614
753
 
615
754
  processComments(d, fmxDec);
616
755
 
@@ -622,7 +761,7 @@ function processDecorator(d: Decorator, e: ClassDeclaration | MethodDeclaration
622
761
  * @param e A ts-morph element
623
762
  * @param fmxScope The Famix model of the named entity
624
763
  */
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 {
764
+ function processComments(e: SourceFile | ModuleDeclaration | ClassDeclaration | InterfaceDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ParameterDeclaration | VariableDeclaration | PropertyDeclaration | PropertySignature | Decorator | EnumDeclaration | EnumMember | TypeParameterDeclaration | VariableStatement | TypeAliasDeclaration | ArrowFunction, fmxScope: Famix.NamedEntity): void {
626
765
  logger.debug(`Process comments:`);
627
766
  e.getLeadingCommentRanges().forEach(c => {
628
767
  const fmxComment = processComment(c, fmxScope);
@@ -654,16 +793,16 @@ function processComment(c: CommentRange, fmxScope: Famix.NamedEntity): Famix.Com
654
793
  * Builds a Famix model for the accesses on the parameters, variables, properties and enum members of the source files
655
794
  * @param accessMap A map of parameters, variables, properties and enum members with their id
656
795
  */
657
- export function processAccesses(accessMap: Map<number, ParameterDeclaration | VariableDeclaration | PropertyDeclaration | EnumMember>): void {
658
- logger.debug(`processAccesses: Creating accesses:`);
796
+ export function processAccesses(accessMap: Map<FamixID, AccessibleTSMorphElement>): void {
797
+ logger.debug(`Creating accesses:`);
659
798
  accessMap.forEach((v, id) => {
660
- logger.debug(`processAccesses: Accesses to ${v.getName()}`);
661
- try {
799
+ logger.debug(`Accesses to ${v.getName()}`);
800
+ // try {
662
801
  const temp_nodes = v.findReferencesAsNodes() as Array<Identifier>;
663
802
  temp_nodes.forEach(node => processNodeForAccesses(node, id));
664
- } catch (error) {
665
- logger.error(`> WARNING: got exception ${error}. Continuing...`);
666
- }
803
+ // } catch (error) {
804
+ // logger.error(`> WARNING: got exception "${error}".\nContinuing...`);
805
+ // }
667
806
  });
668
807
  }
669
808
 
@@ -673,7 +812,7 @@ export function processAccesses(accessMap: Map<number, ParameterDeclaration | Va
673
812
  * @param id An id of a parameter, a variable, a property or an enum member
674
813
  */
675
814
  function processNodeForAccesses(n: Identifier, id: number): void {
676
- try {
815
+ // try {
677
816
  // sometimes node's first ancestor is a PropertyDeclaration, which is not an access
678
817
  // see https://github.com/fuhrmanator/FamixTypeScriptImporter/issues/9
679
818
  // check for a node whose first ancestor is a property declaration and bail?
@@ -684,11 +823,15 @@ function processNodeForAccesses(n: Identifier, id: number): void {
684
823
  }
685
824
  entityDictionary.createFamixAccess(n, id);
686
825
  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
- }
826
+ // } catch (error) {
827
+ // logger.error(`> Got exception "${error}".\nScopeDeclaration invalid for "${n.getSymbol().fullyQualifiedName}".\nContinuing...`);
828
+ // }
690
829
  }
691
830
 
831
+
832
+ // exports has name -> Declaration -- the declaration can be used to find the FamixElement
833
+
834
+ // handle `import path = require("path")` for example
692
835
  export function processImportClausesForImportEqualsDeclarations(sourceFiles: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
693
836
  logger.info(`Creating import clauses from ImportEqualsDeclarations in source files:`);
694
837
  sourceFiles.forEach(sourceFile => {
@@ -697,44 +840,42 @@ export function processImportClausesForImportEqualsDeclarations(sourceFiles: Arr
697
840
  // You've found an ImportEqualsDeclaration
698
841
  logger.info("Declaration Name:", node.getName());
699
842
  logger.info("Module Reference Text:", node.getModuleReference().getText());
843
+ // what's the name of the imported entity?
844
+ // const importedEntity = node.getName();
700
845
  // create a famix import clause
701
846
  const namedImport = node.getNameNode();
702
- entityDictionary.createFamixImportClause({importDeclaration: node,
703
- importer: sourceFile,
847
+ entityDictionary.oldCreateFamixImportClause({importDeclaration: node,
848
+ importerSourceFile: sourceFile,
704
849
  moduleSpecifierFilePath: node.getModuleReference().getText(),
705
850
  importElement: namedImport,
706
851
  isInExports: exports.find(e => e.has(namedImport.getText())) !== undefined,
707
852
  isDefaultExport: false});
853
+ // entityDictionary.createFamixImportClause(importedEntity, importingEntity);
708
854
  }
709
855
  });
710
856
  }
711
857
  );
712
-
713
858
  }
714
859
 
715
860
  /**
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
- */
861
+ * Builds a Famix model for the import clauses of the source files which are modules
862
+ * @param modules An array of modules
863
+ * @param exports An array of maps of exported declarations
864
+ */
720
865
  export function processImportClausesForModules(modules: Array<SourceFile>, exports: Array<ReadonlyMap<string, ExportedDeclarations[]>>): void {
721
866
  logger.info(`Creating import clauses from ${modules.length} modules:`);
722
867
  modules.forEach(module => {
868
+ const modulePath = module.getFilePath() + module.getBaseName();
723
869
  module.getImportDeclarations().forEach(impDecl => {
724
- logger.debug(`Importing ${impDecl.getModuleSpecifierValue()}`);
870
+ logger.info(`Importing ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
725
871
  const path = getModulePath(impDecl);
726
872
 
727
873
  impDecl.getNamedImports().forEach(namedImport => {
728
- logger.debug(`Importing (named) ${namedImport.getName()} from ${impDecl.getModuleSpecifierValue()}`);
874
+ logger.info(`Importing (named) ${namedImport.getName()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
729
875
  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,
876
+ let importFoundInExports = isInExports(exports, importedEntityName);
877
+ entityDictionary.oldCreateFamixImportClause({importDeclaration: impDecl,
878
+ importerSourceFile: module,
738
879
  moduleSpecifierFilePath: path,
739
880
  importElement: namedImport,
740
881
  isInExports: importFoundInExports,
@@ -743,10 +884,10 @@ export function processImportClausesForModules(modules: Array<SourceFile>, expor
743
884
 
744
885
  const defaultImport = impDecl.getDefaultImport();
745
886
  if (defaultImport !== undefined) {
746
- logger.debug(`Importing (default) ${defaultImport.getText()} from ${impDecl.getModuleSpecifierValue()}`);
887
+ logger.info(`Importing (default) ${defaultImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
747
888
  // call with module, impDecl.getModuleSpecifierValue(), path, defaultImport, false, true
748
- entityDictionary.createFamixImportClause({importDeclaration: impDecl,
749
- importer: module,
889
+ entityDictionary.oldCreateFamixImportClause({importDeclaration: impDecl,
890
+ importerSourceFile: module,
750
891
  moduleSpecifierFilePath: path,
751
892
  importElement: defaultImport,
752
893
  isInExports: false,
@@ -755,9 +896,9 @@ export function processImportClausesForModules(modules: Array<SourceFile>, expor
755
896
 
756
897
  const namespaceImport = impDecl.getNamespaceImport();
757
898
  if (namespaceImport !== undefined) {
758
- logger.debug(`Importing (namespace) ${namespaceImport.getText()} from ${impDecl.getModuleSpecifierValue()}`);
759
- entityDictionary.createFamixImportClause({importDeclaration: impDecl,
760
- importer: module,
899
+ logger.info(`Importing (namespace) ${namespaceImport.getText()} from ${impDecl.getModuleSpecifierValue()} in ${modulePath}`);
900
+ entityDictionary.oldCreateFamixImportClause({importDeclaration: impDecl,
901
+ importerSourceFile: module,
761
902
  moduleSpecifierFilePath: path,
762
903
  importElement: namespaceImport,
763
904
  isInExports: false,
@@ -768,11 +909,21 @@ export function processImportClausesForModules(modules: Array<SourceFile>, expor
768
909
  });
769
910
  }
770
911
 
912
+ function isInExports(exports: ReadonlyMap<string, ExportedDeclarations[]>[], importedEntityName: string) {
913
+ let importFoundInExports = false;
914
+ exports.forEach(e => {
915
+ if (e.has(importedEntityName)) {
916
+ importFoundInExports = true;
917
+ }
918
+ });
919
+ return importFoundInExports;
920
+ }
921
+
771
922
  /**
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
- */
923
+ * Builds a Famix model for the inheritances of the classes and interfaces of the source files
924
+ * @param classes An array of classes
925
+ * @param interfaces An array of interfaces
926
+ */
776
927
  export function processInheritances(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[]): void {
777
928
  logger.info(`processInheritances: Creating inheritances:`);
778
929
  classes.forEach(cls => {
@@ -808,15 +959,17 @@ export function processInheritances(classes: ClassDeclaration[], interfaces: Int
808
959
  * Builds a Famix model for the invocations of the methods and functions of the source files
809
960
  * @param methodsAndFunctionsWithId A map of methods and functions with their id
810
961
  */
811
- export function processInvocations(methodsAndFunctionsWithId: Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression>): void {
962
+ export function processInvocations(methodsAndFunctionsWithId: Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction>): void {
812
963
  logger.info(`Creating invocations:`);
813
964
  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...`);
965
+ if (!(m instanceof ArrowFunction)) {
966
+ 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'))}`);
967
+ try {
968
+ const temp_nodes = m.findReferencesAsNodes() as Array<Identifier>;
969
+ temp_nodes.forEach(node => processNodeForInvocations(node, m, id));
970
+ } catch (error) {
971
+ logger.error(`> WARNING: got exception ${error}. Continuing...`);
972
+ }
820
973
  }
821
974
  });
822
975
  }
@@ -833,6 +986,34 @@ function processNodeForInvocations(n: Identifier, m: MethodDeclaration | Constru
833
986
 
834
987
  logger.debug(`node: node, (${n.getType().getText()})`);
835
988
  } catch (error) {
836
- logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${n.getSymbol().getFullyQualifiedName()}. Continuing...`);
989
+ logger.error(`> WARNING: got exception ${error}. ScopeDeclaration invalid for ${n.getSymbol()!.getFullyQualifiedName()}. Continuing...`);
837
990
  }
838
- }
991
+ }
992
+
993
+ /**
994
+ * Builds a Famix model for the inheritances of the classes and interfaces of the source files
995
+ * @param classes An array of classes
996
+ * @param interfaces An array of interfaces
997
+ */
998
+ export function processConcretisations(classes: ClassDeclaration[], interfaces: InterfaceDeclaration[], functions: Map<number, MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | FunctionDeclaration | FunctionExpression | ArrowFunction>): void {
999
+ logger.info(`processConcretisations: Creating concretisations:`);
1000
+ classes.forEach(cls => {
1001
+ logger.debug(`processConcretisations: Checking class concretisation for ${cls.getName()}`);
1002
+ entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(cls);
1003
+ entityDictionary.createFamixConcretisationGenericInstantiation(cls);
1004
+ entityDictionary.createFamixConcretisationInterfaceClass(cls);
1005
+ entityDictionary.createFamixConcretisationTypeInstanciation(cls);
1006
+
1007
+ });
1008
+ interfaces.forEach(inter => {
1009
+ logger.debug(`processConcretisations: Checking interface concretisation for ${inter.getName()}`);
1010
+ entityDictionary.createFamixConcretisationTypeInstanciation(inter);
1011
+ entityDictionary.createFamixConcretisationClassOrInterfaceSpecialisation(inter)
1012
+ });
1013
+ functions.forEach(func => {
1014
+ if(func instanceof FunctionDeclaration || func instanceof MethodDeclaration ){
1015
+ logger.debug(`processConcretisations: Checking Method concretisation`);
1016
+ entityDictionary.createFamixConcretisationFunctionInstantiation(func);
1017
+ }
1018
+ })
1019
+ }