ts2famix 2.1.0-beta.2 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/.eslintrc.json +24 -24
  2. package/LICENSE +24 -24
  3. package/README.md +78 -78
  4. package/dist/analyze.js +3 -3
  5. package/dist/analyze_functions/process_functions.js +92 -62
  6. package/dist/famix_functions/EntityDictionary.js +674 -599
  7. package/dist/famix_functions/helpers_creation.js +18 -12
  8. package/dist/fqn.js +351 -18
  9. package/dist/lib/famix/famix_JSON_exporter.js +1 -1
  10. package/dist/lib/famix/famix_base_element.js +1 -1
  11. package/dist/lib/famix/famix_repository.js +14 -5
  12. package/dist/lib/famix/index.js +1 -1
  13. package/dist/lib/famix/model/famix/access.js +1 -1
  14. package/dist/lib/famix/model/famix/accessor.js +1 -1
  15. package/dist/lib/famix/model/famix/alias.js +1 -1
  16. package/dist/lib/famix/model/famix/arrow_function.js +1 -1
  17. package/dist/lib/famix/model/famix/behavioral_entity.js +1 -1
  18. package/dist/lib/famix/model/famix/class.js +1 -1
  19. package/dist/lib/famix/model/famix/comment.js +1 -1
  20. package/dist/lib/famix/model/famix/concretisation.js +1 -1
  21. package/dist/lib/famix/model/famix/container_entity.js +1 -1
  22. package/dist/lib/famix/model/famix/decorator.js +1 -1
  23. package/dist/lib/famix/model/famix/entity.js +1 -1
  24. package/dist/lib/famix/model/famix/enum.js +1 -1
  25. package/dist/lib/famix/model/famix/enum_value.js +1 -1
  26. package/dist/lib/famix/model/famix/function.js +1 -1
  27. package/dist/lib/famix/model/famix/import_clause.js +1 -1
  28. package/dist/lib/famix/model/famix/index.js +1 -1
  29. package/dist/lib/famix/model/famix/indexed_file_anchor.js +1 -1
  30. package/dist/lib/famix/model/famix/inheritance.js +1 -1
  31. package/dist/lib/famix/model/famix/interface.js +1 -1
  32. package/dist/lib/famix/model/famix/invocation.js +1 -1
  33. package/dist/lib/famix/model/famix/method.js +1 -1
  34. package/dist/lib/famix/model/famix/module.js +2 -2
  35. package/dist/lib/famix/model/famix/named_entity.js +1 -1
  36. package/dist/lib/famix/model/famix/parameter.js +1 -1
  37. package/dist/lib/famix/model/famix/parameter_concretisation.js +1 -1
  38. package/dist/lib/famix/model/famix/parameter_type.js +1 -1
  39. package/dist/lib/famix/model/famix/parametric_arrow_function.js +1 -1
  40. package/dist/lib/famix/model/famix/parametric_class.js +1 -1
  41. package/dist/lib/famix/model/famix/parametric_function.js +1 -1
  42. package/dist/lib/famix/model/famix/parametric_interface.js +1 -1
  43. package/dist/lib/famix/model/famix/parametric_method.js +1 -1
  44. package/dist/lib/famix/model/famix/primitive_type.js +1 -1
  45. package/dist/lib/famix/model/famix/property.js +1 -1
  46. package/dist/lib/famix/model/famix/reference.js +1 -1
  47. package/dist/lib/famix/model/famix/scoping_entity.js +1 -1
  48. package/dist/lib/famix/model/famix/script_entity.js +1 -1
  49. package/dist/lib/famix/model/famix/source_anchor.js +1 -1
  50. package/dist/lib/famix/model/famix/source_language.js +1 -1
  51. package/dist/lib/famix/model/famix/sourced_entity.js +1 -1
  52. package/dist/lib/famix/model/famix/structural_entity.js +1 -1
  53. package/dist/lib/famix/model/famix/type.js +1 -1
  54. package/dist/lib/famix/model/famix/variable.js +1 -1
  55. package/dist/lib/ts-complex/cyclomatic-service.js +1 -1
  56. package/dist/refactorer/refactor-getter-setter.js +1 -1
  57. package/dist/ts2famix-cli-wrapper.js +1 -1
  58. package/dist/ts2famix-cli.js +3 -1
  59. package/doc-uml/famix-typescript-model.puml +619 -607
  60. package/doc-uml/famix-typescript-model.svg +1 -1
  61. package/eslint.config.mjs +28 -28
  62. package/jest.config.json +1 -1
  63. package/package.json +70 -70
  64. package/src/analyze.ts +120 -120
  65. package/src/analyze_functions/process_functions.ts +1069 -1040
  66. package/src/famix_functions/EntityDictionary.ts +2061 -2016
  67. package/src/famix_functions/helpers_creation.ts +143 -135
  68. package/src/fqn.ts +416 -50
  69. package/src/generate_uml.sh +20 -20
  70. package/src/lib/famix/License.md +22 -22
  71. package/src/lib/famix/famix_JSON_exporter.ts +56 -56
  72. package/src/lib/famix/famix_base_element.ts +22 -22
  73. package/src/lib/famix/famix_repository.ts +288 -278
  74. package/src/lib/famix/index.ts +8 -8
  75. package/src/lib/famix/model/famix/access.ts +50 -50
  76. package/src/lib/famix/model/famix/accessor.ts +15 -15
  77. package/src/lib/famix/model/famix/alias.ts +39 -39
  78. package/src/lib/famix/model/famix/arrow_function.ts +15 -15
  79. package/src/lib/famix/model/famix/behavioral_entity.ts +97 -97
  80. package/src/lib/famix/model/famix/class.ts +85 -85
  81. package/src/lib/famix/model/famix/comment.ts +47 -47
  82. package/src/lib/famix/model/famix/concretisation.ts +40 -40
  83. package/src/lib/famix/model/famix/container_entity.ts +160 -160
  84. package/src/lib/famix/model/famix/decorator.ts +37 -37
  85. package/src/lib/famix/model/famix/entity.ts +15 -15
  86. package/src/lib/famix/model/famix/enum.ts +30 -30
  87. package/src/lib/famix/model/famix/enum_value.ts +28 -28
  88. package/src/lib/famix/model/famix/function.ts +15 -15
  89. package/src/lib/famix/model/famix/import_clause.ts +51 -51
  90. package/src/lib/famix/model/famix/index.ts +41 -41
  91. package/src/lib/famix/model/famix/indexed_file_anchor.ts +46 -46
  92. package/src/lib/famix/model/famix/inheritance.ts +40 -40
  93. package/src/lib/famix/model/famix/interface.ts +75 -75
  94. package/src/lib/famix/model/famix/invocation.ts +65 -65
  95. package/src/lib/famix/model/famix/method.ts +89 -89
  96. package/src/lib/famix/model/famix/module.ts +71 -71
  97. package/src/lib/famix/model/famix/named_entity.ts +95 -95
  98. package/src/lib/famix/model/famix/parameter.ts +28 -28
  99. package/src/lib/famix/model/famix/parameter_concretisation.ts +51 -51
  100. package/src/lib/famix/model/famix/parameter_type.ts +58 -58
  101. package/src/lib/famix/model/famix/parametric_arrow_function.ts +32 -32
  102. package/src/lib/famix/model/famix/parametric_class.ts +49 -49
  103. package/src/lib/famix/model/famix/parametric_function.ts +32 -32
  104. package/src/lib/famix/model/famix/parametric_interface.ts +49 -49
  105. package/src/lib/famix/model/famix/parametric_method.ts +32 -32
  106. package/src/lib/famix/model/famix/primitive_type.ts +15 -15
  107. package/src/lib/famix/model/famix/property.ts +94 -94
  108. package/src/lib/famix/model/famix/reference.ts +40 -40
  109. package/src/lib/famix/model/famix/scoping_entity.ts +35 -35
  110. package/src/lib/famix/model/famix/script_entity.ts +34 -34
  111. package/src/lib/famix/model/famix/source_anchor.ts +30 -30
  112. package/src/lib/famix/model/famix/source_language.ts +35 -35
  113. package/src/lib/famix/model/famix/sourced_entity.ts +70 -70
  114. package/src/lib/famix/model/famix/structural_entity.ts +43 -43
  115. package/src/lib/famix/model/famix/type.ts +87 -87
  116. package/src/lib/famix/model/famix/variable.ts +27 -27
  117. package/src/lib/famix/package.json +28 -28
  118. package/src/lib/ts-complex/cyclomatic-service.ts +83 -83
  119. package/src/refactorer/refactor-getter-setter.ts +140 -140
  120. package/src/ts2famix-cli-wrapper.ts +21 -21
  121. package/src/ts2famix-cli.ts +62 -60
  122. package/tsconfig.check-tests.json +14 -14
  123. package/tsconfig.json +73 -72
  124. package/.vscode/settings.json +0 -4
  125. package/TODO +0 -1
  126. package/arwea-fix.json +0 -1
  127. package/bogus.ts +0 -3
  128. package/class-diagram.puml +0 -792
  129. package/debug.txt +0 -13332
  130. package/debuglog.txt +0 -12073
  131. package/dist/famix2puml.js +0 -126
  132. package/dist/getClasses-arrow-body.js +0 -43
  133. package/dist/lib/famix/src/famix_JSON_exporter.js +0 -55
  134. package/dist/lib/famix/src/famix_base_element.js +0 -18
  135. package/dist/lib/famix/src/famix_repository.js +0 -224
  136. package/dist/lib/famix/src/index.js +0 -31
  137. package/dist/lib/famix/src/model/famix/access.js +0 -40
  138. package/dist/lib/famix/src/model/famix/accessor.js +0 -17
  139. package/dist/lib/famix/src/model/famix/alias.js +0 -33
  140. package/dist/lib/famix/src/model/famix/arrowFunction.js +0 -17
  141. package/dist/lib/famix/src/model/famix/arrow_function.js +0 -17
  142. package/dist/lib/famix/src/model/famix/behavioral_entity.js +0 -79
  143. package/dist/lib/famix/src/model/famix/class.js +0 -71
  144. package/dist/lib/famix/src/model/famix/comment.js +0 -39
  145. package/dist/lib/famix/src/model/famix/concretisation.js +0 -31
  146. package/dist/lib/famix/src/model/famix/container_entity.js +0 -126
  147. package/dist/lib/famix/src/model/famix/decorator.js +0 -32
  148. package/dist/lib/famix/src/model/famix/entity.js +0 -17
  149. package/dist/lib/famix/src/model/famix/enum.js +0 -31
  150. package/dist/lib/famix/src/model/famix/enum_value.js +0 -25
  151. package/dist/lib/famix/src/model/famix/function.js +0 -17
  152. package/dist/lib/famix/src/model/famix/implicit_variable.js +0 -17
  153. package/dist/lib/famix/src/model/famix/import_clause.js +0 -41
  154. package/dist/lib/famix/src/model/famix/index.js +0 -86
  155. package/dist/lib/famix/src/model/famix/indexed_file_anchor.js +0 -38
  156. package/dist/lib/famix/src/model/famix/inheritance.js +0 -33
  157. package/dist/lib/famix/src/model/famix/interface.js +0 -64
  158. package/dist/lib/famix/src/model/famix/invocation.js +0 -54
  159. package/dist/lib/famix/src/model/famix/method.js +0 -67
  160. package/dist/lib/famix/src/model/famix/module.js +0 -60
  161. package/dist/lib/famix/src/model/famix/named_entity.js +0 -78
  162. package/dist/lib/famix/src/model/famix/parameter.js +0 -25
  163. package/dist/lib/famix/src/model/famix/parameterConcretisation.js +0 -44
  164. package/dist/lib/famix/src/model/famix/parameter_concretisation.js +0 -44
  165. package/dist/lib/famix/src/model/famix/parameter_type.js +0 -45
  166. package/dist/lib/famix/src/model/famix/parametricArrowFunction.js +0 -29
  167. package/dist/lib/famix/src/model/famix/parametric_arrow_function.js +0 -31
  168. package/dist/lib/famix/src/model/famix/parametric_class.js +0 -44
  169. package/dist/lib/famix/src/model/famix/parametric_function.js +0 -31
  170. package/dist/lib/famix/src/model/famix/parametric_interface.js +0 -44
  171. package/dist/lib/famix/src/model/famix/parametric_method.js +0 -31
  172. package/dist/lib/famix/src/model/famix/primitive_type.js +0 -17
  173. package/dist/lib/famix/src/model/famix/property.js +0 -73
  174. package/dist/lib/famix/src/model/famix/reference.js +0 -33
  175. package/dist/lib/famix/src/model/famix/scoping_entity.js +0 -36
  176. package/dist/lib/famix/src/model/famix/script_entity.js +0 -29
  177. package/dist/lib/famix/src/model/famix/source_anchor.js +0 -27
  178. package/dist/lib/famix/src/model/famix/source_language.js +0 -35
  179. package/dist/lib/famix/src/model/famix/sourced_entity.js +0 -60
  180. package/dist/lib/famix/src/model/famix/structural_entity.js +0 -39
  181. package/dist/lib/famix/src/model/famix/text_anchor.js +0 -38
  182. package/dist/lib/famix/src/model/famix/type.js +0 -73
  183. package/dist/lib/famix/src/model/famix/variable.js +0 -24
  184. package/fqn-model.json +0 -1
  185. package/iterateGenericTypes.ts +0 -69
  186. package/out/class-diagram/class-diagram.svg +0 -1
  187. package/sample.json +0 -1
  188. package/sample.ts +0 -1
  189. package/stats.txt +0 -3091
  190. package/tabby-debug-output.txt +0 -19433
  191. package/ts2famix.log +0 -22656
  192. package/validate-references.js +0 -103
@@ -1,83 +1,83 @@
1
- /*
2
- Portions of this file:
3
-
4
- MIT License
5
-
6
- Copyright (c) 2018 Anand Undavia
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
-
12
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
- */
14
-
15
- import { forEachChild, isIdentifier, SyntaxKind, createSourceFile, ScriptTarget, Node, CaseClause, BinaryExpression, FunctionLikeDeclaration } from 'typescript';
16
- import { isFunctionWithBody } from 'tsutils';
17
- import { existsSync, PathLike, readFileSync } from 'fs';
18
-
19
- const getNodeName = (node: FunctionLikeDeclaration) => {
20
- const { name, pos, end } = node;
21
- const key = name !== undefined && isIdentifier(name) ? name.text : JSON.stringify({ pos, end });
22
- return key;
23
- };
24
-
25
- const increasesComplexity = (node: Node) => {
26
- /* eslint-disable indent */
27
- switch (node.kind) {
28
- case SyntaxKind.CaseClause:
29
- return (node as CaseClause).statements.length > 0;
30
- case SyntaxKind.CatchClause:
31
- case SyntaxKind.ConditionalExpression:
32
- case SyntaxKind.DoStatement:
33
- case SyntaxKind.ForStatement:
34
- case SyntaxKind.ForInStatement:
35
- case SyntaxKind.ForOfStatement:
36
- case SyntaxKind.IfStatement:
37
- case SyntaxKind.WhileStatement:
38
- return true;
39
-
40
- case SyntaxKind.BinaryExpression:
41
- switch ((node as BinaryExpression).operatorToken.kind) {
42
- case SyntaxKind.BarBarToken:
43
- case SyntaxKind.AmpersandAmpersandToken:
44
- return true;
45
- default:
46
- return false;
47
- }
48
-
49
- default:
50
- return false;
51
- }
52
- /* eslint-enable indent */
53
- };
54
-
55
- const calculateFromSource = (ctx: Node) => {
56
- let complexity = 0;
57
- const output: { [key: string]: number } = {};
58
- forEachChild(ctx, function cb(node) {
59
- if (isFunctionWithBody(node)) {
60
- const old = complexity;
61
- complexity = 1;
62
- forEachChild(node, cb);
63
- const name = getNodeName(node)?.toString();
64
- output[name] = complexity;
65
- complexity = old;
66
- } else {
67
- if (increasesComplexity(node)) {
68
- complexity += 1;
69
- }
70
- forEachChild(node, cb);
71
- }
72
- });
73
- return output;
74
- };
75
-
76
- export const calculate = (filePath: PathLike) => {
77
- if (!existsSync(filePath)) {
78
- throw new Error(`File "${filePath}" does not exists`);
79
- }
80
- const sourceText = readFileSync(filePath).toString();
81
- const source = createSourceFile(filePath.toString(), sourceText, ScriptTarget.ES2015);
82
- return calculateFromSource(source);
83
- };
1
+ /*
2
+ Portions of this file:
3
+
4
+ MIT License
5
+
6
+ Copyright (c) 2018 Anand Undavia
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ */
14
+
15
+ import { forEachChild, isIdentifier, SyntaxKind, createSourceFile, ScriptTarget, Node, CaseClause, BinaryExpression, FunctionLikeDeclaration } from 'typescript';
16
+ import { isFunctionWithBody } from 'tsutils';
17
+ import { existsSync, PathLike, readFileSync } from 'fs';
18
+
19
+ const getNodeName = (node: FunctionLikeDeclaration) => {
20
+ const { name, pos, end } = node;
21
+ const key = name !== undefined && isIdentifier(name) ? name.text : JSON.stringify({ pos, end });
22
+ return key;
23
+ };
24
+
25
+ const increasesComplexity = (node: Node) => {
26
+ /* eslint-disable indent */
27
+ switch (node.kind) {
28
+ case SyntaxKind.CaseClause:
29
+ return (node as CaseClause).statements.length > 0;
30
+ case SyntaxKind.CatchClause:
31
+ case SyntaxKind.ConditionalExpression:
32
+ case SyntaxKind.DoStatement:
33
+ case SyntaxKind.ForStatement:
34
+ case SyntaxKind.ForInStatement:
35
+ case SyntaxKind.ForOfStatement:
36
+ case SyntaxKind.IfStatement:
37
+ case SyntaxKind.WhileStatement:
38
+ return true;
39
+
40
+ case SyntaxKind.BinaryExpression:
41
+ switch ((node as BinaryExpression).operatorToken.kind) {
42
+ case SyntaxKind.BarBarToken:
43
+ case SyntaxKind.AmpersandAmpersandToken:
44
+ return true;
45
+ default:
46
+ return false;
47
+ }
48
+
49
+ default:
50
+ return false;
51
+ }
52
+ /* eslint-enable indent */
53
+ };
54
+
55
+ const calculateFromSource = (ctx: Node) => {
56
+ let complexity = 0;
57
+ const output: { [key: string]: number } = {};
58
+ forEachChild(ctx, function cb(node) {
59
+ if (isFunctionWithBody(node)) {
60
+ const old = complexity;
61
+ complexity = 1;
62
+ forEachChild(node, cb);
63
+ const name = getNodeName(node)?.toString();
64
+ output[name] = complexity;
65
+ complexity = old;
66
+ } else {
67
+ if (increasesComplexity(node)) {
68
+ complexity += 1;
69
+ }
70
+ forEachChild(node, cb);
71
+ }
72
+ });
73
+ return output;
74
+ };
75
+
76
+ export const calculate = (filePath: PathLike) => {
77
+ if (!existsSync(filePath)) {
78
+ throw new Error(`File "${filePath}" does not exists`);
79
+ }
80
+ const sourceText = readFileSync(filePath).toString();
81
+ const source = createSourceFile(filePath.toString(), sourceText, ScriptTarget.ES2015);
82
+ return calculateFromSource(source);
83
+ };
@@ -1,140 +1,140 @@
1
- import { ClassDeclaration, Project, SourceFile, SyntaxKind } from "ts-morph";
2
- import * as path from "path";
3
-
4
- const project = new Project();
5
- project.addSourceFilesAtPaths("src/lib/famix/model/famix/famix_base_element.ts");
6
- project.getSourceFiles().forEach(sourceFile => { console.log(sourceFile.getFilePath()); });
7
-
8
- project.getSourceFiles().forEach(sourceFile => {
9
- const typeMap = createTypeMap(sourceFile);
10
-
11
- const classes = sourceFile.getClasses();
12
- classes.forEach(cls => {
13
- const properties = cls.getProperties();
14
- cls.getMethods().forEach(method => {
15
- const methodName = method.getName();
16
- let propName: string;
17
-
18
- if (isEligibleGetter(methodName)) {
19
- propName = methodName.charAt(3).toLowerCase() + methodName.slice(4);
20
- renamePropertyIfExists(cls, propName, properties);
21
- refactorToGetter(cls, method, propName, typeMap);
22
- replaceMethodCalls(cls, `get${capitalize(propName)}`, propName);
23
- } else if (isEligibleSetter(methodName)) {
24
- propName = methodName.charAt(3).toLowerCase() + methodName.slice(4);
25
- renamePropertyIfExists(cls, propName, properties);
26
- refactorToSetter(cls, method, propName, typeMap);
27
- replaceMethodCalls(cls, `set${capitalize(propName)}`, propName);
28
- }
29
- });
30
- });
31
- });
32
-
33
- project.save().then(() => {
34
- console.log("Refactoring complete!");
35
- });
36
-
37
- function isEligibleGetter(methodName: string): boolean {
38
- return methodName.startsWith("get") && /^[A-Z][a-zA-Z0-9]*$/.test(methodName.slice(3)) && !methodName.includes("JSON");
39
- }
40
-
41
- function isEligibleSetter(methodName: string): boolean {
42
- return methodName.startsWith("set") && /^[A-Z][a-zA-Z0-9]*$/.test(methodName.slice(3));
43
- }
44
-
45
- function renamePropertyIfExists(cls: any, propName: string, properties: any[]) {
46
- const existingProperty = properties.find(prop => prop.getName() === propName);
47
- if (existingProperty) {
48
- existingProperty.rename(`_${propName}`);
49
- }
50
- }
51
-
52
- function createTypeMap(sourceFile: SourceFile): Map<string, string> {
53
- const typeMap = new Map<string, string>();
54
- const importDeclarations = sourceFile.getImportDeclarations();
55
-
56
- importDeclarations.forEach(importDecl => {
57
- const moduleSpecifier = importDecl.getModuleSpecifier().getText().replace(/['"]/g, '');
58
- const absolutePath = path.resolve(sourceFile.getDirectory().getPath(), moduleSpecifier);
59
- const normalizedPath = normalizePath(absolutePath);
60
- const namedImports = importDecl.getNamedImports();
61
- const defaultImport = importDecl.getDefaultImport();
62
-
63
- namedImports.forEach(namedImport => {
64
- console.log(`Named import: ${namedImport.getName()}, path: ${normalizedPath}`);
65
- typeMap.set(namedImport.getName(), normalizedPath);
66
- });
67
-
68
- if (defaultImport) {
69
- typeMap.set(defaultImport.getText(), normalizedPath);
70
- }
71
- });
72
-
73
- return typeMap;
74
- }
75
-
76
- function refactorToGetter(cls: any, method: any, propName: string, typeMap: Map<string, string>) {
77
- const getterName = propName;
78
- const renamedProp = `_${propName}`;
79
- const returnType = method.getReturnType().getText();
80
- const simplifiedType = replaceLongTypePaths(returnType, typeMap);
81
-
82
- const getterBody = method.getBodyText().replace(new RegExp(`this\\.${propName}`, 'g'), `this.${renamedProp}`);
83
-
84
- cls.addGetAccessor({
85
- name: getterName,
86
- statements: getterBody,
87
- // returnType: simplifiedType, // don't need a return type for getter
88
- });
89
-
90
- method.remove();
91
- }
92
-
93
- function refactorToSetter(cls: any, method: any, propName: string, typeMap: Map<string, string>) {
94
- const setterName = propName;
95
- const renamedProp = `_${propName}`;
96
-
97
- const parameter = method.getParameters()[0];
98
- const paramName = parameter.getName();
99
- const paramType = replaceLongTypePaths(parameter.getType().getText(), typeMap);
100
-
101
- const setterBody = method.getBodyText().replace(new RegExp(`this\\.${propName}`, 'g'), `this.${renamedProp}`);
102
-
103
- cls.addSetAccessor({
104
- name: setterName,
105
- statements: setterBody,
106
- parameters: [{ name: paramName, type: paramType }],
107
- });
108
-
109
- method.remove();
110
- }
111
-
112
- function replaceLongTypePaths(type: string, typeMap: Map<string, string>): string {
113
- for (const [importName, importPath] of typeMap.entries()) {
114
- const longPath = `import("${importPath}")${importName}`;
115
- const regex = new RegExp(`import\\(["']${normalizePath(importPath)}["']\\)\\.${importName}`, 'g');
116
- if (regex.test(type)) {
117
- return importName;
118
- }
119
- }
120
- return type;
121
- }
122
-
123
- function normalizePath(filePath: string): string {
124
- return filePath.replace(/\\/g, '/');
125
- }
126
-
127
- function replaceMethodCalls(cls: ClassDeclaration, methodName: string, propName: string) {
128
- cls.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(callExpr => {
129
- const expr = callExpr.getExpression();
130
- if (expr.getText() === `this.${methodName}`) {
131
- callExpr.replaceWithText(`this.${propName}`);
132
- } else if (expr.getText() === `this.${methodName}` && callExpr.getArguments().length > 0) {
133
- callExpr.replaceWithText(`this.${propName} = ${callExpr.getArguments()[0].getText()}`);
134
- }
135
- });
136
- }
137
-
138
- function capitalize(str: string): string {
139
- return str.charAt(0).toUpperCase() + str.slice(1);
140
- }
1
+ import { ClassDeclaration, Project, SourceFile, SyntaxKind } from "ts-morph";
2
+ import * as path from "path";
3
+
4
+ const project = new Project();
5
+ project.addSourceFilesAtPaths("src/lib/famix/model/famix/famix_base_element.ts");
6
+ project.getSourceFiles().forEach(sourceFile => { console.log(sourceFile.getFilePath()); });
7
+
8
+ project.getSourceFiles().forEach(sourceFile => {
9
+ const typeMap = createTypeMap(sourceFile);
10
+
11
+ const classes = sourceFile.getClasses();
12
+ classes.forEach(cls => {
13
+ const properties = cls.getProperties();
14
+ cls.getMethods().forEach(method => {
15
+ const methodName = method.getName();
16
+ let propName: string;
17
+
18
+ if (isEligibleGetter(methodName)) {
19
+ propName = methodName.charAt(3).toLowerCase() + methodName.slice(4);
20
+ renamePropertyIfExists(cls, propName, properties);
21
+ refactorToGetter(cls, method, propName, typeMap);
22
+ replaceMethodCalls(cls, `get${capitalize(propName)}`, propName);
23
+ } else if (isEligibleSetter(methodName)) {
24
+ propName = methodName.charAt(3).toLowerCase() + methodName.slice(4);
25
+ renamePropertyIfExists(cls, propName, properties);
26
+ refactorToSetter(cls, method, propName, typeMap);
27
+ replaceMethodCalls(cls, `set${capitalize(propName)}`, propName);
28
+ }
29
+ });
30
+ });
31
+ });
32
+
33
+ project.save().then(() => {
34
+ console.log("Refactoring complete!");
35
+ });
36
+
37
+ function isEligibleGetter(methodName: string): boolean {
38
+ return methodName.startsWith("get") && /^[A-Z][a-zA-Z0-9]*$/.test(methodName.slice(3)) && !methodName.includes("JSON");
39
+ }
40
+
41
+ function isEligibleSetter(methodName: string): boolean {
42
+ return methodName.startsWith("set") && /^[A-Z][a-zA-Z0-9]*$/.test(methodName.slice(3));
43
+ }
44
+
45
+ function renamePropertyIfExists(cls: any, propName: string, properties: any[]) {
46
+ const existingProperty = properties.find(prop => prop.getName() === propName);
47
+ if (existingProperty) {
48
+ existingProperty.rename(`_${propName}`);
49
+ }
50
+ }
51
+
52
+ function createTypeMap(sourceFile: SourceFile): Map<string, string> {
53
+ const typeMap = new Map<string, string>();
54
+ const importDeclarations = sourceFile.getImportDeclarations();
55
+
56
+ importDeclarations.forEach(importDecl => {
57
+ const moduleSpecifier = importDecl.getModuleSpecifier().getText().replace(/['"]/g, '');
58
+ const absolutePath = path.resolve(sourceFile.getDirectory().getPath(), moduleSpecifier);
59
+ const normalizedPath = normalizePath(absolutePath);
60
+ const namedImports = importDecl.getNamedImports();
61
+ const defaultImport = importDecl.getDefaultImport();
62
+
63
+ namedImports.forEach(namedImport => {
64
+ console.log(`Named import: ${namedImport.getName()}, path: ${normalizedPath}`);
65
+ typeMap.set(namedImport.getName(), normalizedPath);
66
+ });
67
+
68
+ if (defaultImport) {
69
+ typeMap.set(defaultImport.getText(), normalizedPath);
70
+ }
71
+ });
72
+
73
+ return typeMap;
74
+ }
75
+
76
+ function refactorToGetter(cls: any, method: any, propName: string, typeMap: Map<string, string>) {
77
+ const getterName = propName;
78
+ const renamedProp = `_${propName}`;
79
+ const returnType = method.getReturnType().getText();
80
+ const simplifiedType = replaceLongTypePaths(returnType, typeMap);
81
+
82
+ const getterBody = method.getBodyText().replace(new RegExp(`this\\.${propName}`, 'g'), `this.${renamedProp}`);
83
+
84
+ cls.addGetAccessor({
85
+ name: getterName,
86
+ statements: getterBody,
87
+ // returnType: simplifiedType, // don't need a return type for getter
88
+ });
89
+
90
+ method.remove();
91
+ }
92
+
93
+ function refactorToSetter(cls: any, method: any, propName: string, typeMap: Map<string, string>) {
94
+ const setterName = propName;
95
+ const renamedProp = `_${propName}`;
96
+
97
+ const parameter = method.getParameters()[0];
98
+ const paramName = parameter.getName();
99
+ const paramType = replaceLongTypePaths(parameter.getType().getText(), typeMap);
100
+
101
+ const setterBody = method.getBodyText().replace(new RegExp(`this\\.${propName}`, 'g'), `this.${renamedProp}`);
102
+
103
+ cls.addSetAccessor({
104
+ name: setterName,
105
+ statements: setterBody,
106
+ parameters: [{ name: paramName, type: paramType }],
107
+ });
108
+
109
+ method.remove();
110
+ }
111
+
112
+ function replaceLongTypePaths(type: string, typeMap: Map<string, string>): string {
113
+ for (const [importName, importPath] of typeMap.entries()) {
114
+ const longPath = `import("${importPath}")${importName}`;
115
+ const regex = new RegExp(`import\\(["']${normalizePath(importPath)}["']\\)\\.${importName}`, 'g');
116
+ if (regex.test(type)) {
117
+ return importName;
118
+ }
119
+ }
120
+ return type;
121
+ }
122
+
123
+ function normalizePath(filePath: string): string {
124
+ return filePath.replace(/\\/g, '/');
125
+ }
126
+
127
+ function replaceMethodCalls(cls: ClassDeclaration, methodName: string, propName: string) {
128
+ cls.getDescendantsOfKind(SyntaxKind.CallExpression).forEach(callExpr => {
129
+ const expr = callExpr.getExpression();
130
+ if (expr.getText() === `this.${methodName}`) {
131
+ callExpr.replaceWithText(`this.${propName}`);
132
+ } else if (expr.getText() === `this.${methodName}` && callExpr.getArguments().length > 0) {
133
+ callExpr.replaceWithText(`this.${propName} = ${callExpr.getArguments()[0].getText()}`);
134
+ }
135
+ });
136
+ }
137
+
138
+ function capitalize(str: string): string {
139
+ return str.charAt(0).toUpperCase() + str.slice(1);
140
+ }
@@ -1,21 +1,21 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawn } from 'child_process';
4
- import * as path from 'path';
5
-
6
- // Resolve the path to ts2famix-cli.js relative to the wrapper script
7
- const cliPath = path.resolve(__dirname, 'ts2famix-cli.js');
8
-
9
- // Allow tslog to display the proper TypeScript files and line numbers
10
- const args = [
11
- '--enable-source-maps',
12
- '--experimental-specifier-resolution=node',
13
- cliPath,
14
- ...process.argv.slice(2)
15
- ];
16
-
17
- const child = spawn('node', args, { stdio: 'inherit' });
18
-
19
- child.on('close', (code) => {
20
- process.exit(code);
21
- });
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process';
4
+ import * as path from 'path';
5
+
6
+ // Resolve the path to ts2famix-cli.js relative to the wrapper script
7
+ const cliPath = path.resolve(__dirname, 'ts2famix-cli.js');
8
+
9
+ // Allow tslog to display the proper TypeScript files and line numbers
10
+ const args = [
11
+ '--enable-source-maps',
12
+ '--experimental-specifier-resolution=node',
13
+ cliPath,
14
+ ...process.argv.slice(2)
15
+ ];
16
+
17
+ const child = spawn('node', args, { stdio: 'inherit' });
18
+
19
+ child.on('close', (code) => {
20
+ process.exit(code);
21
+ });
@@ -1,60 +1,62 @@
1
- #!/usr/bin/env node
2
- import * as fs from "fs";
3
- import yargs from "yargs";
4
- import { Importer } from './analyze';
5
- import { FamixRepository } from "./lib/famix/famix_repository";
6
- import { Project } from "ts-morph";
7
- import { config } from "./analyze";
8
-
9
- const argv = yargs
10
- .example(`ts2famix -i "path/to/project/**/*.ts" -o JSONModels/projectName.json`, 'Creates a JSON-format Famix model of typescript files.')
11
- .example(`ts2famix -i path/to/tsconfig.json -o JSONModels/projectName.json`, 'Creates a JSON-format model of a typescript project.')
12
- .alias('i', 'input')
13
- .nargs('i', 1)
14
- .alias('o', 'output')
15
- .nargs('o', 1)
16
- .alias('l', 'loglevel')
17
- .nargs('l', 1)
18
- .default('l', 3)
19
- .describe('l', 'Set minimum logging level 0: silly, 1: trace, 2: debug, 3: info, 4: warn, 5: error, 6: fatal')
20
- .boolean('graphemes')
21
- .default('graphemes', false)
22
- .describe('graphemes', 'Process graphemes (outside of the BMP) to avoid source anchor offset errors (due to performance issues, this is disabled by default)')
23
- .demandOption('input')
24
- .demandOption('output')
25
- .parseSync();
26
-
27
- import { logger } from './analyze';
28
- logger.settings.minLevel = Number(argv.loglevel) as number;
29
- config.expectGraphemes = argv.graphemes as boolean;
30
-
31
- const importer = new Importer();
32
- let famixRep: FamixRepository;
33
-
34
- if ((argv.input as string).endsWith('tsconfig.json')) {
35
- const tsConfigFilePath = argv.input as string;
36
- // get the baseUrl from the tsconfig file
37
- const baseUrl = tsConfigFilePath.substring(0, tsConfigFilePath.lastIndexOf('/'));
38
- logger.info(`baseUrl: ${baseUrl}`);
39
- const project = new Project({
40
- tsConfigFilePath,
41
- compilerOptions: {
42
- baseUrl: baseUrl,
43
- }
44
- });
45
- famixRep = importer.famixRepFromProject(project);
46
-
47
- } else {
48
- const paths = new Array<string>();
49
- paths.push(argv.input as string);
50
- famixRep = importer.famixRepFromPaths(paths);
51
- }
52
-
53
- const jsonOutput = famixRep.export({format: "json"});
54
- const jsonFilePath = argv.output as string;
55
-
56
- fs.writeFile(jsonFilePath, jsonOutput, (err) => {
57
- if (err) { throw err; }
58
- });
59
-
60
- logger.info(`Created: ${jsonFilePath}`);
1
+ #!/usr/bin/env node
2
+ import * as fs from "fs";
3
+ import yargs from "yargs";
4
+ import { Importer } from './analyze';
5
+ import { FamixRepository } from "./lib/famix/famix_repository";
6
+ import { Project } from "ts-morph";
7
+ import { config } from "./analyze";
8
+
9
+ const argv = yargs
10
+ .example(`ts2famix -i "path/to/project/**/*.ts" -o JSONModels/projectName.json`, 'Creates a JSON-format Famix model of typescript files.')
11
+ .example(`ts2famix -i path/to/tsconfig.json -o JSONModels/projectName.json`, 'Creates a JSON-format model of a typescript project.')
12
+ .version()
13
+ .alias('v', 'version')
14
+ .alias('i', 'input')
15
+ .nargs('i', 1)
16
+ .alias('o', 'output')
17
+ .nargs('o', 1)
18
+ .alias('l', 'loglevel')
19
+ .nargs('l', 1)
20
+ .default('l', 3)
21
+ .describe('l', 'Set minimum logging level 0: silly, 1: trace, 2: debug, 3: info, 4: warn, 5: error, 6: fatal')
22
+ .boolean('graphemes')
23
+ .default('graphemes', false)
24
+ .describe('graphemes', 'Process graphemes (outside of the BMP) to avoid source anchor offset errors (due to performance issues, this is disabled by default)')
25
+ .demandOption('input')
26
+ .demandOption('output')
27
+ .parseSync();
28
+
29
+ import { logger } from './analyze';
30
+ logger.settings.minLevel = Number(argv.loglevel) as number;
31
+ config.expectGraphemes = argv.graphemes as boolean;
32
+
33
+ const importer = new Importer();
34
+ let famixRep: FamixRepository;
35
+
36
+ if ((argv.input as string).endsWith('tsconfig.json')) {
37
+ const tsConfigFilePath = argv.input as string;
38
+ // get the baseUrl from the tsconfig file
39
+ const baseUrl = tsConfigFilePath.substring(0, tsConfigFilePath.lastIndexOf('/'));
40
+ logger.info(`baseUrl: ${baseUrl}`);
41
+ const project = new Project({
42
+ tsConfigFilePath,
43
+ compilerOptions: {
44
+ baseUrl: baseUrl,
45
+ }
46
+ });
47
+ famixRep = importer.famixRepFromProject(project);
48
+
49
+ } else {
50
+ const paths = new Array<string>();
51
+ paths.push(argv.input as string);
52
+ famixRep = importer.famixRepFromPaths(paths);
53
+ }
54
+
55
+ const jsonOutput = famixRep.export({format: "json"});
56
+ const jsonFilePath = argv.output as string;
57
+
58
+ fs.writeFile(jsonFilePath, jsonOutput, (err) => {
59
+ if (err) { throw err; }
60
+ });
61
+
62
+ logger.info(`Created: ${jsonFilePath}`);
@@ -1,14 +1,14 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "commonjs",
5
- "strict": false,
6
- "esModuleInterop": true,
7
- "skipLibCheck": true,
8
- "forceConsistentCasingInFileNames": true,
9
- "noEmit": true
10
- },
11
- "include": [
12
- "test/**/*.ts"
13
- ]
14
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "strict": false,
6
+ "esModuleInterop": true,
7
+ "skipLibCheck": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "noEmit": true
10
+ },
11
+ "include": [
12
+ "test/**/*.ts"
13
+ ]
14
+ }