yukigo 0.2.3 → 0.3.2

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 (266) hide show
  1. package/.mocharc.json +3 -3
  2. package/CHANGELOG.md +105 -40
  3. package/README.md +193 -193
  4. package/dist/analyzer/GraphBuilder.d.ts +1 -0
  5. package/dist/analyzer/GraphBuilder.js +2 -1
  6. package/dist/analyzer/index.d.ts +0 -7
  7. package/dist/analyzer/index.js +3 -3
  8. package/dist/analyzer/inspections/functional/functional.d.ts +1 -1
  9. package/dist/analyzer/inspections/functional/functional.js +1 -1
  10. package/dist/analyzer/inspections/functional/smells.d.ts +3 -3
  11. package/dist/analyzer/inspections/functional/smells.js +27 -35
  12. package/dist/analyzer/inspections/generic/generic.d.ts +22 -14
  13. package/dist/analyzer/inspections/generic/generic.js +82 -60
  14. package/dist/analyzer/inspections/generic/smells.d.ts +2 -0
  15. package/dist/analyzer/inspections/generic/smells.js +55 -64
  16. package/dist/analyzer/inspections/imperative/imperative.d.ts +3 -3
  17. package/dist/analyzer/inspections/imperative/imperative.js +3 -3
  18. package/dist/analyzer/inspections/imperative/smells.d.ts +1 -0
  19. package/dist/analyzer/inspections/imperative/smells.js +8 -5
  20. package/dist/analyzer/inspections/logic/logic.d.ts +8 -8
  21. package/dist/analyzer/inspections/logic/logic.js +5 -5
  22. package/dist/analyzer/inspections/logic/smells.js +2 -2
  23. package/dist/analyzer/inspections/object/object.d.ts +5 -5
  24. package/dist/analyzer/inspections/object/object.js +22 -21
  25. package/dist/analyzer/inspections/object/smells.js +11 -23
  26. package/dist/analyzer/utils.d.ts +6 -2
  27. package/dist/analyzer/utils.js +6 -2
  28. package/dist/interpreter/components/EnvBuilder.d.ts +20 -1
  29. package/dist/interpreter/components/EnvBuilder.js +211 -66
  30. package/dist/interpreter/components/EqualityComparer.d.ts +15 -0
  31. package/dist/interpreter/components/EqualityComparer.js +69 -0
  32. package/dist/interpreter/components/Operations.d.ts +17 -14
  33. package/dist/interpreter/components/Operations.js +61 -62
  34. package/dist/interpreter/components/PatternMatcher.d.ts +19 -58
  35. package/dist/interpreter/components/PatternMatcher.js +185 -286
  36. package/dist/interpreter/components/RuntimeContext.d.ts +24 -15
  37. package/dist/interpreter/components/RuntimeContext.js +43 -4
  38. package/dist/interpreter/components/TestRunner.d.ts +15 -13
  39. package/dist/interpreter/components/TestRunner.js +86 -53
  40. package/dist/interpreter/components/evaluators/BaseEvaluator.d.ts +19 -0
  41. package/dist/interpreter/components/evaluators/BaseEvaluator.js +20 -0
  42. package/dist/interpreter/components/evaluators/ExpressionEvaluator.d.ts +34 -0
  43. package/dist/interpreter/components/evaluators/ExpressionEvaluator.js +298 -0
  44. package/dist/interpreter/components/evaluators/OperationEvaluator.d.ts +25 -0
  45. package/dist/interpreter/components/evaluators/OperationEvaluator.js +226 -0
  46. package/dist/interpreter/components/evaluators/PrimitiveEvaluator.d.ts +19 -0
  47. package/dist/interpreter/components/evaluators/PrimitiveEvaluator.js +50 -0
  48. package/dist/interpreter/components/evaluators/StatementEvaluator.d.ts +28 -0
  49. package/dist/interpreter/components/evaluators/StatementEvaluator.js +240 -0
  50. package/dist/interpreter/components/evaluators/TestingEvaluator.d.ts +15 -0
  51. package/dist/interpreter/components/evaluators/TestingEvaluator.js +14 -0
  52. package/dist/interpreter/components/evaluators/index.d.ts +110 -0
  53. package/dist/interpreter/components/evaluators/index.js +21 -0
  54. package/dist/interpreter/components/evaluators/utils.d.ts +7 -0
  55. package/dist/interpreter/components/evaluators/utils.js +50 -0
  56. package/dist/interpreter/components/hooks/YukigoHook.d.ts +27 -0
  57. package/dist/interpreter/components/hooks/YukigoHook.js +1 -0
  58. package/dist/interpreter/components/kernel/commands.d.ts +122 -0
  59. package/dist/interpreter/components/kernel/commands.js +203 -0
  60. package/dist/interpreter/components/kernel/index.d.ts +51 -0
  61. package/dist/interpreter/components/kernel/index.js +176 -0
  62. package/dist/interpreter/components/logic/LogicEngine.d.ts +26 -23
  63. package/dist/interpreter/components/logic/LogicEngine.js +234 -221
  64. package/dist/interpreter/components/logic/LogicResolver.d.ts +22 -51
  65. package/dist/interpreter/components/logic/LogicResolver.js +73 -440
  66. package/dist/interpreter/components/logic/LogicTerm.d.ts +104 -0
  67. package/dist/interpreter/components/logic/LogicTerm.js +423 -0
  68. package/dist/interpreter/components/logic/LogicTranslator.d.ts +25 -9
  69. package/dist/interpreter/components/logic/LogicTranslator.js +211 -74
  70. package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +6 -4
  71. package/dist/interpreter/components/runtimes/FunctionRuntime.js +82 -84
  72. package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +13 -14
  73. package/dist/interpreter/components/runtimes/LazyRuntime.js +112 -239
  74. package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +17 -14
  75. package/dist/interpreter/components/runtimes/ObjectRuntime.js +105 -74
  76. package/dist/interpreter/errors.d.ts +10 -0
  77. package/dist/interpreter/errors.js +17 -0
  78. package/dist/interpreter/index.d.ts +9 -5
  79. package/dist/interpreter/index.js +11 -13
  80. package/dist/interpreter/primitives/YuValue.d.ts +21 -0
  81. package/dist/interpreter/primitives/YuValue.js +40 -0
  82. package/dist/interpreter/primitives/capabilities.d.ts +90 -0
  83. package/dist/interpreter/primitives/capabilities.js +1 -0
  84. package/dist/interpreter/primitives/entities/LazyList.d.ts +48 -0
  85. package/dist/interpreter/primitives/entities/LazyList.js +164 -0
  86. package/dist/interpreter/primitives/entities/LogicResult.d.ts +51 -0
  87. package/dist/interpreter/primitives/entities/LogicResult.js +101 -0
  88. package/dist/interpreter/primitives/entities/RuntimeClass.d.ts +24 -0
  89. package/dist/interpreter/primitives/entities/RuntimeClass.js +57 -0
  90. package/dist/interpreter/primitives/entities/RuntimeFunction.d.ts +40 -0
  91. package/dist/interpreter/primitives/entities/RuntimeFunction.js +73 -0
  92. package/dist/interpreter/primitives/entities/RuntimeObject.d.ts +27 -0
  93. package/dist/interpreter/primitives/entities/RuntimeObject.js +82 -0
  94. package/dist/interpreter/primitives/entities/RuntimePredicate.d.ts +19 -0
  95. package/dist/interpreter/primitives/entities/RuntimePredicate.js +59 -0
  96. package/dist/interpreter/primitives/index.d.ts +14 -0
  97. package/dist/interpreter/primitives/index.js +14 -0
  98. package/dist/interpreter/primitives/scalars/YuBoolean.d.ts +24 -0
  99. package/dist/interpreter/primitives/scalars/YuBoolean.js +69 -0
  100. package/dist/interpreter/primitives/scalars/YuChar.d.ts +28 -0
  101. package/dist/interpreter/primitives/scalars/YuChar.js +78 -0
  102. package/dist/interpreter/primitives/scalars/YuNil.d.ts +25 -0
  103. package/dist/interpreter/primitives/scalars/YuNil.js +73 -0
  104. package/dist/interpreter/primitives/scalars/YuNumber.d.ts +49 -0
  105. package/dist/interpreter/primitives/scalars/YuNumber.js +165 -0
  106. package/dist/interpreter/primitives/sequences/YuArray.d.ts +33 -0
  107. package/dist/interpreter/primitives/sequences/YuArray.js +150 -0
  108. package/dist/interpreter/primitives/sequences/YuString.d.ts +40 -0
  109. package/dist/interpreter/primitives/sequences/YuString.js +130 -0
  110. package/dist/interpreter/utils.d.ts +23 -10
  111. package/dist/interpreter/utils.js +25 -30
  112. package/dist/tester/index.d.ts +3 -3
  113. package/dist/tester/index.js +39 -28
  114. package/dist/utils/helpers.d.ts +13 -5
  115. package/dist/utils/helpers.js +38 -85
  116. package/package.json +3 -16
  117. package/src/analyzer/GraphBuilder.ts +143 -142
  118. package/src/analyzer/index.ts +185 -194
  119. package/src/analyzer/inspections/functional/functional.ts +121 -121
  120. package/src/analyzer/inspections/functional/smells.ts +88 -102
  121. package/src/analyzer/inspections/generic/generic.ts +610 -577
  122. package/src/analyzer/inspections/generic/smells.ts +355 -365
  123. package/src/analyzer/inspections/imperative/imperative.ts +104 -101
  124. package/src/analyzer/inspections/imperative/smells.ts +58 -54
  125. package/src/analyzer/inspections/logic/logic.ts +84 -90
  126. package/src/analyzer/inspections/logic/smells.ts +54 -54
  127. package/src/analyzer/inspections/object/object.ts +295 -264
  128. package/src/analyzer/inspections/object/smells.ts +130 -144
  129. package/src/analyzer/utils.ts +115 -109
  130. package/src/index.ts +3 -3
  131. package/src/interpreter/components/EnvBuilder.ts +405 -202
  132. package/src/interpreter/components/EqualityComparer.ts +107 -0
  133. package/src/interpreter/components/Operations.ts +126 -99
  134. package/src/interpreter/components/PatternMatcher.ts +375 -475
  135. package/src/interpreter/components/RuntimeContext.ts +181 -119
  136. package/src/interpreter/components/TestRunner.ts +223 -151
  137. package/src/interpreter/components/evaluators/BaseEvaluator.ts +36 -0
  138. package/src/interpreter/components/evaluators/ExpressionEvaluator.ts +475 -0
  139. package/src/interpreter/components/evaluators/OperationEvaluator.ts +477 -0
  140. package/src/interpreter/components/evaluators/PrimitiveEvaluator.ts +80 -0
  141. package/src/interpreter/components/evaluators/StatementEvaluator.ts +372 -0
  142. package/src/interpreter/components/evaluators/TestingEvaluator.ts +26 -0
  143. package/src/interpreter/components/evaluators/index.ts +34 -0
  144. package/src/interpreter/components/evaluators/utils.ts +64 -0
  145. package/src/interpreter/components/hooks/YukigoHook.ts +45 -0
  146. package/src/interpreter/components/kernel/commands.ts +255 -0
  147. package/src/interpreter/components/kernel/index.ts +222 -0
  148. package/src/interpreter/components/logic/LogicEngine.ts +509 -519
  149. package/src/interpreter/components/logic/LogicResolver.ts +209 -858
  150. package/src/interpreter/components/logic/LogicTerm.ts +477 -0
  151. package/src/interpreter/components/logic/LogicTranslator.ts +362 -149
  152. package/src/interpreter/components/runtimes/FunctionRuntime.ts +249 -227
  153. package/src/interpreter/components/runtimes/LazyRuntime.ts +226 -334
  154. package/src/interpreter/components/runtimes/ObjectRuntime.ts +262 -224
  155. package/src/interpreter/errors.ts +68 -47
  156. package/src/interpreter/index.ts +50 -52
  157. package/src/interpreter/primitives/YuValue.ts +64 -0
  158. package/src/interpreter/primitives/capabilities.ts +111 -0
  159. package/src/interpreter/primitives/entities/LazyList.ts +225 -0
  160. package/src/interpreter/primitives/entities/LogicResult.ts +133 -0
  161. package/src/interpreter/primitives/entities/RuntimeClass.ts +70 -0
  162. package/src/interpreter/primitives/entities/RuntimeFunction.ts +108 -0
  163. package/src/interpreter/primitives/entities/RuntimeObject.ts +110 -0
  164. package/src/interpreter/primitives/entities/RuntimePredicate.ts +77 -0
  165. package/src/interpreter/primitives/index.ts +17 -0
  166. package/src/interpreter/primitives/scalars/YuBoolean.ts +79 -0
  167. package/src/interpreter/primitives/scalars/YuChar.ts +94 -0
  168. package/src/interpreter/primitives/scalars/YuNil.ts +84 -0
  169. package/src/interpreter/primitives/scalars/YuNumber.ts +187 -0
  170. package/src/interpreter/primitives/sequences/YuArray.ts +178 -0
  171. package/src/interpreter/primitives/sequences/YuString.ts +165 -0
  172. package/src/interpreter/utils.ts +105 -84
  173. package/src/tester/index.ts +157 -128
  174. package/src/utils/helpers.ts +113 -169
  175. package/tests/analyzer/functional.spec.ts +221 -207
  176. package/tests/analyzer/generic.spec.ts +178 -178
  177. package/tests/analyzer/helpers.spec.ts +83 -89
  178. package/tests/analyzer/logic.spec.ts +237 -237
  179. package/tests/analyzer/oop.spec.ts +320 -323
  180. package/tests/analyzer/transitive.spec.ts +166 -166
  181. package/tests/interpreter/EnvBuilder.spec.ts +181 -183
  182. package/tests/interpreter/FunctionRuntime.spec.ts +224 -223
  183. package/tests/interpreter/LazyRuntime.spec.ts +227 -225
  184. package/tests/interpreter/LogicEngine.spec.ts +371 -327
  185. package/tests/interpreter/LogicSubstitution.spec.ts +90 -80
  186. package/tests/interpreter/ObjectRuntime.spec.ts +431 -606
  187. package/tests/interpreter/Operations.spec.ts +312 -220
  188. package/tests/interpreter/PatternSystem.spec.ts +254 -213
  189. package/tests/interpreter/Tests.spec.ts +122 -122
  190. package/tests/interpreter/interpreter.spec.ts +1143 -991
  191. package/tests/kernel/YukigoKernel.spec.ts +112 -0
  192. package/tests/tester/Tester.spec.ts +156 -152
  193. package/tsconfig.build.json +16 -15
  194. package/tsconfig.json +27 -25
  195. package/dist/interpreter/components/Visitor.d.ts +0 -70
  196. package/dist/interpreter/components/Visitor.js +0 -634
  197. package/dist/interpreter/entities.d.ts +0 -105
  198. package/dist/interpreter/entities.js +0 -96
  199. package/dist/interpreter/trampoline.d.ts +0 -17
  200. package/dist/interpreter/trampoline.js +0 -38
  201. package/dist/src/analyzer/GraphBuilder.d.ts +0 -30
  202. package/dist/src/analyzer/GraphBuilder.js +0 -100
  203. package/dist/src/analyzer/index.d.ts +0 -59
  204. package/dist/src/analyzer/index.js +0 -152
  205. package/dist/src/analyzer/inspections/functional/functional.d.ts +0 -44
  206. package/dist/src/analyzer/inspections/functional/functional.js +0 -149
  207. package/dist/src/analyzer/inspections/functional/smells.d.ts +0 -16
  208. package/dist/src/analyzer/inspections/functional/smells.js +0 -98
  209. package/dist/src/analyzer/inspections/generic/generic.d.ts +0 -178
  210. package/dist/src/analyzer/inspections/generic/generic.js +0 -604
  211. package/dist/src/analyzer/inspections/generic/smells.d.ts +0 -61
  212. package/dist/src/analyzer/inspections/generic/smells.js +0 -349
  213. package/dist/src/analyzer/inspections/imperative/imperative.d.ts +0 -35
  214. package/dist/src/analyzer/inspections/imperative/imperative.js +0 -109
  215. package/dist/src/analyzer/inspections/imperative/smells.d.ts +0 -16
  216. package/dist/src/analyzer/inspections/imperative/smells.js +0 -58
  217. package/dist/src/analyzer/inspections/logic/logic.d.ts +0 -32
  218. package/dist/src/analyzer/inspections/logic/logic.js +0 -96
  219. package/dist/src/analyzer/inspections/logic/smells.d.ts +0 -15
  220. package/dist/src/analyzer/inspections/logic/smells.js +0 -60
  221. package/dist/src/analyzer/inspections/object/object.d.ts +0 -90
  222. package/dist/src/analyzer/inspections/object/object.js +0 -321
  223. package/dist/src/analyzer/inspections/object/smells.d.ts +0 -30
  224. package/dist/src/analyzer/inspections/object/smells.js +0 -135
  225. package/dist/src/analyzer/utils.d.ts +0 -30
  226. package/dist/src/analyzer/utils.js +0 -78
  227. package/dist/src/index.d.ts +0 -4
  228. package/dist/src/index.js +0 -4
  229. package/dist/src/interpreter/components/EnvBuilder.d.ts +0 -21
  230. package/dist/src/interpreter/components/EnvBuilder.js +0 -155
  231. package/dist/src/interpreter/components/Operations.d.ts +0 -14
  232. package/dist/src/interpreter/components/Operations.js +0 -84
  233. package/dist/src/interpreter/components/PatternMatcher.d.ts +0 -73
  234. package/dist/src/interpreter/components/PatternMatcher.js +0 -358
  235. package/dist/src/interpreter/components/RuntimeContext.d.ts +0 -35
  236. package/dist/src/interpreter/components/RuntimeContext.js +0 -93
  237. package/dist/src/interpreter/components/TestRunner.d.ts +0 -19
  238. package/dist/src/interpreter/components/TestRunner.js +0 -110
  239. package/dist/src/interpreter/components/Visitor.d.ts +0 -71
  240. package/dist/src/interpreter/components/Visitor.js +0 -638
  241. package/dist/src/interpreter/components/logic/LogicEngine.d.ts +0 -29
  242. package/dist/src/interpreter/components/logic/LogicEngine.js +0 -259
  243. package/dist/src/interpreter/components/logic/LogicResolver.d.ts +0 -53
  244. package/dist/src/interpreter/components/logic/LogicResolver.js +0 -484
  245. package/dist/src/interpreter/components/logic/LogicTranslator.d.ts +0 -14
  246. package/dist/src/interpreter/components/logic/LogicTranslator.js +0 -99
  247. package/dist/src/interpreter/components/runtimes/FunctionRuntime.d.ts +0 -12
  248. package/dist/src/interpreter/components/runtimes/FunctionRuntime.js +0 -149
  249. package/dist/src/interpreter/components/runtimes/LazyRuntime.d.ts +0 -19
  250. package/dist/src/interpreter/components/runtimes/LazyRuntime.js +0 -269
  251. package/dist/src/interpreter/components/runtimes/ObjectRuntime.d.ts +0 -35
  252. package/dist/src/interpreter/components/runtimes/ObjectRuntime.js +0 -126
  253. package/dist/src/interpreter/errors.d.ts +0 -19
  254. package/dist/src/interpreter/errors.js +0 -36
  255. package/dist/src/interpreter/index.d.ts +0 -24
  256. package/dist/src/interpreter/index.js +0 -41
  257. package/dist/src/interpreter/trampoline.d.ts +0 -17
  258. package/dist/src/interpreter/trampoline.js +0 -38
  259. package/dist/src/interpreter/utils.d.ts +0 -11
  260. package/dist/src/interpreter/utils.js +0 -65
  261. package/dist/src/tester/index.d.ts +0 -25
  262. package/dist/src/tester/index.js +0 -113
  263. package/dist/src/utils/helpers.d.ts +0 -13
  264. package/dist/src/utils/helpers.js +0 -52
  265. package/src/interpreter/components/Visitor.ts +0 -1065
  266. package/src/interpreter/trampoline.ts +0 -71
@@ -1,323 +1,320 @@
1
- import { expect } from "chai";
2
- import {
3
- Class,
4
- Method,
5
- Send,
6
- Self,
7
- SymbolPrimitive,
8
- Attribute,
9
- New,
10
- Interface,
11
- Object as AstObject,
12
- PrimitiveMethod,
13
- Implement,
14
- ASTNode,
15
- Equation,
16
- UnguardedBody,
17
- Sequence,
18
- NilPrimitive,
19
- Statement,
20
- Print,
21
- StringPrimitive,
22
- Variable,
23
- } from "yukigo-ast";
24
- import { Analyzer, InspectionRule } from "../../src/analyzer/index.js";
25
-
26
- describe("OOP Inspections", () => {
27
- const createSymbol = (name: string) => new SymbolPrimitive(name);
28
- const analyzer = new Analyzer();
29
-
30
- const runSingleRule = (
31
- ast: any[],
32
- inspection: string,
33
- expected: boolean,
34
- binding?: string,
35
- args: string[] = []
36
- ) => {
37
- const rule: InspectionRule = { inspection, binding, args, expected };
38
- const results = analyzer.analyze(ast, [rule]);
39
- const result = results[0];
40
- return result.passed;
41
- };
42
-
43
- const createMethod = (
44
- name: string,
45
- equationsCount: number = 1,
46
- isAbstract: boolean = false,
47
- bodyNode?: Statement
48
- ): Method => {
49
- const identifier = createSymbol(name);
50
- const stmts = bodyNode ? [bodyNode] : [];
51
- const equations = new Array(equationsCount).fill(
52
- new Equation([], new UnguardedBody(new Sequence(stmts)))
53
- );
54
- const method = new Method(identifier, equations);
55
- method.setMetadata("isAbstract", isAbstract);
56
- return method;
57
- };
58
-
59
- const createAttribute = (
60
- name: string,
61
- expression: any = new NilPrimitive(null)
62
- ) => {
63
- return new Attribute(createSymbol(name), expression);
64
- };
65
-
66
- const createNew = (className: string) => {
67
- return new New(createSymbol(className), []);
68
- };
69
-
70
- const createClass = (
71
- name: string,
72
- stmts: Statement[] = [],
73
- extendsName?: string,
74
- implementsName?: string,
75
- includes?: string[]
76
- ): Class => {
77
- const identifier = createSymbol(name);
78
- const extendsSymbol = extendsName ? createSymbol(extendsName) : undefined;
79
- const implementsNode = implementsName
80
- ? new Implement(createSymbol(implementsName))
81
- : undefined;
82
- const includesMixin =
83
- includes && includes.length > 0
84
- ? includes.map((sym) => createSymbol(sym))
85
- : undefined;
86
-
87
- const expression = new Sequence(stmts);
88
-
89
- return new Class(
90
- identifier,
91
- extendsSymbol,
92
- implementsNode,
93
- includesMixin,
94
- expression
95
- );
96
- };
97
-
98
- const createObject = (name: string, children: Statement[] = []) => {
99
- const identifier = createSymbol(name);
100
- const expression = new Sequence(children);
101
- return new AstObject(identifier, expression);
102
- };
103
-
104
- describe("DeclaresAttribute", () => {
105
- it("should detect if an attribute with the specific name is declared", () => {
106
- const attr = createAttribute("energy");
107
- const ast = [createClass("A", [attr])];
108
- expect(
109
- runSingleRule(ast, "DeclaresAttribute", true, undefined, ["energy"])
110
- ).to.be.true;
111
- });
112
-
113
- it("should ignore attributes with different names", () => {
114
- const attr = createAttribute("life");
115
- const ast = [createClass("A", [attr])];
116
- expect(
117
- runSingleRule(ast, "DeclaresAttribute", false, undefined, ["energy"])
118
- ).to.be.true;
119
- });
120
- });
121
-
122
- describe("DeclaresClass", () => {
123
- it("should detect specific class declaration", () => {
124
- const ast = [createClass("Bird")];
125
- expect(runSingleRule(ast, "DeclaresClass", true, "Bird")).to.be.true;
126
- });
127
- });
128
-
129
- describe("DeclaresInterface", () => {
130
- it("should detect specific interface declaration", () => {
131
- const ast = [
132
- new Interface(createSymbol("Flyable"), [], new Sequence([])),
133
- ];
134
- expect(runSingleRule(ast, "DeclaresInterface", true, "Flyable")).to.be
135
- .true;
136
- });
137
- });
138
-
139
- describe("DeclaresMethod", () => {
140
- it("should detect specific method declaration", () => {
141
- const ast = [createMethod("fly")];
142
- expect(runSingleRule(ast, "DeclaresMethod", true, "fly")).to.be.true;
143
- });
144
- });
145
-
146
- describe("DeclaresObject", () => {
147
- it("should detect specific object declaration", () => {
148
- const ast = [createObject("pepita")];
149
- expect(runSingleRule(ast, "DeclaresObject", true, "pepita")).to.be.true;
150
- });
151
- });
152
-
153
- describe("DeclaresPrimitive", () => {
154
- it("should detect primitive operator override", () => {
155
- const op: any = "==";
156
- const ast = [new PrimitiveMethod(op, [], undefined)];
157
- expect(runSingleRule(ast, "DeclaresPrimitive", true, undefined, ["=="]))
158
- .to.be.true;
159
- });
160
- });
161
-
162
- describe("DeclaresSuperclass", () => {
163
- it("should detect if a class extends a specific superclass", () => {
164
- const ast = [createClass("Sparrow", [], "Bird")];
165
- expect(
166
- runSingleRule(ast, "DeclaresSuperclass", true, undefined, ["Bird"])
167
- ).to.be.true;
168
- });
169
- });
170
-
171
- describe("Implements", () => {
172
- it("should detect if a class implements a specific interface", () => {
173
- const ast = [createClass("Pigeon", [], undefined, "Messenger")];
174
- expect(runSingleRule(ast, "Implements", true, undefined, ["Messenger"]))
175
- .to.be.true;
176
- });
177
- });
178
-
179
- describe("IncludeMixin", () => {
180
- it("should detect usage of a specific mixin", () => {
181
- const ast = [
182
- createClass("ClassWithMixin", [], undefined, undefined, ["Walking"]),
183
- ];
184
- expect(runSingleRule(ast, "IncludeMixin", true, undefined, ["Walking"]))
185
- .to.be.true;
186
- });
187
- });
188
-
189
- describe("Instantiates", () => {
190
- it("should detect instantiation of a specific class", () => {
191
- const ast = [new Variable(new SymbolPrimitive("a"), createNew("Engine"))];
192
- expect(runSingleRule(ast, "Instantiates", true, undefined, ["Engine"])).to
193
- .be.true;
194
- });
195
- });
196
-
197
- describe("UsesDynamicPolymorphism", () => {
198
- it("should detect when a method name is used in at least two different places (polymorphism)", () => {
199
- const method1 = createMethod("fly");
200
- const method2 = createMethod("fly");
201
- const class1 = createClass("Bird", [method1]);
202
- const class2 = createClass("Airplane", [method2]);
203
- const ast = [class1, class2];
204
- expect(runSingleRule(ast, "UsesDynamicPolymorphism", true, undefined, ["fly"]))
205
- .to.be.true;
206
- });
207
-
208
- it("should not throw if only one method is found", () => {
209
- const method1 = createMethod("fly");
210
- const class1 = createClass("Bird", [method1]);
211
- const ast = [class1];
212
- expect(runSingleRule(ast, "UsesDynamicPolymorphism", false, "fly")).to.be
213
- .true;
214
- });
215
- });
216
-
217
- describe("UsesInheritance", () => {
218
- it("should detect inheritance in classes", () => {
219
- const ast = [createClass("Child", [], "Parent")];
220
- expect(runSingleRule(ast, "UsesInheritance", true)).to.be.true;
221
- });
222
-
223
- it("should detect inheritance in interfaces", () => {
224
- const ast = [
225
- new Interface(
226
- createSymbol("IChild"),
227
- [createSymbol("IParent")],
228
- new Sequence([])
229
- ),
230
- ];
231
- expect(runSingleRule(ast, "UsesInheritance", true)).to.be.true;
232
- });
233
-
234
- it("should ignore classes without parent", () => {
235
- const ast = [createClass("Orphan")];
236
- expect(runSingleRule(ast, "UsesInheritance", false)).to.be.true;
237
- });
238
- });
239
-
240
- describe("UsesMixins", () => {
241
- it("should detect any mixin usage", () => {
242
- const ast = [
243
- createClass("ClassWithMixin", [], undefined, undefined, ["AnyMixin"]),
244
- ];
245
- expect(runSingleRule(ast, "UsesMixins", true)).to.be.true;
246
- });
247
- });
248
-
249
- describe("UsesObjectComposition", () => {
250
- it("should detect composition when an attribute is initialized with New", () => {
251
- const instantiation = createNew("Engine");
252
- const attr = createAttribute("myEngine", instantiation);
253
- const ast = [createClass("A", [attr])];
254
- expect(runSingleRule(ast, "UsesObjectComposition", true)).to.be.true;
255
- });
256
-
257
- it("should ignore attributes initialized with literals", () => {
258
- const attr = createAttribute(
259
- "energy",
260
- new StringPrimitive("Initialized with string!")
261
- );
262
- const ast = [createClass("A", [attr])];
263
- expect(runSingleRule(ast, "UsesObjectComposition", false)).to.be.true;
264
- });
265
- });
266
-
267
- describe("UsesStaticMethodOverload", () => {
268
- it("should detect two methods with the same name in the same class", () => {
269
- const m1 = createMethod("calculate");
270
- const m2 = createMethod("calculate");
271
- const ast = [createClass("Calculator", [m1, m2])];
272
- expect(runSingleRule(ast, "UsesStaticMethodOverload", true)).to.be.true;
273
- });
274
-
275
- it("should NOT detect overload if methods are in different classes", () => {
276
- const m1 = createMethod("calculate");
277
- const m2 = createMethod("calculate");
278
- const classA = createClass("A", [m1]);
279
- const classB = createClass("B", [m2]);
280
- const ast = [classA, classB];
281
- expect(runSingleRule(ast, "UsesStaticMethodOverload", false)).to.be.true;
282
- });
283
- });
284
-
285
- describe("UsesDynamicMethodOverload", () => {
286
- it("should detect a method with multiple equations (pattern matching)", () => {
287
- const ast = [createMethod("fibonacci", 2)];
288
- expect(runSingleRule(ast, "UsesDynamicMethodOverload", true)).to.be.true;
289
- });
290
-
291
- it("should ignore methods with a single equation", () => {
292
- const ast = [createMethod("fibonacci", 1)];
293
- expect(runSingleRule(ast, "UsesDynamicMethodOverload", false)).to.be.true;
294
- });
295
- });
296
-
297
- describe("UsesTemplateMethod", () => {
298
- it("should detect template method usage (call to undeclared method on self)", () => {
299
- const declaredMethod = createMethod("abstractMethod", 1, true);
300
- const sendToSelf = new Send(
301
- new Self(),
302
- createSymbol("abstractMethod"),
303
- []
304
- );
305
- const templateMethod = createMethod("process", 1, false, sendToSelf);
306
- const ast = [createClass("MyClass", [declaredMethod, templateMethod])];
307
- expect(runSingleRule(ast, "UsesTemplateMethod", true)).to.be.true;
308
- });
309
-
310
- it("should NOT detect if calling a declared method on self", () => {
311
- const declaredMethod = createMethod(
312
- "declared",
313
- 1,
314
- false,
315
- new Print(new StringPrimitive("This method is Declared"))
316
- );
317
- const sendToSelf = new Send(new Self(), createSymbol("declared"), []);
318
- const method = createMethod("process", 1, false, sendToSelf);
319
- const ast = [createClass("MyClass", [declaredMethod, method])];
320
- expect(runSingleRule(ast, "UsesTemplateMethod", false)).to.be.true;
321
- });
322
- });
323
- });
1
+ import { expect } from "chai";
2
+ import {
3
+ Class,
4
+ Method,
5
+ Send,
6
+ Self,
7
+ SymbolPrimitive,
8
+ Attribute,
9
+ New,
10
+ Interface,
11
+ Object as AstObject,
12
+ PrimitiveMethod,
13
+ Implement,
14
+ Equation,
15
+ UnguardedBody,
16
+ Sequence,
17
+ NilPrimitive,
18
+ Statement,
19
+ Print,
20
+ StringPrimitive,
21
+ Variable,
22
+ SourceLocation,
23
+ } from "yukigo-ast";
24
+ import { Analyzer, InspectionRule } from "../../src/analyzer/index.js";
25
+
26
+ describe("OOP Inspections", () => {
27
+ const createSymbol = (name: string) => new SymbolPrimitive(name);
28
+ const analyzer = new Analyzer();
29
+
30
+ const runSingleRule = (
31
+ ast: any[],
32
+ inspection: string,
33
+ expected: boolean,
34
+ binding?: string,
35
+ args: string[] = []
36
+ ) => {
37
+ const rule: InspectionRule = { inspection, binding, args, expected };
38
+ const results = analyzer.analyze(ast, [rule]);
39
+ const result = results[0];
40
+ return result.passed;
41
+ };
42
+
43
+ const createMethod = (
44
+ name: string,
45
+ equationsCount: number = 1,
46
+ isAbstract: boolean = false,
47
+ bodyNode?: Statement
48
+ ): Method => {
49
+ const identifier = createSymbol(name);
50
+ const stmts = bodyNode ? [bodyNode] : [];
51
+ const equations = new Array(equationsCount).fill(
52
+ new Equation([], new UnguardedBody(new Sequence(stmts)))
53
+ );
54
+ const method = new Method(identifier, equations, undefined, isAbstract);
55
+ return method;
56
+ };
57
+
58
+ const createAttribute = (
59
+ name: string,
60
+ expression: any = new NilPrimitive(null)
61
+ ) => {
62
+ return new Attribute(createSymbol(name), expression);
63
+ };
64
+
65
+ const createNew = (className: string) => {
66
+ return new New(createSymbol(className), []);
67
+ };
68
+
69
+ const createClass = (
70
+ name: string,
71
+ stmts: Statement[] = [],
72
+ extendsName?: string,
73
+ implementsName?: string,
74
+ includes?: string[]
75
+ ): Class => {
76
+ const identifier = createSymbol(name);
77
+ const extendsSymbol = extendsName ? createSymbol(extendsName) : undefined;
78
+ const implementsNode = implementsName
79
+ ? new Implement(createSymbol(implementsName))
80
+ : undefined;
81
+ const includesMixin = includes
82
+ ? includes.map((sym) => createSymbol(sym))
83
+ : [];
84
+ const expression = new Sequence(stmts);
85
+
86
+ return new Class(
87
+ identifier,
88
+ extendsSymbol,
89
+ implementsNode,
90
+ includesMixin,
91
+ expression
92
+ );
93
+ };
94
+
95
+ const createObject = (name: string, children: Statement[] = []) => {
96
+ const identifier = createSymbol(name);
97
+ const expression = new Sequence(children);
98
+ return new AstObject(identifier, expression);
99
+ };
100
+
101
+ describe("DeclaresAttribute", () => {
102
+ it("should detect if an attribute with the specific name is declared", () => {
103
+ const attr = createAttribute("energy");
104
+ const ast = [createClass("A", [attr])];
105
+ expect(
106
+ runSingleRule(ast, "DeclaresAttribute", true, undefined, ["energy"])
107
+ ).to.be.true;
108
+ });
109
+
110
+ it("should ignore attributes with different names", () => {
111
+ const attr = createAttribute("life");
112
+ const ast = [createClass("A", [attr])];
113
+ expect(
114
+ runSingleRule(ast, "DeclaresAttribute", false, undefined, ["energy"])
115
+ ).to.be.true;
116
+ });
117
+ });
118
+
119
+ describe("DeclaresClass", () => {
120
+ it("should detect specific class declaration", () => {
121
+ const ast = [createClass("Bird")];
122
+ expect(runSingleRule(ast, "DeclaresClass", true, "Bird")).to.be.true;
123
+ });
124
+ });
125
+
126
+ describe("DeclaresInterface", () => {
127
+ it("should detect specific interface declaration", () => {
128
+ const ast = [
129
+ new Interface(createSymbol("Flyable"), [], new Sequence([])),
130
+ ];
131
+ expect(runSingleRule(ast, "DeclaresInterface", true, "Flyable")).to.be
132
+ .true;
133
+ });
134
+ });
135
+
136
+ describe("DeclaresMethod", () => {
137
+ it("should detect specific method declaration", () => {
138
+ const ast = [createMethod("fly")];
139
+ expect(runSingleRule(ast, "DeclaresMethod", true, "fly")).to.be.true;
140
+ });
141
+ });
142
+
143
+ describe("DeclaresObject", () => {
144
+ it("should detect specific object declaration", () => {
145
+ const ast = [createObject("pepita")];
146
+ expect(runSingleRule(ast, "DeclaresObject", true, "pepita")).to.be.true;
147
+ });
148
+ });
149
+
150
+ describe("DeclaresPrimitive", () => {
151
+ it("should detect primitive operator override", () => {
152
+ const op: any = "==";
153
+ const ast = [new PrimitiveMethod(op, [], new SourceLocation(0,0))];
154
+ expect(runSingleRule(ast, "DeclaresPrimitive", true, undefined, ["=="]))
155
+ .to.be.true;
156
+ });
157
+ });
158
+
159
+ describe("DeclaresSuperclass", () => {
160
+ it("should detect if a class extends a specific superclass", () => {
161
+ const ast = [createClass("Sparrow", [], "Bird")];
162
+ expect(
163
+ runSingleRule(ast, "DeclaresSuperclass", true, undefined, ["Bird"])
164
+ ).to.be.true;
165
+ });
166
+ });
167
+
168
+ describe("Implements", () => {
169
+ it("should detect if a class implements a specific interface", () => {
170
+ const ast = [createClass("Pigeon", [], undefined, "Messenger")];
171
+ expect(runSingleRule(ast, "Implements", true, undefined, ["Messenger"]))
172
+ .to.be.true;
173
+ });
174
+ });
175
+
176
+ describe("IncludeMixin", () => {
177
+ it("should detect usage of a specific mixin", () => {
178
+ const ast = [
179
+ createClass("ClassWithMixin", [], undefined, undefined, ["Walking"]),
180
+ ];
181
+ expect(runSingleRule(ast, "IncludeMixin", true, undefined, ["Walking"]))
182
+ .to.be.true;
183
+ });
184
+ });
185
+
186
+ describe("Instantiates", () => {
187
+ it("should detect instantiation of a specific class", () => {
188
+ const ast = [new Variable(new SymbolPrimitive("a"), createNew("Engine"))];
189
+ expect(runSingleRule(ast, "Instantiates", true, undefined, ["Engine"])).to
190
+ .be.true;
191
+ });
192
+ });
193
+
194
+ describe("UsesDynamicPolymorphism", () => {
195
+ it("should detect when a method name is used in at least two different places (polymorphism)", () => {
196
+ const method1 = createMethod("fly");
197
+ const method2 = createMethod("fly");
198
+ const class1 = createClass("Bird", [method1]);
199
+ const class2 = createClass("Airplane", [method2]);
200
+ const ast = [class1, class2];
201
+ expect(runSingleRule(ast, "UsesDynamicPolymorphism", true, undefined, ["fly"]))
202
+ .to.be.true;
203
+ });
204
+
205
+ it("should not throw if only one method is found", () => {
206
+ const method1 = createMethod("fly");
207
+ const class1 = createClass("Bird", [method1]);
208
+ const ast = [class1];
209
+ expect(runSingleRule(ast, "UsesDynamicPolymorphism", false, "fly")).to.be
210
+ .true;
211
+ });
212
+ });
213
+
214
+ describe("UsesInheritance", () => {
215
+ it("should detect inheritance in classes", () => {
216
+ const ast = [createClass("Child", [], "Parent")];
217
+ expect(runSingleRule(ast, "UsesInheritance", true)).to.be.true;
218
+ });
219
+
220
+ it("should detect inheritance in interfaces", () => {
221
+ const ast = [
222
+ new Interface(
223
+ createSymbol("IChild"),
224
+ [createSymbol("IParent")],
225
+ new Sequence([])
226
+ ),
227
+ ];
228
+ expect(runSingleRule(ast, "UsesInheritance", true)).to.be.true;
229
+ });
230
+
231
+ it("should ignore classes without parent", () => {
232
+ const ast = [createClass("Orphan")];
233
+ expect(runSingleRule(ast, "UsesInheritance", false)).to.be.true;
234
+ });
235
+ });
236
+
237
+ describe("UsesMixins", () => {
238
+ it("should detect any mixin usage", () => {
239
+ const ast = [
240
+ createClass("ClassWithMixin", [], undefined, undefined, ["AnyMixin"]),
241
+ ];
242
+ expect(runSingleRule(ast, "UsesMixins", true)).to.be.true;
243
+ });
244
+ });
245
+
246
+ describe("UsesObjectComposition", () => {
247
+ it("should detect composition when an attribute is initialized with New", () => {
248
+ const instantiation = createNew("Engine");
249
+ const attr = createAttribute("myEngine", instantiation);
250
+ const ast = [createClass("A", [attr])];
251
+ expect(runSingleRule(ast, "UsesObjectComposition", true)).to.be.true;
252
+ });
253
+
254
+ it("should ignore attributes initialized with literals", () => {
255
+ const attr = createAttribute(
256
+ "energy",
257
+ new StringPrimitive("Initialized with string!")
258
+ );
259
+ const ast = [createClass("A", [attr])];
260
+ expect(runSingleRule(ast, "UsesObjectComposition", false)).to.be.true;
261
+ });
262
+ });
263
+
264
+ describe("UsesStaticMethodOverload", () => {
265
+ it("should detect two methods with the same name in the same class", () => {
266
+ const m1 = createMethod("calculate");
267
+ const m2 = createMethod("calculate");
268
+ const ast = [createClass("Calculator", [m1, m2])];
269
+ expect(runSingleRule(ast, "UsesStaticMethodOverload", true)).to.be.true;
270
+ });
271
+
272
+ it("should NOT detect overload if methods are in different classes", () => {
273
+ const m1 = createMethod("calculate");
274
+ const m2 = createMethod("calculate");
275
+ const classA = createClass("A", [m1]);
276
+ const classB = createClass("B", [m2]);
277
+ const ast = [classA, classB];
278
+ expect(runSingleRule(ast, "UsesStaticMethodOverload", false)).to.be.true;
279
+ });
280
+ });
281
+
282
+ describe("UsesDynamicMethodOverload", () => {
283
+ it("should detect a method with multiple equations (pattern matching)", () => {
284
+ const ast = [createMethod("fibonacci", 2)];
285
+ expect(runSingleRule(ast, "UsesDynamicMethodOverload", true)).to.be.true;
286
+ });
287
+
288
+ it("should ignore methods with a single equation", () => {
289
+ const ast = [createMethod("fibonacci", 1)];
290
+ expect(runSingleRule(ast, "UsesDynamicMethodOverload", false)).to.be.true;
291
+ });
292
+ });
293
+
294
+ describe("UsesTemplateMethod", () => {
295
+ it("should detect template method usage (call to undeclared method on self)", () => {
296
+ const declaredMethod = createMethod("abstractMethod", 1, true);
297
+ const sendToSelf = new Send(
298
+ new Self(),
299
+ createSymbol("abstractMethod"),
300
+ []
301
+ );
302
+ const templateMethod = createMethod("process", 1, false, sendToSelf);
303
+ const ast = [createClass("MyClass", [declaredMethod, templateMethod])];
304
+ expect(runSingleRule(ast, "UsesTemplateMethod", true)).to.be.true;
305
+ });
306
+
307
+ it("should NOT detect if calling a declared method on self", () => {
308
+ const declaredMethod = createMethod(
309
+ "declared",
310
+ 1,
311
+ false,
312
+ new Print(new StringPrimitive("This method is Declared"))
313
+ );
314
+ const sendToSelf = new Send(new Self(), createSymbol("declared"), []);
315
+ const method = createMethod("process", 1, false, sendToSelf);
316
+ const ast = [createClass("MyClass", [declaredMethod, method])];
317
+ expect(runSingleRule(ast, "UsesTemplateMethod", false)).to.be.true;
318
+ });
319
+ });
320
+ });