@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,480 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import yaml from 'yaml';
4
+
5
+ // New structured selector format
6
+ interface SelectorEntry {
7
+ selector?: string; // CSS selector (optional, empty string means use type/value)
8
+ type?: 'placeholder' | 'role' | 'testid' | 'label' | 'text'; // Locator strategy
9
+ value?: string; // Natural language value for the locator (e.g., 'button', 'link' for role)
10
+ name?: string; // Accessible name for role-based selectors (e.g., 'Login', 'Submit')
11
+ nth?: number; // Element index (0 = no index, 1+ = append .nth())
12
+ }
13
+
14
+ // New selector file structure: flat key-value pairs
15
+ type SelectorFile = Record<string, SelectorEntry>;
16
+
17
+ // Legacy format for backward compatibility
18
+ interface LegacySelectorElement {
19
+ selector: string;
20
+ type?: 'selector' | 'data' | 'testid' | 'placeholder' | 'label' | 'text' | 'id' | 'button';
21
+ value?: string;
22
+ nth?: number;
23
+ }
24
+
25
+ interface LegacySelectorFile {
26
+ screen: string;
27
+ elements: Record<string, LegacySelectorElement>;
28
+ }
29
+
30
+ export interface ResolvedSelector {
31
+ strategy: 'testid' | 'id' | 'placeholder' | 'label' | 'text' | 'css' | 'role';
32
+ value: string;
33
+ role?: string; // For role-based selectors (e.g., 'button', 'link')
34
+ name?: string; // For accessible name in role selectors
35
+ selector?: string; // CSS selector for fallback
36
+ nth?: number; // Index for .nth() if multiple matches exist
37
+ }
38
+
39
+ /**
40
+ * SelectorResolver - Resolves selector references to direct Playwright locator code
41
+ * Supports natural language references with auto-generated keys
42
+ */
43
+ export class SelectorResolver {
44
+ private selectorCache = new Map<string, SelectorFile | LegacySelectorFile>();
45
+ private selectorsDir: string;
46
+ private featureName?: string;
47
+ private screenName?: string;
48
+
49
+ constructor(selectorsDir?: string, screenName?: string) {
50
+ this.selectorsDir = selectorsDir || path.join(process.cwd(), 'qa', 'selectors', 'screens');
51
+ this.screenName = screenName;
52
+ }
53
+
54
+ /**
55
+ * Set screen context for base selector file lookup
56
+ */
57
+ setScreenContext(screenName: string): void {
58
+ this.screenName = screenName;
59
+ }
60
+
61
+ /**
62
+ * Set feature context for automatic file inference
63
+ */
64
+ setFeatureContext(featureName: string): void {
65
+ this.featureName = featureName;
66
+ }
67
+
68
+ /**
69
+ * Generate selector key from natural language label
70
+ * "Email Address" → "email.address"
71
+ * "Submit Button" → "submit.button"
72
+ * "User's Profile" → "users.profile"
73
+ */
74
+ static generateKey(label: string): string {
75
+ return label
76
+ .toLowerCase()
77
+ .replace(/['\u2019]s/g, 's') // Apostrophe s to just s ("User's" → "users")
78
+ .replace(/['\u2019]/g, '') // Remove remaining apostrophes
79
+ .replace(/[^a-z0-9\s]/g, '') // Remove special chars except spaces
80
+ .trim()
81
+ .replace(/\s+/g, '.'); // Spaces to dots
82
+ }
83
+
84
+ /**
85
+ * Resolve selector reference to Playwright locator code
86
+ * Supports:
87
+ * - Natural language: "Email Address", "Password" (with feature context)
88
+ * - Legacy format: "login:email_field" or "login.email_field" (with screen prefix)
89
+ */
90
+ resolveSelector(selectorRef: string, featureName?: string): ResolvedSelector {
91
+ const contextName = featureName || this.featureName;
92
+
93
+ // Check if it's legacy format (contains : or has dot with screen prefix)
94
+ // Legacy: "login:email_field" or "login.email_field"
95
+ // Natural: "Email Address", "Password", "Submit Button"
96
+ const hasColonSeparator = selectorRef.includes(':');
97
+ const hasDotSeparator = selectorRef.includes('.');
98
+
99
+ // If it has colon, it's definitely legacy
100
+ if (hasColonSeparator) {
101
+ return this.resolveLegacyFormat(selectorRef);
102
+ }
103
+
104
+ // If it has dots and looks like a technical identifier (lowercase, no spaces), it's legacy
105
+ if (hasDotSeparator && /^[a-z0-9\-\_\.]+$/.test(selectorRef)) {
106
+ return this.resolveLegacyFormat(selectorRef);
107
+ }
108
+
109
+ // Otherwise, it's natural language with feature context
110
+ if (!contextName) {
111
+ throw new Error(
112
+ `Natural language selector "${selectorRef}" requires feature context. ` +
113
+ `Use setFeatureContext() or pass featureName parameter.`
114
+ );
115
+ }
116
+
117
+ return this.resolveNaturalLanguage(selectorRef, contextName);
118
+ }
119
+
120
+ /**
121
+ * Resolve natural language selector
122
+ */
123
+ private resolveNaturalLanguage(label: string, featureName: string): ResolvedSelector {
124
+ const key = SelectorResolver.generateKey(label);
125
+ const selectorFile = this.loadNewSelectorFile(featureName);
126
+
127
+ const entry = selectorFile[key];
128
+ if (!entry) {
129
+ throw new Error(
130
+ `Selector "${label}" (key: ${key}) not found in ${featureName}.yaml. ` +
131
+ `Available selectors: ${Object.keys(selectorFile).join(', ')}`
132
+ );
133
+ }
134
+
135
+ return this.resolveFromEntry(entry, label);
136
+ }
137
+
138
+ /**
139
+ * Resolve legacy format selector
140
+ * Now uses feature context instead of requiring screen prefix in selector
141
+ */
142
+ private resolveLegacyFormat(selectorRef: string): ResolvedSelector {
143
+ // Extract screen and element
144
+ const cleaned = selectorRef.replace(/[\[\]]/g, '');
145
+
146
+ // Check if it has screen prefix (legacy format: "login:email_field" or "login.email_field")
147
+ if (cleaned.includes(':') || cleaned.includes('.')) {
148
+ const parts = cleaned.split(/[.:]/);
149
+
150
+ if (parts.length < 2) {
151
+ throw new Error(
152
+ `Invalid legacy selector reference: ${selectorRef}. ` +
153
+ `Expected format with screen prefix: [screen:element] or [screen.element]`
154
+ );
155
+ }
156
+
157
+ const screenId = parts[0];
158
+ const elementId = parts.slice(1).join('_');
159
+
160
+ // Load selector metadata from legacy file
161
+ const element = this.loadLegacySelectorElement(screenId, elementId);
162
+
163
+ // Priority chain: testid → id → placeholder → label → text → css
164
+ return this.resolveByPriority(element);
165
+ }
166
+
167
+ // Single word without separator - treat as natural language with feature context
168
+ if (!this.featureName) {
169
+ throw new Error(
170
+ `Selector "${selectorRef}" requires feature context. ` +
171
+ `Use setFeatureContext() or pass featureName parameter.`
172
+ );
173
+ }
174
+
175
+ return this.resolveNaturalLanguage(selectorRef, this.featureName);
176
+ }
177
+
178
+ /**
179
+ * Resolve from new structured entry format
180
+ */
181
+ private resolveFromEntry(entry: SelectorEntry, originalLabel: string): ResolvedSelector {
182
+ // Default values
183
+ const selector = entry.selector || '';
184
+ const type = entry.type || 'placeholder';
185
+ const value = entry.value || originalLabel;
186
+ const name = entry.name || originalLabel; // Use name field if provided, otherwise use label
187
+ const nth = entry.nth || 0;
188
+
189
+ // If custom selector is provided, use it
190
+ if (selector && selector.trim()) {
191
+ return {
192
+ strategy: 'css',
193
+ value: selector,
194
+ selector: selector,
195
+ nth,
196
+ };
197
+ }
198
+
199
+ // Use type-based strategy
200
+ switch (type) {
201
+ case 'placeholder':
202
+ return {
203
+ strategy: 'placeholder',
204
+ value,
205
+ nth,
206
+ };
207
+
208
+ case 'role':
209
+ return {
210
+ strategy: 'role',
211
+ role: value,
212
+ name: name, // Use the name field for accessible name
213
+ value,
214
+ nth,
215
+ };
216
+
217
+ case 'testid':
218
+ return {
219
+ strategy: 'testid',
220
+ value,
221
+ nth,
222
+ };
223
+
224
+ case 'label':
225
+ return {
226
+ strategy: 'label',
227
+ value,
228
+ nth,
229
+ };
230
+
231
+ case 'text':
232
+ return {
233
+ strategy: 'text',
234
+ value,
235
+ nth,
236
+ };
237
+
238
+ default:
239
+ // Fallback to placeholder
240
+ return {
241
+ strategy: 'placeholder',
242
+ value,
243
+ nth,
244
+ };
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Resolve selector by priority chain (legacy)
250
+ * Returns metadata only - no framework-specific code
251
+ */
252
+ private resolveByPriority(element: LegacySelectorElement): ResolvedSelector {
253
+ // Extract data-testid from selector if present
254
+ const testIdMatch = element.selector.match(/\[data-testid=["']([^"']+)["']\]/);
255
+ if (testIdMatch) {
256
+ return {
257
+ strategy: 'testid',
258
+ value: testIdMatch[1],
259
+ nth: element.nth,
260
+ };
261
+ }
262
+
263
+ // Check type-based strategies
264
+ if (element.type === 'button' && element.value) {
265
+ return {
266
+ strategy: 'role',
267
+ role: 'button',
268
+ name: element.value,
269
+ value: element.value,
270
+ nth: element.nth,
271
+ };
272
+ }
273
+
274
+ if (element.type === 'placeholder' && element.value) {
275
+ return {
276
+ strategy: 'placeholder',
277
+ value: element.value,
278
+ nth: element.nth,
279
+ };
280
+ }
281
+
282
+ if (element.type === 'label' && element.value) {
283
+ return {
284
+ strategy: 'label',
285
+ value: element.value,
286
+ nth: element.nth,
287
+ };
288
+ }
289
+
290
+ if (element.type === 'text' && element.value) {
291
+ return {
292
+ strategy: 'text',
293
+ value: element.value,
294
+ nth: element.nth,
295
+ };
296
+ }
297
+
298
+ // Extract #id from selector if present
299
+ const idMatch = element.selector.match(/#([\w-]+)/);
300
+ if (idMatch) {
301
+ return {
302
+ strategy: 'id',
303
+ value: idMatch[1],
304
+ selector: `#${idMatch[1]}`,
305
+ nth: element.nth,
306
+ };
307
+ }
308
+
309
+ // Fallback to CSS selector
310
+ return {
311
+ strategy: 'css',
312
+ value: element.selector,
313
+ selector: element.selector,
314
+ nth: element.nth,
315
+ };
316
+ }
317
+
318
+ /**
319
+ * Load new format selector file (flat key-value structure)
320
+ * Supports base + feature-specific merging:
321
+ * 1. Load base (screen-level) selectors - OPTIONAL
322
+ * 2. Load feature-specific selectors - REQUIRED
323
+ * 3. Merge (feature overrides base)
324
+ *
325
+ * Priority: override > normal, checks both old and new folder structures
326
+ * Old: qa/selectors/screens/<feature>.yaml
327
+ * New: qa/screens/<feature>/selectors/<feature>.yaml
328
+ */
329
+ private loadNewSelectorFile(featureName: string): SelectorFile {
330
+ const cacheKey = `new:${featureName}`;
331
+ if (this.selectorCache.has(cacheKey)) {
332
+ return this.selectorCache.get(cacheKey) as SelectorFile;
333
+ }
334
+
335
+ const selectors: SelectorFile = {};
336
+
337
+ // 1. Try load base file (screen-level shared selectors) - OPTIONAL
338
+ if (this.screenName) {
339
+ const basePath = this.findSelectorPath(this.screenName);
340
+ if (basePath && fs.existsSync(basePath)) {
341
+ const baseContent = fs.readFileSync(basePath, 'utf-8');
342
+ const baseSelectors = yaml.parse(baseContent) as SelectorFile;
343
+ Object.assign(selectors, baseSelectors);
344
+ }
345
+ }
346
+
347
+ // 2. Load feature-specific selectors - REQUIRED
348
+ const featurePath = this.findSelectorPath(featureName);
349
+ if (!featurePath) {
350
+ throw new Error(
351
+ `Selector file not found for feature "${featureName}". ` +
352
+ `Searched paths for ${featureName}.yaml`
353
+ );
354
+ }
355
+
356
+ const featureContent = fs.readFileSync(featurePath, 'utf-8');
357
+ const featureSelectors = yaml.parse(featureContent) as SelectorFile;
358
+
359
+ // 3. Merge: feature-specific overrides base
360
+ Object.assign(selectors, featureSelectors);
361
+
362
+ this.selectorCache.set(cacheKey, selectors);
363
+ return selectors;
364
+ }
365
+
366
+ /**
367
+ * Find selector file path (checks both old and new structures)
368
+ */
369
+ private findSelectorPath(name: string): string | null {
370
+ // Build list of possible paths (priority order)
371
+ const possiblePaths: string[] = [];
372
+
373
+ // Old structure: qa/selectors/screens/<name>.yaml
374
+ const oldOverridePath = path.join(this.selectorsDir, `${name}-override.yaml`);
375
+ const oldNormalPath = path.join(this.selectorsDir, `${name}.yaml`);
376
+ possiblePaths.push(oldOverridePath, oldNormalPath);
377
+
378
+ // New structure: qa/screens/<screenName>/selectors/<name>.yaml
379
+ const qaDir = path.dirname(path.dirname(this.selectorsDir)); // go up from qa/selectors/screens to qa/
380
+
381
+ if (this.screenName) {
382
+ // Use screenName for directory, name for filename
383
+ const newOverridePath = path.join(qaDir, 'screens', this.screenName, 'selectors', `${name}-override.yaml`);
384
+ const newNormalPath = path.join(qaDir, 'screens', this.screenName, 'selectors', `${name}.yaml`);
385
+ possiblePaths.push(newOverridePath, newNormalPath);
386
+ } else {
387
+ // Fallback: assume name is both screen and feature
388
+ const newOverridePath = path.join(qaDir, 'screens', name, 'selectors', `${name}-override.yaml`);
389
+ const newNormalPath = path.join(qaDir, 'screens', name, 'selectors', `${name}.yaml`);
390
+ possiblePaths.push(newOverridePath, newNormalPath);
391
+ }
392
+
393
+ // Find first existing file
394
+ for (const p of possiblePaths) {
395
+ if (fs.existsSync(p)) {
396
+ return p;
397
+ }
398
+ }
399
+
400
+ return null;
401
+ }
402
+
403
+ /**
404
+ * Load selector element from legacy YAML file
405
+ */
406
+ private loadLegacySelectorElement(screenId: string, elementId: string): LegacySelectorElement {
407
+ const selectorFile = this.loadLegacySelectorFile(screenId);
408
+
409
+ const element = selectorFile.elements[elementId];
410
+ if (!element) {
411
+ throw new Error(
412
+ `Element "${elementId}" not found in screen "${screenId}". ` +
413
+ `Available elements: ${Object.keys(selectorFile.elements).join(', ')}`
414
+ );
415
+ }
416
+
417
+ return element;
418
+ }
419
+
420
+ /**
421
+ * Load legacy selector file from disk (with caching)
422
+ * Checks both old and new folder structures
423
+ */
424
+ private loadLegacySelectorFile(screenId: string): LegacySelectorFile {
425
+ const cacheKey = `legacy:${screenId}`;
426
+ if (this.selectorCache.has(cacheKey)) {
427
+ return this.selectorCache.get(cacheKey) as LegacySelectorFile;
428
+ }
429
+
430
+ // Build list of possible paths (priority order)
431
+ const possiblePaths: string[] = [];
432
+
433
+ // Old structure: qa/selectors/screens/<screen>.yaml
434
+ const oldOverridePath = path.join(this.selectorsDir, `${screenId}-override.yaml`);
435
+ const oldNormalPath = path.join(this.selectorsDir, `${screenId}.yaml`);
436
+ possiblePaths.push(oldOverridePath, oldNormalPath);
437
+
438
+ // New structure: qa/screens/<screen>/selectors/<screen>.yaml
439
+ const qaDir = path.dirname(path.dirname(this.selectorsDir));
440
+ const newOverridePath = path.join(qaDir, 'screens', screenId, 'selectors', `${screenId}-override.yaml`);
441
+ const newNormalPath = path.join(qaDir, 'screens', screenId, 'selectors', `${screenId}.yaml`);
442
+ possiblePaths.push(newOverridePath, newNormalPath);
443
+
444
+ // Find first existing file
445
+ let filePath: string | undefined;
446
+ for (const p of possiblePaths) {
447
+ if (fs.existsSync(p)) {
448
+ filePath = p;
449
+ break;
450
+ }
451
+ }
452
+
453
+ if (!filePath) {
454
+ throw new Error(
455
+ `Selector file not found for screen "${screenId}". ` +
456
+ `Searched: ${possiblePaths.join(', ')}`
457
+ );
458
+ }
459
+
460
+ const content = fs.readFileSync(filePath, 'utf-8');
461
+ const selectorFile = yaml.parse(content) as LegacySelectorFile;
462
+
463
+ this.selectorCache.set(cacheKey, selectorFile);
464
+ return selectorFile;
465
+ }
466
+
467
+ /**
468
+ * Escape single quotes in strings
469
+ */
470
+ private escapeQuotes(text: string): string {
471
+ return text.replace(/'/g, "\\'");
472
+ }
473
+
474
+ /**
475
+ * Clear cache (useful for testing)
476
+ */
477
+ clearCache(): void {
478
+ this.selectorCache.clear();
479
+ }
480
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Core types for Selector DSL Framework
3
+ * Framework-agnostic types for multi-platform support
4
+ */
5
+
6
+ // ============================================================================
7
+ // UI Model Types
8
+ // ============================================================================
9
+
10
+ export interface UIElement {
11
+ key: string; // Unique key within screen (e1, e2, ...)
12
+ tag: string; // HTML/component tag (input, button, View, TextField, ...)
13
+ role?: string; // ARIA role or semantic role
14
+ name?: string; // name attribute
15
+ id?: string; // id/resource-id attribute
16
+ placeholder?: string; // placeholder text
17
+ label?: string; // Associated label text
18
+ text?: string; // Text content
19
+ ariaLabel?: string; // aria-label attribute
20
+ testId?: string; // data-testid / test ID
21
+ source: string; // Source file path
22
+ framework?: string; // Framework-specific type (TextField, EditText, etc.)
23
+ props?: Record<string, any>; // Additional framework-specific props
24
+ }
25
+
26
+ export interface UIModel {
27
+ screenId: string; // Screen identifier (login, dashboard, ...)
28
+ routeId: string; // Route path or identifier
29
+ framework: FrameworkType; // Framework type
30
+ sourceFiles: string[]; // All source files merged
31
+ elements: UIElement[]; // All UI elements on this screen
32
+ metadata?: {
33
+ scannedAt: string; // ISO timestamp
34
+ version: string; // Tool version
35
+ hash: string; // Content hash for cache
36
+ };
37
+ }
38
+
39
+ // ============================================================================
40
+ // Selector DSL Types
41
+ // ============================================================================
42
+
43
+ export type DiscoveryMethod =
44
+ | 'ai-static-analysis' // Generated by AI from static code analysis
45
+ | 'manual' // Manually written by QA
46
+ | 'runtime'; // Discovered at runtime
47
+
48
+ export type LocatorType =
49
+ | 'css' // CSS selector (web)
50
+ | 'xpath' // XPath selector
51
+ | 'resource-id' // Android resource-id
52
+ | 'accessibility-id' // iOS accessibility identifier
53
+ | 'test-id' // Framework test ID (data-testid, etc.)
54
+ | 'key' // Flutter Key
55
+ | 'text' // Text-based locator
56
+ | 'role'; // ARIA role locator
57
+
58
+ export interface SelectorEntry {
59
+ selector: string; // The actual selector string
60
+ type: string; // Element type (input, button, link, text, ...)
61
+ description: string; // Human-readable description
62
+ discoveryMethod: DiscoveryMethod;
63
+ locatorType?: LocatorType; // Type of locator (for multi-platform)
64
+ confidence?: 'high' | 'medium' | 'low'; // AI confidence level
65
+ alternatives?: string[]; // Alternative selectors (fallbacks)
66
+ metadata?: {
67
+ lastValidated?: string; // ISO timestamp
68
+ validationStatus?: 'valid' | 'invalid' | 'unknown';
69
+ };
70
+ }
71
+
72
+ export interface SelectorDSL {
73
+ [elementId: string]: SelectorEntry;
74
+ }
75
+
76
+ // ============================================================================
77
+ // Framework Types
78
+ // ============================================================================
79
+
80
+ export type FrameworkType =
81
+ | 'react'
82
+ | 'react-nextjs'
83
+ | 'vue'
84
+ | 'angular'
85
+ | 'html'
86
+ | 'flutter'
87
+ | 'jetpack-compose'
88
+ | 'swiftui';
89
+
90
+ export type TargetPlatform =
91
+ | 'web'
92
+ | 'android'
93
+ | 'ios'
94
+ | 'desktop';
95
+
96
+ // ============================================================================
97
+ // Executor Types
98
+ // ============================================================================
99
+
100
+ export type ExecutorType =
101
+ | 'playwright' // Web - Playwright
102
+ | 'puppeteer' // Web - Puppeteer
103
+ | 'selenium' // Web - Selenium
104
+ | 'appium-android' // Android - Appium
105
+ | 'appium-ios' // iOS - Appium
106
+ | 'flutter-driver' // Flutter Driver
107
+ | 'espresso' // Android - Espresso
108
+ | 'xcuitest'; // iOS - XCUITest
109
+
110
+ export interface ExecutorConfig {
111
+ type: ExecutorType;
112
+ platform: TargetPlatform;
113
+ selectorPath: string; // Path to selector DSL files
114
+ overridePath?: string; // Path to override files
115
+ }
116
+
117
+ // ============================================================================
118
+ // Cache Types
119
+ // ============================================================================
120
+
121
+ export interface CacheEntry {
122
+ screenId: string;
123
+ hash: string; // SHA-256 hash of UI Model + element IDs
124
+ selectors: SelectorDSL;
125
+ metadata: {
126
+ createdAt: string; // ISO timestamp
127
+ aiModel?: string; // AI model used (claude-3-5-sonnet, gemini-2.0-flash, ...)
128
+ tokenCost?: number; // Token usage
129
+ framework: FrameworkType;
130
+ };
131
+ }
132
+
133
+ // ============================================================================
134
+ // Generator Config Types
135
+ // ============================================================================
136
+
137
+ export interface GeneratorConfig {
138
+ // AI Provider
139
+ aiProvider: 'anthropic' | 'google' | 'openai';
140
+ aiModel?: string; // Optional: specific model (defaults to best available)
141
+
142
+ // Paths
143
+ sourceRoot: string; // Root directory to scan (e.g., 'app', 'src')
144
+ uiModelPath: string; // Where to save UI models
145
+ selectorPath: string; // Where to save selectors
146
+ cachePath: string; // Cache directory
147
+
148
+ // Framework
149
+ framework: FrameworkType;
150
+
151
+ // Options
152
+ enableCache: boolean;
153
+ cacheExpiry?: number; // Cache expiry in milliseconds
154
+ parallelScans?: number; // Number of parallel scans
155
+ verbose?: boolean;
156
+ }
157
+
158
+ // ============================================================================
159
+ // CLI Types
160
+ // ============================================================================
161
+
162
+ export interface DiscoverOptions {
163
+ screenId?: string; // Specific screen to discover
164
+ all?: boolean; // Discover all screens
165
+ force?: boolean; // Force re-scan even if cached
166
+ }
167
+
168
+ export interface GenerateOptions {
169
+ screenId?: string; // Specific screen to generate
170
+ all?: boolean; // Generate all screens
171
+ force?: boolean; // Force re-generation
172
+ skipCache?: boolean; // Skip cache lookup
173
+ }
174
+
175
+ export interface ValidateOptions {
176
+ screenId?: string; // Specific screen to validate
177
+ all?: boolean; // Validate all screens
178
+ executor?: ExecutorType; // Executor to validate against
179
+ }
180
+
181
+ // ============================================================================
182
+ // Gherkin Integration Types
183
+ // ============================================================================
184
+
185
+ export interface GherkinElementReference {
186
+ elementId: string; // e.g., "[login.email]"
187
+ screenId: string; // e.g., "login"
188
+ elementName: string; // e.g., "email"
189
+ }
190
+
191
+ export function parseElementReference(ref: string): GherkinElementReference | null {
192
+ // Parse "[screen.element]" format
193
+ const match = ref.match(/^\[([^.]+)\.([^\]]+)\]$/);
194
+ if (!match) return null;
195
+
196
+ return {
197
+ elementId: ref,
198
+ screenId: match[1],
199
+ elementName: match[2]
200
+ };
201
+ }
202
+
203
+ // ============================================================================
204
+ // Error Types
205
+ // ============================================================================
206
+
207
+ export class SelectorNotFoundError extends Error {
208
+ constructor(public elementId: string, public screenId: string) {
209
+ super(`Selector not found: ${elementId} on screen ${screenId}`);
210
+ this.name = 'SelectorNotFoundError';
211
+ }
212
+ }
213
+
214
+ export class UIModelNotFoundError extends Error {
215
+ constructor(public screenId: string) {
216
+ super(`UI Model not found for screen: ${screenId}`);
217
+ this.name = 'UIModelNotFoundError';
218
+ }
219
+ }
220
+
221
+ export class GeneratorError extends Error {
222
+ constructor(message: string, public cause?: Error) {
223
+ super(message);
224
+ this.name = 'GeneratorError';
225
+ }
226
+ }