@sun-asterisk/sungen 1.0.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 (451) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +490 -0
  3. package/bin/sungen.js +12 -0
  4. package/dist/cli/commands/auto-tag-command.d.ts +8 -0
  5. package/dist/cli/commands/auto-tag-command.d.ts.map +1 -0
  6. package/dist/cli/commands/auto-tag-command.js +104 -0
  7. package/dist/cli/commands/auto-tag-command.js.map +1 -0
  8. package/dist/cli/index.d.ts +7 -0
  9. package/dist/cli/index.d.ts.map +1 -0
  10. package/dist/cli/index.js +196 -0
  11. package/dist/cli/index.js.map +1 -0
  12. package/dist/config/ai-providers.yaml +56 -0
  13. package/dist/config/config-loader.d.ts +51 -0
  14. package/dist/config/config-loader.d.ts.map +1 -0
  15. package/dist/config/config-loader.js +216 -0
  16. package/dist/config/config-loader.js.map +1 -0
  17. package/dist/config/config-schema.d.ts +121 -0
  18. package/dist/config/config-schema.d.ts.map +1 -0
  19. package/dist/config/config-schema.js +7 -0
  20. package/dist/config/config-schema.js.map +1 -0
  21. package/dist/config/default.config.yaml +101 -0
  22. package/dist/config/framework.config.yaml +52 -0
  23. package/dist/config/routes.yaml +31 -0
  24. package/dist/core/selector-base/annotation-handler.d.ts +45 -0
  25. package/dist/core/selector-base/annotation-handler.d.ts.map +1 -0
  26. package/dist/core/selector-base/annotation-handler.js +102 -0
  27. package/dist/core/selector-base/annotation-handler.js.map +1 -0
  28. package/dist/core/selector-base/base-generator.d.ts +49 -0
  29. package/dist/core/selector-base/base-generator.d.ts.map +1 -0
  30. package/dist/core/selector-base/base-generator.js +214 -0
  31. package/dist/core/selector-base/base-generator.js.map +1 -0
  32. package/dist/core/selector-base/gherkin-parser.d.ts +24 -0
  33. package/dist/core/selector-base/gherkin-parser.d.ts.map +1 -0
  34. package/dist/core/selector-base/gherkin-parser.js +42 -0
  35. package/dist/core/selector-base/gherkin-parser.js.map +1 -0
  36. package/dist/core/selector-mapper/priority-mapper.d.ts +74 -0
  37. package/dist/core/selector-mapper/priority-mapper.d.ts.map +1 -0
  38. package/dist/core/selector-mapper/priority-mapper.js +477 -0
  39. package/dist/core/selector-mapper/priority-mapper.js.map +1 -0
  40. package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts +91 -0
  41. package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts.map +1 -0
  42. package/dist/core/ui-scanner/heuristics/base-heuristic.js +175 -0
  43. package/dist/core/ui-scanner/heuristics/base-heuristic.js.map +1 -0
  44. package/dist/core/ui-scanner/react-scanner.d.ts +32 -0
  45. package/dist/core/ui-scanner/react-scanner.d.ts.map +1 -0
  46. package/dist/core/ui-scanner/react-scanner.js +163 -0
  47. package/dist/core/ui-scanner/react-scanner.js.map +1 -0
  48. package/dist/core/ui-scanner/scanner-interface.d.ts +94 -0
  49. package/dist/core/ui-scanner/scanner-interface.d.ts.map +1 -0
  50. package/dist/core/ui-scanner/scanner-interface.js +33 -0
  51. package/dist/core/ui-scanner/scanner-interface.js.map +1 -0
  52. package/dist/core/ui-scanner/strict-scanner.d.ts +81 -0
  53. package/dist/core/ui-scanner/strict-scanner.d.ts.map +1 -0
  54. package/dist/core/ui-scanner/strict-scanner.js +511 -0
  55. package/dist/core/ui-scanner/strict-scanner.js.map +1 -0
  56. package/dist/executor/playwright/playwright-generator.d.ts +33 -0
  57. package/dist/executor/playwright/playwright-generator.d.ts.map +1 -0
  58. package/dist/executor/playwright/playwright-generator.js +136 -0
  59. package/dist/executor/playwright/playwright-generator.js.map +1 -0
  60. package/dist/executor/test-generator.d.ts +63 -0
  61. package/dist/executor/test-generator.d.ts.map +1 -0
  62. package/dist/executor/test-generator.js +30 -0
  63. package/dist/executor/test-generator.js.map +1 -0
  64. package/dist/external/ai-provider.d.ts +60 -0
  65. package/dist/external/ai-provider.d.ts.map +1 -0
  66. package/dist/external/ai-provider.js +30 -0
  67. package/dist/external/ai-provider.js.map +1 -0
  68. package/dist/external/anthropic-provider.d.ts +29 -0
  69. package/dist/external/anthropic-provider.d.ts.map +1 -0
  70. package/dist/external/anthropic-provider.js +85 -0
  71. package/dist/external/anthropic-provider.js.map +1 -0
  72. package/dist/generators/cache/cache-manager.d.ts +66 -0
  73. package/dist/generators/cache/cache-manager.d.ts.map +1 -0
  74. package/dist/generators/cache/cache-manager.js +286 -0
  75. package/dist/generators/cache/cache-manager.js.map +1 -0
  76. package/dist/generators/cli.d.ts +7 -0
  77. package/dist/generators/cli.d.ts.map +1 -0
  78. package/dist/generators/cli.js +570 -0
  79. package/dist/generators/cli.js.map +1 -0
  80. package/dist/generators/dsl-writer/index.d.ts +33 -0
  81. package/dist/generators/dsl-writer/index.d.ts.map +1 -0
  82. package/dist/generators/dsl-writer/index.js +226 -0
  83. package/dist/generators/dsl-writer/index.js.map +1 -0
  84. package/dist/generators/gherkin-parser/index.d.ts +47 -0
  85. package/dist/generators/gherkin-parser/index.d.ts.map +1 -0
  86. package/dist/generators/gherkin-parser/index.js +149 -0
  87. package/dist/generators/gherkin-parser/index.js.map +1 -0
  88. package/dist/generators/gherkin-parser/selector-extractor.d.ts +37 -0
  89. package/dist/generators/gherkin-parser/selector-extractor.d.ts.map +1 -0
  90. package/dist/generators/gherkin-parser/selector-extractor.js +108 -0
  91. package/dist/generators/gherkin-parser/selector-extractor.js.map +1 -0
  92. package/dist/generators/scaffold-generator/index.d.ts +111 -0
  93. package/dist/generators/scaffold-generator/index.d.ts.map +1 -0
  94. package/dist/generators/scaffold-generator/index.js +408 -0
  95. package/dist/generators/scaffold-generator/index.js.map +1 -0
  96. package/dist/generators/selector-mapper/ai-mapper.d.ts +56 -0
  97. package/dist/generators/selector-mapper/ai-mapper.d.ts.map +1 -0
  98. package/dist/generators/selector-mapper/ai-mapper.js +457 -0
  99. package/dist/generators/selector-mapper/ai-mapper.js.map +1 -0
  100. package/dist/generators/selector-mapper/hybrid-mapper.d.ts +67 -0
  101. package/dist/generators/selector-mapper/hybrid-mapper.d.ts.map +1 -0
  102. package/dist/generators/selector-mapper/hybrid-mapper.js +349 -0
  103. package/dist/generators/selector-mapper/hybrid-mapper.js.map +1 -0
  104. package/dist/generators/selector-mapper/index.d.ts +8 -0
  105. package/dist/generators/selector-mapper/index.d.ts.map +1 -0
  106. package/dist/generators/selector-mapper/index.js +12 -0
  107. package/dist/generators/selector-mapper/index.js.map +1 -0
  108. package/dist/generators/selector-mapper/intelligent-mapper.d.ts +125 -0
  109. package/dist/generators/selector-mapper/intelligent-mapper.d.ts.map +1 -0
  110. package/dist/generators/selector-mapper/intelligent-mapper.js +391 -0
  111. package/dist/generators/selector-mapper/intelligent-mapper.js.map +1 -0
  112. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +49 -0
  113. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -0
  114. package/dist/generators/test-generator/adapters/adapter-interface.js +7 -0
  115. package/dist/generators/test-generator/adapters/adapter-interface.js.map +1 -0
  116. package/dist/generators/test-generator/adapters/adapter-registry.d.ts +29 -0
  117. package/dist/generators/test-generator/adapters/adapter-registry.d.ts.map +1 -0
  118. package/dist/generators/test-generator/adapters/adapter-registry.js +50 -0
  119. package/dist/generators/test-generator/adapters/adapter-registry.js.map +1 -0
  120. package/dist/generators/test-generator/adapters/index.d.ts +4 -0
  121. package/dist/generators/test-generator/adapters/index.d.ts.map +1 -0
  122. package/dist/generators/test-generator/adapters/index.js +13 -0
  123. package/dist/generators/test-generator/adapters/index.js.map +1 -0
  124. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +23 -0
  125. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -0
  126. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js +38 -0
  127. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -0
  128. package/dist/generators/test-generator/adapters/playwright/templates/before-each.hbs +8 -0
  129. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +5 -0
  130. package/dist/generators/test-generator/adapters/playwright/templates/scenario.hbs +8 -0
  131. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +1 -0
  132. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/clear-action.hbs +1 -0
  133. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-action.hbs +1 -0
  134. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/double-click-action.hbs +1 -0
  135. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -0
  136. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/hover-action.hbs +1 -0
  137. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/press-action.hbs +1 -0
  138. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -0
  139. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +1 -0
  140. package/dist/generators/test-generator/adapters/playwright/templates/steps/active-state-assertion.hbs +2 -0
  141. package/dist/generators/test-generator/adapters/playwright/templates/steps/ai-response-assertion-selector.hbs +5 -0
  142. package/dist/generators/test-generator/adapters/playwright/templates/steps/ai-response-assertion-simple.hbs +1 -0
  143. package/dist/generators/test-generator/adapters/playwright/templates/steps/application-running.hbs +1 -0
  144. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +1 -0
  145. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -0
  146. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +1 -0
  147. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -0
  148. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -0
  149. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -0
  150. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +1 -0
  151. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -0
  152. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +1 -0
  153. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-visible-assertion.hbs +1 -0
  154. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +1 -0
  155. package/dist/generators/test-generator/adapters/playwright/templates/steps/check-action.hbs +1 -0
  156. package/dist/generators/test-generator/adapters/playwright/templates/steps/checkbox.hbs +2 -0
  157. package/dist/generators/test-generator/adapters/playwright/templates/steps/checked-assertion.hbs +1 -0
  158. package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-action.hbs +1 -0
  159. package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-auth.hbs +6 -0
  160. package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-browser-state.hbs +6 -0
  161. package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-database.hbs +4 -0
  162. package/dist/generators/test-generator/adapters/playwright/templates/steps/clear.hbs +2 -0
  163. package/dist/generators/test-generator/adapters/playwright/templates/steps/click-action.hbs +1 -0
  164. package/dist/generators/test-generator/adapters/playwright/templates/steps/click.hbs +2 -0
  165. package/dist/generators/test-generator/adapters/playwright/templates/steps/contain-text-assertion.hbs +1 -0
  166. package/dist/generators/test-generator/adapters/playwright/templates/steps/contains-text-assertion.hbs +2 -0
  167. package/dist/generators/test-generator/adapters/playwright/templates/steps/count-assertion.hbs +1 -0
  168. package/dist/generators/test-generator/adapters/playwright/templates/steps/count-greater-than.hbs +3 -0
  169. package/dist/generators/test-generator/adapters/playwright/templates/steps/count-less-than.hbs +3 -0
  170. package/dist/generators/test-generator/adapters/playwright/templates/steps/disabled-assertion.hbs +2 -0
  171. package/dist/generators/test-generator/adapters/playwright/templates/steps/displayed-containing-text.hbs +3 -0
  172. package/dist/generators/test-generator/adapters/playwright/templates/steps/displayed-with-text.hbs +3 -0
  173. package/dist/generators/test-generator/adapters/playwright/templates/steps/double-click-action.hbs +1 -0
  174. package/dist/generators/test-generator/adapters/playwright/templates/steps/empty-assertion-advanced.hbs +3 -0
  175. package/dist/generators/test-generator/adapters/playwright/templates/steps/empty-assertion.hbs +2 -0
  176. package/dist/generators/test-generator/adapters/playwright/templates/steps/enabled-assertion.hbs +2 -0
  177. package/dist/generators/test-generator/adapters/playwright/templates/steps/error-message-assertion.hbs +3 -0
  178. package/dist/generators/test-generator/adapters/playwright/templates/steps/fill-action.hbs +1 -0
  179. package/dist/generators/test-generator/adapters/playwright/templates/steps/fill.hbs +2 -0
  180. package/dist/generators/test-generator/adapters/playwright/templates/steps/focused-assertion.hbs +1 -0
  181. package/dist/generators/test-generator/adapters/playwright/templates/steps/generic-message-assertion.hbs +3 -0
  182. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-attribute.hbs +2 -0
  183. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-class.hbs +2 -0
  184. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-count.hbs +2 -0
  185. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-image-src.hbs +3 -0
  186. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-link.hbs +3 -0
  187. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-placeholder.hbs +3 -0
  188. package/dist/generators/test-generator/adapters/playwright/templates/steps/has-value.hbs +2 -0
  189. package/dist/generators/test-generator/adapters/playwright/templates/steps/have-text-assertion.hbs +1 -0
  190. package/dist/generators/test-generator/adapters/playwright/templates/steps/hover-action.hbs +1 -0
  191. package/dist/generators/test-generator/adapters/playwright/templates/steps/html5-validation-check.hbs +4 -0
  192. package/dist/generators/test-generator/adapters/playwright/templates/steps/is-checked.hbs +2 -0
  193. package/dist/generators/test-generator/adapters/playwright/templates/steps/is-editable.hbs +2 -0
  194. package/dist/generators/test-generator/adapters/playwright/templates/steps/is-focused.hbs +2 -0
  195. package/dist/generators/test-generator/adapters/playwright/templates/steps/is-hidden.hbs +2 -0
  196. package/dist/generators/test-generator/adapters/playwright/templates/steps/is-unchecked.hbs +2 -0
  197. package/dist/generators/test-generator/adapters/playwright/templates/steps/locator.hbs +1 -0
  198. package/dist/generators/test-generator/adapters/playwright/templates/steps/login.hbs +8 -0
  199. package/dist/generators/test-generator/adapters/playwright/templates/steps/message-assertion-body.hbs +1 -0
  200. package/dist/generators/test-generator/adapters/playwright/templates/steps/message-assertion-selector.hbs +2 -0
  201. package/dist/generators/test-generator/adapters/playwright/templates/steps/message-count-assertion.hbs +3 -0
  202. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -0
  203. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +2 -0
  204. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element.hbs +1 -0
  205. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-timeout.hbs +1 -0
  206. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation.hbs +1 -0
  207. package/dist/generators/test-generator/adapters/playwright/templates/steps/not-checked-assertion.hbs +1 -0
  208. package/dist/generators/test-generator/adapters/playwright/templates/steps/not-visible-assertion.hbs +1 -0
  209. package/dist/generators/test-generator/adapters/playwright/templates/steps/not-visible.hbs +2 -0
  210. package/dist/generators/test-generator/adapters/playwright/templates/steps/notification-assertion.hbs +4 -0
  211. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +1 -0
  212. package/dist/generators/test-generator/adapters/playwright/templates/steps/press-action.hbs +1 -0
  213. package/dist/generators/test-generator/adapters/playwright/templates/steps/press-enter.hbs +2 -0
  214. package/dist/generators/test-generator/adapters/playwright/templates/steps/redirect-assertion.hbs +3 -0
  215. package/dist/generators/test-generator/adapters/playwright/templates/steps/route-assertion.hbs +2 -0
  216. package/dist/generators/test-generator/adapters/playwright/templates/steps/screen-navigation.hbs +3 -0
  217. package/dist/generators/test-generator/adapters/playwright/templates/steps/scroll-bottom-assertion.hbs +5 -0
  218. package/dist/generators/test-generator/adapters/playwright/templates/steps/select-action.hbs +1 -0
  219. package/dist/generators/test-generator/adapters/playwright/templates/steps/select.hbs +2 -0
  220. package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/application-running.hbs +1 -0
  221. package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-auth.hbs +6 -0
  222. package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-browser-state.hbs +6 -0
  223. package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-database.hbs +4 -0
  224. package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/user-login-todo.hbs +6 -0
  225. package/dist/generators/test-generator/adapters/playwright/templates/steps/text-matches-pattern.hbs +3 -0
  226. package/dist/generators/test-generator/adapters/playwright/templates/steps/uncheck-action.hbs +1 -0
  227. package/dist/generators/test-generator/adapters/playwright/templates/steps/user-login-todo.hbs +6 -0
  228. package/dist/generators/test-generator/adapters/playwright/templates/steps/visibility-assertion.hbs +2 -0
  229. package/dist/generators/test-generator/adapters/playwright/templates/steps/visible-assertion.hbs +1 -0
  230. package/dist/generators/test-generator/adapters/playwright/templates/steps/wait-for-element.hbs +1 -0
  231. package/dist/generators/test-generator/adapters/playwright/templates/steps/wait-timeout.hbs +1 -0
  232. package/dist/generators/test-generator/adapters/playwright/templates/steps/wait.hbs +1 -0
  233. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +19 -0
  234. package/dist/generators/test-generator/ai-step-mapper.d.ts +27 -0
  235. package/dist/generators/test-generator/ai-step-mapper.d.ts.map +1 -0
  236. package/dist/generators/test-generator/ai-step-mapper.js +204 -0
  237. package/dist/generators/test-generator/ai-step-mapper.js.map +1 -0
  238. package/dist/generators/test-generator/code-generator.d.ts +52 -0
  239. package/dist/generators/test-generator/code-generator.d.ts.map +1 -0
  240. package/dist/generators/test-generator/code-generator.js +191 -0
  241. package/dist/generators/test-generator/code-generator.js.map +1 -0
  242. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts +7 -0
  243. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -0
  244. package/dist/generators/test-generator/patterns/assertion-patterns.js +173 -0
  245. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -0
  246. package/dist/generators/test-generator/patterns/form-patterns.d.ts +8 -0
  247. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -0
  248. package/dist/generators/test-generator/patterns/form-patterns.js +110 -0
  249. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -0
  250. package/dist/generators/test-generator/patterns/index.d.ts +45 -0
  251. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -0
  252. package/dist/generators/test-generator/patterns/index.js +106 -0
  253. package/dist/generators/test-generator/patterns/index.js.map +1 -0
  254. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +7 -0
  255. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -0
  256. package/dist/generators/test-generator/patterns/interaction-patterns.js +100 -0
  257. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -0
  258. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +8 -0
  259. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -0
  260. package/dist/generators/test-generator/patterns/navigation-patterns.js +92 -0
  261. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -0
  262. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +7 -0
  263. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -0
  264. package/dist/generators/test-generator/patterns/setup-patterns.js +84 -0
  265. package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -0
  266. package/dist/generators/test-generator/patterns/types.d.ts +38 -0
  267. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -0
  268. package/dist/generators/test-generator/patterns/types.js +3 -0
  269. package/dist/generators/test-generator/patterns/types.js.map +1 -0
  270. package/dist/generators/test-generator/step-mapper-old.d.ts +180 -0
  271. package/dist/generators/test-generator/step-mapper-old.d.ts.map +1 -0
  272. package/dist/generators/test-generator/step-mapper-old.js +752 -0
  273. package/dist/generators/test-generator/step-mapper-old.js.map +1 -0
  274. package/dist/generators/test-generator/step-mapper-refactored.d.ts +47 -0
  275. package/dist/generators/test-generator/step-mapper-refactored.d.ts.map +1 -0
  276. package/dist/generators/test-generator/step-mapper-refactored.js +182 -0
  277. package/dist/generators/test-generator/step-mapper-refactored.js.map +1 -0
  278. package/dist/generators/test-generator/step-mapper.d.ts +66 -0
  279. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -0
  280. package/dist/generators/test-generator/step-mapper.js +248 -0
  281. package/dist/generators/test-generator/step-mapper.js.map +1 -0
  282. package/dist/generators/test-generator/template-engine.d.ts +33 -0
  283. package/dist/generators/test-generator/template-engine.d.ts.map +1 -0
  284. package/dist/generators/test-generator/template-engine.js +129 -0
  285. package/dist/generators/test-generator/template-engine.js.map +1 -0
  286. package/dist/generators/test-generator/utils/data-resolver.d.ts +39 -0
  287. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -0
  288. package/dist/generators/test-generator/utils/data-resolver.js +162 -0
  289. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -0
  290. package/dist/generators/test-generator/utils/path-inference.d.ts +49 -0
  291. package/dist/generators/test-generator/utils/path-inference.d.ts.map +1 -0
  292. package/dist/generators/test-generator/utils/path-inference.js +286 -0
  293. package/dist/generators/test-generator/utils/path-inference.js.map +1 -0
  294. package/dist/generators/test-generator/utils/selector-resolver.d.ts +93 -0
  295. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -0
  296. package/dist/generators/test-generator/utils/selector-resolver.js +408 -0
  297. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -0
  298. package/dist/generators/types.d.ts +118 -0
  299. package/dist/generators/types.d.ts.map +1 -0
  300. package/dist/generators/types.js +48 -0
  301. package/dist/generators/types.js.map +1 -0
  302. package/dist/generators/ui-model-builder/deep-scanner.d.ts +121 -0
  303. package/dist/generators/ui-model-builder/deep-scanner.d.ts.map +1 -0
  304. package/dist/generators/ui-model-builder/deep-scanner.js +1113 -0
  305. package/dist/generators/ui-model-builder/deep-scanner.js.map +1 -0
  306. package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts +110 -0
  307. package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts.map +1 -0
  308. package/dist/generators/ui-model-builder/enhanced-deep-scanner.js +608 -0
  309. package/dist/generators/ui-model-builder/enhanced-deep-scanner.js.map +1 -0
  310. package/dist/generators/ui-model-builder/react-scanner.d.ts +107 -0
  311. package/dist/generators/ui-model-builder/react-scanner.d.ts.map +1 -0
  312. package/dist/generators/ui-model-builder/react-scanner.js +797 -0
  313. package/dist/generators/ui-model-builder/react-scanner.js.map +1 -0
  314. package/dist/input/cli-adapter.d.ts +63 -0
  315. package/dist/input/cli-adapter.d.ts.map +1 -0
  316. package/dist/input/cli-adapter.js +173 -0
  317. package/dist/input/cli-adapter.js.map +1 -0
  318. package/dist/input/config-adapter.d.ts +25 -0
  319. package/dist/input/config-adapter.d.ts.map +1 -0
  320. package/dist/input/config-adapter.js +70 -0
  321. package/dist/input/config-adapter.js.map +1 -0
  322. package/dist/input/input-adapter.d.ts +28 -0
  323. package/dist/input/input-adapter.d.ts.map +1 -0
  324. package/dist/input/input-adapter.js +17 -0
  325. package/dist/input/input-adapter.js.map +1 -0
  326. package/dist/input/vscode-adapter.d.ts +62 -0
  327. package/dist/input/vscode-adapter.d.ts.map +1 -0
  328. package/dist/input/vscode-adapter.js +64 -0
  329. package/dist/input/vscode-adapter.js.map +1 -0
  330. package/dist/orchestrator/cache-manager.d.ts +37 -0
  331. package/dist/orchestrator/cache-manager.d.ts.map +1 -0
  332. package/dist/orchestrator/cache-manager.js +148 -0
  333. package/dist/orchestrator/cache-manager.js.map +1 -0
  334. package/dist/orchestrator/pipeline.d.ts +73 -0
  335. package/dist/orchestrator/pipeline.d.ts.map +1 -0
  336. package/dist/orchestrator/pipeline.js +607 -0
  337. package/dist/orchestrator/pipeline.js.map +1 -0
  338. package/dist/orchestrator/project-initializer.d.ts +51 -0
  339. package/dist/orchestrator/project-initializer.d.ts.map +1 -0
  340. package/dist/orchestrator/project-initializer.js +326 -0
  341. package/dist/orchestrator/project-initializer.js.map +1 -0
  342. package/dist/orchestrator/reporter.d.ts +15 -0
  343. package/dist/orchestrator/reporter.d.ts.map +1 -0
  344. package/dist/orchestrator/reporter.js +30 -0
  345. package/dist/orchestrator/reporter.js.map +1 -0
  346. package/dist/orchestrator/screen-manager.d.ts +47 -0
  347. package/dist/orchestrator/screen-manager.d.ts.map +1 -0
  348. package/dist/orchestrator/screen-manager.js +271 -0
  349. package/dist/orchestrator/screen-manager.js.map +1 -0
  350. package/dist/tools/auto-tagger.d.ts +107 -0
  351. package/dist/tools/auto-tagger.d.ts.map +1 -0
  352. package/dist/tools/auto-tagger.js +502 -0
  353. package/dist/tools/auto-tagger.js.map +1 -0
  354. package/package.json +73 -0
  355. package/src/cli/commands/auto-tag-command.ts +80 -0
  356. package/src/cli/index.ts +205 -0
  357. package/src/config/ai-providers.yaml +56 -0
  358. package/src/config/config-loader.ts +248 -0
  359. package/src/config/config-schema.ts +148 -0
  360. package/src/config/default.config.yaml +101 -0
  361. package/src/config/framework.config.yaml +52 -0
  362. package/src/config/routes.yaml +31 -0
  363. package/src/core/selector-base/annotation-handler.ts +127 -0
  364. package/src/core/selector-base/base-generator.ts +234 -0
  365. package/src/core/selector-base/gherkin-parser.ts +57 -0
  366. package/src/core/selector-mapper/priority-mapper.ts +607 -0
  367. package/src/core/ui-scanner/heuristics/base-heuristic.ts +216 -0
  368. package/src/core/ui-scanner/react-scanner.ts +156 -0
  369. package/src/core/ui-scanner/scanner-interface.ts +133 -0
  370. package/src/core/ui-scanner/strict-scanner.ts +629 -0
  371. package/src/executor/playwright/playwright-generator.ts +125 -0
  372. package/src/executor/test-generator.ts +90 -0
  373. package/src/external/ai-provider.ts +90 -0
  374. package/src/external/anthropic-provider.ts +114 -0
  375. package/src/generators/README.md +410 -0
  376. package/src/generators/cache/cache-manager.ts +322 -0
  377. package/src/generators/cli.ts +640 -0
  378. package/src/generators/dsl-writer/index.ts +253 -0
  379. package/src/generators/gherkin-parser/index.ts +155 -0
  380. package/src/generators/gherkin-parser/selector-extractor.ts +142 -0
  381. package/src/generators/scaffold-generator/index.ts +524 -0
  382. package/src/generators/selector-mapper/ai-mapper.ts +528 -0
  383. package/src/generators/selector-mapper/hybrid-mapper.ts +427 -0
  384. package/src/generators/selector-mapper/index.ts +10 -0
  385. package/src/generators/selector-mapper/intelligent-mapper.ts +530 -0
  386. package/src/generators/test-generator/adapters/adapter-interface.ts +49 -0
  387. package/src/generators/test-generator/adapters/adapter-registry.ts +56 -0
  388. package/src/generators/test-generator/adapters/index.ts +9 -0
  389. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +40 -0
  390. package/src/generators/test-generator/adapters/playwright/templates/before-each.hbs +8 -0
  391. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +5 -0
  392. package/src/generators/test-generator/adapters/playwright/templates/scenario.hbs +8 -0
  393. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +1 -0
  394. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/clear-action.hbs +1 -0
  395. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-action.hbs +1 -0
  396. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/double-click-action.hbs +1 -0
  397. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -0
  398. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/hover-action.hbs +1 -0
  399. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/press-action.hbs +1 -0
  400. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -0
  401. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +1 -0
  402. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +1 -0
  403. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -0
  404. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +1 -0
  405. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -0
  406. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -0
  407. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -0
  408. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +1 -0
  409. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -0
  410. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +1 -0
  411. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-visible-assertion.hbs +1 -0
  412. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +1 -0
  413. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -0
  414. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +2 -0
  415. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element.hbs +1 -0
  416. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-timeout.hbs +1 -0
  417. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +1 -0
  418. package/src/generators/test-generator/adapters/playwright/templates/steps/setup/application-running.hbs +1 -0
  419. package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-auth.hbs +6 -0
  420. package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-browser-state.hbs +6 -0
  421. package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-database.hbs +4 -0
  422. package/src/generators/test-generator/adapters/playwright/templates/steps/setup/user-login-todo.hbs +6 -0
  423. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +19 -0
  424. package/src/generators/test-generator/ai-step-mapper.ts +224 -0
  425. package/src/generators/test-generator/code-generator.ts +235 -0
  426. package/src/generators/test-generator/patterns/assertion-patterns.ts +183 -0
  427. package/src/generators/test-generator/patterns/form-patterns.ts +124 -0
  428. package/src/generators/test-generator/patterns/index.ts +97 -0
  429. package/src/generators/test-generator/patterns/interaction-patterns.ts +119 -0
  430. package/src/generators/test-generator/patterns/navigation-patterns.ts +110 -0
  431. package/src/generators/test-generator/patterns/setup-patterns.ts +94 -0
  432. package/src/generators/test-generator/patterns/types.ts +41 -0
  433. package/src/generators/test-generator/step-mapper.ts +254 -0
  434. package/src/generators/test-generator/template-engine.ts +160 -0
  435. package/src/generators/test-generator/utils/data-resolver.ts +147 -0
  436. package/src/generators/test-generator/utils/path-inference.ts +344 -0
  437. package/src/generators/test-generator/utils/selector-resolver.ts +480 -0
  438. package/src/generators/types.ts +226 -0
  439. package/src/generators/ui-model-builder/deep-scanner.ts +1244 -0
  440. package/src/generators/ui-model-builder/enhanced-deep-scanner.ts +731 -0
  441. package/src/generators/ui-model-builder/react-scanner.ts +959 -0
  442. package/src/input/cli-adapter.ts +185 -0
  443. package/src/input/config-adapter.ts +71 -0
  444. package/src/input/input-adapter.ts +32 -0
  445. package/src/input/vscode-adapter.ts +90 -0
  446. package/src/orchestrator/cache-manager.ts +138 -0
  447. package/src/orchestrator/pipeline.ts +713 -0
  448. package/src/orchestrator/project-initializer.ts +315 -0
  449. package/src/orchestrator/reporter.ts +36 -0
  450. package/src/orchestrator/screen-manager.ts +268 -0
  451. package/src/tools/auto-tagger.ts +572 -0
@@ -0,0 +1,713 @@
1
+ /**
2
+ * Pipeline Orchestrator
3
+ * Coordinates all phases of test generation: UI Scan → Selector Mapping → Code Generation
4
+ */
5
+
6
+ import * as path from 'path';
7
+ import * as fs from 'fs';
8
+ import yaml from 'yaml';
9
+ import { RuntimeConfig } from '../config/config-schema';
10
+ import { ScannerFactory, UIModel } from '../core/ui-scanner/scanner-interface';
11
+ import { SelectorBaseGenerator, SelectorBase } from '../core/selector-base/base-generator';
12
+ import { AIProviderFactory } from '../external/ai-provider';
13
+ import { TestGeneratorFactory, GeneratedTest } from '../executor/test-generator';
14
+ import { CacheManager } from './cache-manager';
15
+ import { Reporter } from './reporter';
16
+
17
+ export class Pipeline {
18
+ private config: RuntimeConfig;
19
+ private cacheManager: CacheManager;
20
+ private reporter: Reporter;
21
+
22
+ constructor(config: RuntimeConfig) {
23
+ this.config = config;
24
+ this.cacheManager = new CacheManager(config);
25
+ this.reporter = new Reporter(config);
26
+ }
27
+
28
+ /**
29
+ * Run UI discovery phase
30
+ * Scans React components and generates UI model
31
+ */
32
+ async runDiscovery(screenName: string): Promise<UIModel> {
33
+ const strictMode = this.config.scanner.strictMode || false;
34
+ const mode = strictMode ? 'strict' : 'standard';
35
+
36
+ // Debug logging
37
+ if (this.config.verbose) {
38
+ console.log(`[DEBUG] strictMode value: ${this.config.scanner.strictMode}`);
39
+ console.log(`[DEBUG] scanner config:`, JSON.stringify(this.config.scanner, null, 2));
40
+ }
41
+
42
+ console.log(`\n🔍 Discovering UI elements for screen: ${screenName} (${mode} mode)\n`);
43
+
44
+ // Check cache
45
+ if (!this.config.force && this.config.cache.enabled) {
46
+ const cached = await this.cacheManager.getUIModel(screenName);
47
+ if (cached) {
48
+ console.log(`✓ Loaded from cache (${cached.elements.length} elements)\n`);
49
+ return cached;
50
+ }
51
+ }
52
+
53
+ let uiModel: UIModel;
54
+
55
+ // Use StrictScanner if strict mode enabled (v3.1)
56
+ if (strictMode) {
57
+ const { StrictScanner } = require('../core/ui-scanner/strict-scanner');
58
+
59
+ const strictConfig = {
60
+ sourceRoot: this.config.paths.sourceRoot,
61
+ projectRoot: process.cwd(),
62
+ strictMode: true,
63
+ filterRules: this.config.scanner.filterRules || {
64
+ allowedTags: ['input', 'button', 'a', 'select', 'textarea'],
65
+ requireAttributes: ['data-testid', 'role'],
66
+ allowGenericWithId: true,
67
+ },
68
+ verbose: this.config.verbose || false,
69
+ };
70
+
71
+ const strictScanner = new StrictScanner(strictConfig);
72
+ const strictResult = await strictScanner.scan(screenName);
73
+
74
+ // Convert StrictScanResult to UIModel format
75
+ uiModel = {
76
+ screen: strictResult.screen,
77
+ timestamp: strictResult.timestamp,
78
+ framework: strictResult.framework,
79
+ sourceFiles: strictResult.sourceFiles,
80
+ elements: strictResult.elements.map(el => ({
81
+ id: el.logicalName,
82
+ type: el.tag as any,
83
+ selector: el.primaryLocator,
84
+ label: el.label,
85
+ placeholder: el.placeholder,
86
+ role: el.role,
87
+ testId: el.props['data-testid'],
88
+ context: {
89
+ component: path.basename(el.sourceFile),
90
+ },
91
+ })),
92
+ stats: {
93
+ totalComponents: 1,
94
+ totalElements: strictResult.stats.totalIncluded,
95
+ maxDepth: 0,
96
+ scanDuration: strictResult.stats.scanDuration,
97
+ filesScanned: strictResult.sourceFiles.length,
98
+ },
99
+ };
100
+
101
+ console.log(` Filtered: ${strictResult.stats.totalFiltered} elements (${strictResult.stats.filterRate.toFixed(1)}%)`);
102
+ console.log(` Direct ID: ${strictResult.stats.directIdMatches} elements`);
103
+ } else {
104
+ // Use standard scanner (old approach)
105
+ const scanner = ScannerFactory.create(this.config.scanner.framework, this.config);
106
+ uiModel = await scanner.scan(screenName, this.config);
107
+ }
108
+
109
+ // Save UI model
110
+ await this.saveUIModel(uiModel);
111
+
112
+ // Cache UI model
113
+ if (this.config.cache.enabled) {
114
+ await this.cacheManager.saveUIModel(screenName, uiModel);
115
+ }
116
+
117
+ console.log(`✓ Discovered ${uiModel.elements.length} elements in ${uiModel.stats.scanDuration}ms\n`);
118
+
119
+ return uiModel;
120
+ }
121
+
122
+ /**
123
+ * Run mapping for single screen or all screens
124
+ */
125
+ async runMapping(screenName?: string): Promise<void> {
126
+ if (screenName) {
127
+ // Map specific screen
128
+ await this.runSelectorMapping(screenName);
129
+ } else {
130
+ // Map all screens discovered from Gherkin
131
+ const screens = await this.discoverScreensFromGherkin();
132
+
133
+ if (screens.length === 0) {
134
+ console.warn('⚠️ No screens found in Gherkin features');
135
+ return;
136
+ }
137
+
138
+ console.log(`📋 Found ${screens.length} screen(s): ${screens.join(', ')}\n`);
139
+
140
+ for (const screen of screens) {
141
+ await this.runSelectorMapping(screen);
142
+ }
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Run selector mapping phase
148
+ * Generates selector base and maps with AI or Hybrid Mapper
149
+ */
150
+ async runSelectorMapping(screenName: string): Promise<SelectorBase> {
151
+ const mode = this.config.selectorMapping.mode || 'hybrid';
152
+ console.log(`\n🎯 Mapping selectors for screen: ${screenName} (mode: ${mode})\n`);
153
+
154
+ // Check cache
155
+ if (!this.config.force && this.config.cache.enabled) {
156
+ const cached = await this.cacheManager.getSelectors(screenName);
157
+ if (cached) {
158
+ console.log(`✓ Loaded from cache (${Object.keys(cached.elements).length} selectors)\n`);
159
+ return cached;
160
+ }
161
+ }
162
+
163
+ // Generate selector base from Gherkin
164
+ const baseGenerator = new SelectorBaseGenerator(this.config);
165
+ const selectorBase = await baseGenerator.generate(screenName);
166
+
167
+ console.log(` Generated selector base with ${selectorBase.metadata.totalElements} elements`);
168
+
169
+ // Load UI model (needed for mapping)
170
+ const uiModel = await this.loadUIModel(screenName);
171
+ if (!uiModel) {
172
+ throw new Error(`UI model not found for screen: ${screenName}. Run discovery first.`);
173
+ }
174
+
175
+ // Map selectors based on mode/strategy
176
+ let mappedSelectors: SelectorBase;
177
+
178
+ // v3.1: Use PriorityMapper if strategy is priority-waterfall
179
+ const strategy = this.config.selectorMapping.strategy;
180
+ if (strategy === 'priority-waterfall') {
181
+ const { PriorityMapper } = require('../core/selector-mapper/priority-mapper');
182
+
183
+ const mapperConfig = {
184
+ strategy: 'priority-waterfall' as const,
185
+ priorities: this.config.selectorMapping.priorities || ['direct-id', 'accessibility', 'heuristic-ai'],
186
+ confidenceThreshold: this.config.selectorMapping.confidenceThreshold || 0.5,
187
+ aiProvider: this.config.selectorMapping.aiProvider,
188
+ model: this.config.selectorMapping.model,
189
+ };
190
+
191
+ const priorityMapper = new PriorityMapper(mapperConfig);
192
+
193
+ // Extract element IDs from selector base
194
+ const elementIds = Object.keys(selectorBase.elements);
195
+
196
+ // Convert UI model to StrictScanResult format (compatible)
197
+ const strictUIModel = {
198
+ screen: uiModel.screen,
199
+ timestamp: uiModel.timestamp,
200
+ framework: uiModel.framework,
201
+ sourceFiles: uiModel.sourceFiles,
202
+ elements: uiModel.elements.map(el => {
203
+ // Check if selector contains data-testid
204
+ const hasTestId = el.selector.includes('data-testid');
205
+
206
+ return {
207
+ logicalName: el.id,
208
+ primaryLocator: el.selector,
209
+ fallbackStrategy: el.selector,
210
+ tag: el.type,
211
+ elementType: el.type,
212
+ discoveryMethod: hasTestId ? 'direct-id' : 'heuristic' as const,
213
+ confidence: hasTestId ? 0.95 : 0.5,
214
+ sourceFile: uiModel.sourceFiles[0] || '',
215
+ label: el.label,
216
+ placeholder: el.placeholder,
217
+ ariaLabel: undefined,
218
+ role: el.role,
219
+ text: undefined,
220
+ props: {},
221
+ };
222
+ }),
223
+ stats: {
224
+ totalScanned: uiModel.stats.totalElements,
225
+ totalFiltered: 0,
226
+ totalIncluded: uiModel.stats.totalElements,
227
+ filterRate: 0,
228
+ directIdMatches: uiModel.elements.filter(el => el.selector.includes('data-testid')).length,
229
+ accessibilityMatches: 0,
230
+ heuristicMatches: uiModel.elements.filter(el => !el.selector.includes('data-testid')).length,
231
+ scanDuration: uiModel.stats.scanDuration,
232
+ },
233
+ };
234
+
235
+ // Map elements using priority waterfall
236
+ const mappingRequests = elementIds.map(id => ({
237
+ elementId: `[${screenName}.${id}]`,
238
+ screenName,
239
+ uiModel: strictUIModel,
240
+ }));
241
+
242
+ const results = await priorityMapper.mapElements(mappingRequests);
243
+
244
+ // Convert results back to SelectorBase format
245
+ mappedSelectors = { ...selectorBase };
246
+ results.forEach(result => {
247
+ // result.elementId is already just the element name (e.g., "email-input")
248
+ const elementId = result.elementId;
249
+
250
+ if (this.config.verbose) {
251
+ console.log(`[DEBUG] Mapping result: ${result.elementId} → ${result.selector} (confidence: ${result.confidence})`);
252
+ console.log(`[DEBUG] Extracted elementId: ${elementId}`);
253
+ }
254
+
255
+ if (elementId && result.confidence > 0 && selectorBase.elements[elementId]) {
256
+ mappedSelectors.elements[elementId] = {
257
+ ...selectorBase.elements[elementId],
258
+ selector: result.selector,
259
+ };
260
+
261
+ if (this.config.verbose) {
262
+ console.log(`[DEBUG] Updated selector for ${elementId}: ${mappedSelectors.elements[elementId].selector}`);
263
+ }
264
+ }
265
+ });
266
+
267
+ // Show statistics
268
+ const stats = priorityMapper.getStats();
269
+ console.log(`\n📊 Priority Mapping Statistics:`);
270
+ console.log(` Total elements: ${stats.totalMappings}`);
271
+ console.log(` Successful: ${stats.successfulMappings} (${((stats.successfulMappings / stats.totalMappings) * 100).toFixed(1)}%)`);
272
+ console.log(` Direct ID: ${stats.directIdMatches} (${((stats.directIdMatches / stats.totalMappings) * 100).toFixed(1)}%)`);
273
+ console.log(` Accessibility: ${stats.accessibilityMatches}`);
274
+ console.log(` Heuristic: ${stats.heuristicMatches}`);
275
+ console.log(` AI: ${stats.aiMatches}`);
276
+ console.log(` Avg time: ${stats.averageMappingTime.toFixed(2)}ms`);
277
+ console.log(` Cost: $${stats.estimatedCost.toFixed(4)}\n`);
278
+ } else if (mode === 'hybrid') {
279
+ // Use Hybrid Mapper (heuristics + AI fallback)
280
+ const { HybridMapper } = require('../generators/selector-mapper/hybrid-mapper');
281
+ const hybridMapper = new HybridMapper({
282
+ provider: this.config.selectorMapping.aiProvider,
283
+ model: this.config.selectorMapping.model,
284
+ apiKey: process.env[this.config.apis.anthropic.apiKeyEnv],
285
+ heuristicFirst: this.config.selectorMapping.heuristicFirst,
286
+ minHeuristicConfidence: this.config.selectorMapping.minHeuristicConfidence,
287
+ verbose: this.config.verbose
288
+ });
289
+
290
+ // Extract element IDs from selector base
291
+ const elementIds = Object.keys(selectorBase.elements).map(id => `[${screenName}.${id}]`);
292
+
293
+ // Map using hybrid approach
294
+ const selectorDSL = await hybridMapper.mapSelectors(uiModel, elementIds);
295
+
296
+ // Convert SelectorDSL back to SelectorBase format
297
+ // selectorDSL is a flat object { elementId: SelectorEntry }
298
+ mappedSelectors = {
299
+ ...selectorBase,
300
+ elements: selectorDSL
301
+ };
302
+
303
+ // Show statistics if verbose
304
+ if (this.config.verbose) {
305
+ const stats = hybridMapper.getStats();
306
+ console.log(`\n📊 Mapping Statistics:`);
307
+ console.log(` Total elements: ${stats.total}`);
308
+ console.log(` Heuristic matches: ${stats.heuristicMatches} (${stats.heuristicSuccessRate.toFixed(1)}%)`);
309
+ console.log(` AI fallback: ${stats.aiMatches} (${(100 - stats.heuristicSuccessRate).toFixed(1)}%)`);
310
+ console.log(` Estimated cost: $${stats.estimatedCost.toFixed(4)}`);
311
+ console.log(` Estimated time: ${stats.estimatedTime}ms`);
312
+ console.log(` Savings vs AI-only: ~${(90 * stats.heuristicSuccessRate / 100).toFixed(0)}%\n`);
313
+ }
314
+ } else if (mode === 'ai-only') {
315
+ // Use AI mapper only (legacy behavior)
316
+ const aiProvider = AIProviderFactory.create(this.config.selectorMapping.aiProvider, this.config);
317
+ mappedSelectors = await aiProvider.mapSelectors(uiModel, selectorBase, this.config);
318
+ } else if (mode === 'heuristic-only') {
319
+ // Use heuristics only (no AI fallback)
320
+ const { HeuristicMatcher } = require('../generators/selector-mapper/hybrid-mapper');
321
+
322
+ mappedSelectors = { ...selectorBase };
323
+
324
+ for (const [elementId, element] of Object.entries(selectorBase.elements)) {
325
+ const match = HeuristicMatcher.match(elementId, uiModel.elements);
326
+
327
+ if (match.confidence > 0) {
328
+ mappedSelectors.elements[elementId] = {
329
+ ...element,
330
+ selector: match.selector
331
+ };
332
+ } else {
333
+ console.warn(` ⚠️ No heuristic match for: ${elementId}`);
334
+ }
335
+ }
336
+ } else {
337
+ throw new Error(`Invalid selector mapping mode: ${mode}`);
338
+ }
339
+
340
+ // Apply overrides
341
+ const finalSelectors = await this.applyOverrides(screenName, mappedSelectors);
342
+
343
+ // Save selectors
344
+ await baseGenerator.save(finalSelectors);
345
+
346
+ // Cache selectors
347
+ if (this.config.cache.enabled) {
348
+ await this.cacheManager.saveSelectors(screenName, finalSelectors);
349
+ }
350
+
351
+ console.log(`✓ Mapped ${Object.keys(finalSelectors.elements).length} selectors\n`);
352
+
353
+ return finalSelectors;
354
+ }
355
+
356
+ /**
357
+ * Run test generation phase
358
+ * Generates Playwright test scripts from Gherkin
359
+ */
360
+ async runTestGeneration(screenName?: string): Promise<GeneratedTest[]> {
361
+ const header = screenName ? `Generating tests: ${screenName}` : 'Generating tests';
362
+ console.log(`\n${header}\n`);
363
+
364
+ // Find all feature files from both old and new structure
365
+ const featureFiles = screenName
366
+ ? this.findFeatureFilesForScreen(screenName)
367
+ : this.findAllFeatureFiles();
368
+
369
+ if (screenName && featureFiles.length === 0) {
370
+ console.error(`No feature files found for screen: ${screenName}`);
371
+ console.error(`Looked in:`);
372
+ console.error(` - qa/screens/${screenName}/features/`);
373
+ console.error(` - qa/features/${screenName}.feature`);
374
+ process.exit(1);
375
+ }
376
+
377
+ // Parse features
378
+ const { GherkinParser } = require('../core/selector-base/gherkin-parser');
379
+ const parser = new GherkinParser(this.config);
380
+ const features = await parser.parseAll(featureFiles);
381
+
382
+ // Validate selector files before generation
383
+ if (screenName) {
384
+ const validation = this.validateSelectorFiles(screenName, features);
385
+ const missing = validation.filter(v => !v.selectorExists);
386
+
387
+ if (missing.length > 0) {
388
+ console.log(`\nMissing selector files:\n`);
389
+ missing.forEach(v => {
390
+ console.log(` ✗ ${v.featureName}.feature → selector file not found`);
391
+ });
392
+ console.log(`\nRun: sungen map --screen ${screenName}\n`);
393
+ process.exit(1);
394
+ }
395
+ }
396
+
397
+ // Generate tests
398
+ const generator = TestGeneratorFactory.create(this.config.testGenerator.framework, this.config);
399
+ const results: GeneratedTest[] = [];
400
+
401
+ for (const feature of features) {
402
+ // Load selectors and test data
403
+ const selectors = {}; // TODO: Load from selector files
404
+ const testData = {}; // TODO: Load from test-data files
405
+
406
+ const result = await generator.generate(feature, selectors, testData, this.config);
407
+ results.push(result);
408
+
409
+ // Display per-file result
410
+ const fileName = path.basename(result.outputPath);
411
+ const relativePath = path.relative(process.cwd(), result.outputPath);
412
+ const stepInfo = result.stats?.totalSteps ? ` (${result.stats.totalSteps} steps)` : '';
413
+
414
+ console.log(`✓ Generated ${fileName}`);
415
+ console.log(` → ${relativePath}${stepInfo}\n`);
416
+ }
417
+
418
+ // Generate report
419
+ await this.reporter.generate(results);
420
+
421
+ // Display next step
422
+ console.log(`Next step: npx playwright test`);
423
+
424
+ return results;
425
+ }
426
+
427
+ /**
428
+ * Validate that selector files exist for all features
429
+ */
430
+ private validateSelectorFiles(screenName: string, features: any[]): Array<{
431
+ featureName: string;
432
+ sourceFile?: string;
433
+ selectorExists: boolean;
434
+ selectorPath: string | null;
435
+ }> {
436
+ const results: Array<{
437
+ featureName: string;
438
+ sourceFile?: string;
439
+ selectorExists: boolean;
440
+ selectorPath: string | null;
441
+ }> = [];
442
+
443
+ for (const feature of features) {
444
+ const featureName = this.extractFeatureName(feature);
445
+ const selectorPath = this.findSelectorFile(screenName, featureName);
446
+
447
+ results.push({
448
+ featureName,
449
+ sourceFile: feature.sourceFile,
450
+ selectorExists: selectorPath !== null,
451
+ selectorPath,
452
+ });
453
+ }
454
+
455
+ return results;
456
+ }
457
+
458
+ /**
459
+ * Extract feature name from parsed feature
460
+ */
461
+ private extractFeatureName(feature: any): string {
462
+ if (feature.sourceFile) {
463
+ return path.basename(feature.sourceFile, path.extname(feature.sourceFile));
464
+ }
465
+ // Fallback to feature name
466
+ return feature.name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
467
+ }
468
+
469
+ /**
470
+ * Find selector file path for a feature
471
+ * Searches both old and new directory structures
472
+ */
473
+ private findSelectorFile(screenName: string, featureName: string): string | null {
474
+ const possiblePaths: string[] = [];
475
+
476
+ // New structure: qa/screens/{screen}/selectors/{feature}.yaml
477
+ const newStructurePath = path.join(
478
+ process.cwd(),
479
+ 'qa',
480
+ 'screens',
481
+ screenName,
482
+ 'selectors',
483
+ `${featureName}.yaml`
484
+ );
485
+ possiblePaths.push(newStructurePath);
486
+
487
+ // Old structure: qa/selectors/screens/{feature}.yaml
488
+ const oldStructurePath = path.join(
489
+ process.cwd(),
490
+ 'qa',
491
+ 'selectors',
492
+ 'screens',
493
+ `${featureName}.yaml`
494
+ );
495
+ possiblePaths.push(oldStructurePath);
496
+
497
+ // Find first existing file
498
+ for (const p of possiblePaths) {
499
+ if (fs.existsSync(p)) {
500
+ return p;
501
+ }
502
+ }
503
+
504
+ return null;
505
+ }
506
+
507
+ /**
508
+ * Run full pipeline
509
+ * Discovery → Selector Mapping → Test Generation
510
+ */
511
+ async runFull(screens?: string[]): Promise<void> {
512
+ console.log('\n🚀 Running full pipeline\n');
513
+
514
+ // Discover screens if not specified
515
+ if (!screens || screens.length === 0) {
516
+ screens = await this.discoverScreensFromGherkin();
517
+ console.log(` Found ${screens.length} screen(s) in Gherkin: ${screens.join(', ')}\n`);
518
+ }
519
+
520
+ // Phase 1: UI Discovery
521
+ console.log('📍 Phase 1: UI Discovery\n');
522
+ for (const screen of screens) {
523
+ await this.runDiscovery(screen);
524
+ }
525
+
526
+ // Phase 2: Selector Mapping
527
+ console.log('📍 Phase 2: Selector Mapping\n');
528
+ for (const screen of screens) {
529
+ await this.runSelectorMapping(screen);
530
+ }
531
+
532
+ // Phase 3: Test Generation
533
+ console.log('📍 Phase 3: Test Generation\n');
534
+ await this.runTestGeneration();
535
+
536
+ console.log('✅ Full pipeline completed!\n');
537
+ }
538
+
539
+ /**
540
+ * Clear all caches
541
+ */
542
+ async clearCache(): Promise<void> {
543
+ await this.cacheManager.clear();
544
+ console.log('✓ Cache cleared\n');
545
+ }
546
+
547
+ // ============================================================================
548
+ // Helper Methods
549
+ // ============================================================================
550
+
551
+ private async saveUIModel(uiModel: UIModel): Promise<void> {
552
+ const outputDir = path.join(this.config.paths.uiModelsDir, 'screens');
553
+ if (!fs.existsSync(outputDir)) {
554
+ fs.mkdirSync(outputDir, { recursive: true });
555
+ }
556
+
557
+ const outputPath = path.join(outputDir, `${uiModel.screen}.json`);
558
+ fs.writeFileSync(outputPath, JSON.stringify(uiModel, null, 2), 'utf-8');
559
+ }
560
+
561
+ private async loadUIModel(screenName: string): Promise<UIModel | null> {
562
+ const filePath = path.join(this.config.paths.uiModelsDir, 'screens', `${screenName}.json`);
563
+
564
+ if (!fs.existsSync(filePath)) {
565
+ return null;
566
+ }
567
+
568
+ try {
569
+ const content = fs.readFileSync(filePath, 'utf-8');
570
+ return JSON.parse(content);
571
+ } catch {
572
+ return null;
573
+ }
574
+ }
575
+
576
+ private async applyOverrides(screenName: string, selectors: SelectorBase): Promise<SelectorBase> {
577
+ const overridePath = path.join(
578
+ this.config.paths.selectorsDir,
579
+ 'screens',
580
+ `${screenName}.override.yaml`
581
+ );
582
+
583
+ if (!fs.existsSync(overridePath)) {
584
+ return selectors;
585
+ }
586
+
587
+ try {
588
+ const content = fs.readFileSync(overridePath, 'utf-8');
589
+ const overrides = yaml.parse(content);
590
+
591
+ // Merge overrides (override values replace AI values)
592
+ if (overrides.elements) {
593
+ for (const [elementId, overrideValue] of Object.entries(overrides.elements)) {
594
+ if (selectors.elements[elementId]) {
595
+ Object.assign(selectors.elements[elementId], overrideValue);
596
+ }
597
+ }
598
+ }
599
+
600
+ if (this.config.verbose) {
601
+ console.log(` Applied overrides from ${path.basename(overridePath)}`);
602
+ }
603
+ } catch (error) {
604
+ console.warn(` Warning: Failed to apply overrides: ${error}`);
605
+ }
606
+
607
+ return selectors;
608
+ }
609
+
610
+ private findFeatureFiles(dir: string): string[] {
611
+ const files: string[] = [];
612
+
613
+ if (!fs.existsSync(dir)) {
614
+ return files;
615
+ }
616
+
617
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
618
+
619
+ for (const entry of entries) {
620
+ const fullPath = path.join(dir, entry.name);
621
+
622
+ if (entry.isDirectory()) {
623
+ files.push(...this.findFeatureFiles(fullPath));
624
+ } else if (entry.isFile() && entry.name.endsWith('.feature')) {
625
+ files.push(fullPath);
626
+ }
627
+ }
628
+
629
+ return files;
630
+ }
631
+
632
+ /**
633
+ * Find feature files for a specific screen
634
+ */
635
+ private findFeatureFilesForScreen(screenName: string): string[] {
636
+ const files: string[] = [];
637
+
638
+ // New structure: qa/screens/<screenName>/features/
639
+ const screenFeaturesDir = path.join(
640
+ path.dirname(this.config.paths.featuresDir),
641
+ 'screens',
642
+ screenName,
643
+ 'features'
644
+ );
645
+
646
+ if (fs.existsSync(screenFeaturesDir)) {
647
+ files.push(...this.findFeatureFiles(screenFeaturesDir));
648
+ }
649
+
650
+ // Old structure: qa/features/<screenName>.feature (by convention)
651
+ const oldFeaturesDir = this.config.paths.featuresDir;
652
+ if (fs.existsSync(oldFeaturesDir)) {
653
+ const screenFeaturePath = path.join(oldFeaturesDir, `${screenName}.feature`);
654
+ if (fs.existsSync(screenFeaturePath)) {
655
+ files.push(screenFeaturePath);
656
+ }
657
+ }
658
+
659
+ return files;
660
+ }
661
+
662
+ /**
663
+ * Find all feature files from both old and new folder structures
664
+ * Old: qa/features/*.feature
665
+ * New: qa/screens/*/features/*.feature
666
+ */
667
+ private findAllFeatureFiles(): string[] {
668
+ const allFiles: string[] = [];
669
+
670
+ // Old structure: qa/features/
671
+ const oldFeaturesDir = this.config.paths.featuresDir;
672
+ allFiles.push(...this.findFeatureFiles(oldFeaturesDir));
673
+
674
+ // New structure: qa/screens/*/features/
675
+ const screensDir = path.join(path.dirname(oldFeaturesDir), 'screens');
676
+ if (fs.existsSync(screensDir)) {
677
+ const screenDirs = fs.readdirSync(screensDir, { withFileTypes: true })
678
+ .filter(entry => entry.isDirectory())
679
+ .map(entry => entry.name);
680
+
681
+ for (const screenName of screenDirs) {
682
+ const screenFeaturesDir = path.join(screensDir, screenName, 'features');
683
+ allFiles.push(...this.findFeatureFiles(screenFeaturesDir));
684
+ }
685
+ }
686
+
687
+ return allFiles;
688
+ }
689
+
690
+ /**
691
+ * Discover all unique screens referenced in Gherkin features
692
+ */
693
+ private async discoverScreensFromGherkin(): Promise<string[]> {
694
+ const featureFiles = this.findAllFeatureFiles();
695
+ const screens = new Set<string>();
696
+
697
+ // Regex to match [screen.element] pattern
698
+ const selectorPattern = /\[([a-z0-9-]+)\.([a-z0-9-]+)\]/gi;
699
+
700
+ for (const featureFile of featureFiles) {
701
+ const content = fs.readFileSync(featureFile, 'utf-8');
702
+
703
+ // Extract all [screen.element] references
704
+ let match;
705
+ while ((match = selectorPattern.exec(content)) !== null) {
706
+ const screenName = match[1];
707
+ screens.add(screenName);
708
+ }
709
+ }
710
+
711
+ return Array.from(screens).sort();
712
+ }
713
+ }