@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,797 @@
1
+ "use strict";
2
+ /**
3
+ * React/Next.js UI Model Builder
4
+ * Scans React/Next.js source code to extract UI elements using heuristic analysis
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.ReactScanner = void 0;
44
+ exports.buildUIModel = buildUIModel;
45
+ exports.discoverScreens = discoverScreens;
46
+ const parser = __importStar(require("@babel/parser"));
47
+ const traverse_1 = __importDefault(require("@babel/traverse"));
48
+ const t = __importStar(require("@babel/types"));
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
51
+ const glob_1 = require("glob");
52
+ class ReactScanner {
53
+ constructor(config) {
54
+ this.elements = [];
55
+ this.elementCounter = 0;
56
+ this.detectedComponents = [];
57
+ this.scannedComponentPaths = new Set(); // Avoid duplicate scans
58
+ this.config = config;
59
+ }
60
+ /**
61
+ * Discover all routes/screens in Next.js app directory
62
+ */
63
+ async discoverScreens() {
64
+ const appDir = this.config.sourceRoot;
65
+ // Find all page.tsx/page.jsx files (Next.js 13+ app directory)
66
+ const pageFiles = await (0, glob_1.glob)('**/page.{tsx,jsx}', {
67
+ cwd: appDir,
68
+ absolute: false,
69
+ ignore: ['**/node_modules/**', '**/api/**']
70
+ });
71
+ // Extract screen IDs from paths
72
+ // Example: "login/page.tsx" -> "login"
73
+ // Example: "auth/login/page.tsx" -> "auth-login"
74
+ // Example: "page.tsx" -> "home"
75
+ const screens = pageFiles.map(file => {
76
+ const dir = path.dirname(file);
77
+ return dir === '.' ? 'home' : dir.replace(/\//g, '-');
78
+ });
79
+ return screens;
80
+ }
81
+ /**
82
+ * Build UI Model for a specific screen
83
+ */
84
+ async buildUIModel(screenId) {
85
+ // Reset state for new screen
86
+ this.elements = [];
87
+ this.elementCounter = 0;
88
+ this.detectedComponents = [];
89
+ this.scannedComponentPaths.clear();
90
+ // Determine route path from screen ID
91
+ // "home" -> "" (root)
92
+ // "auth-login" -> "auth/login"
93
+ const routePath = screenId === 'home' ? '' : screenId.replace(/-/g, '/');
94
+ const routeDir = path.join(this.config.sourceRoot, routePath);
95
+ // Collect source files to scan
96
+ const sourceFiles = [];
97
+ // 1. App root layout
98
+ const rootLayout = path.join(this.config.sourceRoot, 'layout.tsx');
99
+ if (fs.existsSync(rootLayout)) {
100
+ sourceFiles.push(rootLayout);
101
+ }
102
+ // 2. Route-specific layout (if exists)
103
+ const routeLayout = path.join(routeDir, 'layout.tsx');
104
+ if (fs.existsSync(routeLayout)) {
105
+ sourceFiles.push(routeLayout);
106
+ }
107
+ // 3. Page component
108
+ const pageTsx = path.join(routeDir, 'page.tsx');
109
+ const pageJsx = path.join(routeDir, 'page.jsx');
110
+ if (fs.existsSync(pageTsx)) {
111
+ sourceFiles.push(pageTsx);
112
+ }
113
+ else if (fs.existsSync(pageJsx)) {
114
+ sourceFiles.push(pageJsx);
115
+ }
116
+ else {
117
+ throw new Error(`Page component not found for screen: ${screenId} at ${routeDir}`);
118
+ }
119
+ // Phase 1: Scan all source files (page components)
120
+ for (const filePath of sourceFiles) {
121
+ await this.scanFile(filePath);
122
+ }
123
+ // Phase 2: Scan detected components (unlimited depth by default)
124
+ const maxDepth = this.config.maxDepth !== undefined ? this.config.maxDepth : 999; // Default unlimited
125
+ const depthLabel = maxDepth === 999 ? 'unlimited' : maxDepth.toString();
126
+ if (this.config.verbose && this.detectedComponents.length > 0) {
127
+ console.log(` Detected ${this.detectedComponents.length} component(s), scanning with depth=${depthLabel}...`);
128
+ }
129
+ await this.scanComponentsRecursive(this.detectedComponents, 1, maxDepth);
130
+ // Build and return UI Model
131
+ const uiModel = {
132
+ screenId,
133
+ routeId: routePath || 'home',
134
+ framework: this.config.framework,
135
+ sourceFiles: sourceFiles.map(f => path.relative(this.config.sourceRoot, f)),
136
+ elements: this.elements,
137
+ metadata: {
138
+ scannedAt: new Date().toISOString(),
139
+ version: '1.0.0',
140
+ hash: this.generateHash(this.elements)
141
+ }
142
+ };
143
+ return uiModel;
144
+ }
145
+ /**
146
+ * Scan a single file and extract UI elements
147
+ */
148
+ async scanFile(filePath) {
149
+ const sourceFileName = path.basename(filePath);
150
+ const importMap = new Map(); // componentName → importPath
151
+ if (this.config.verbose) {
152
+ console.log(` Scanning: ${filePath}`);
153
+ }
154
+ const code = fs.readFileSync(filePath, 'utf-8');
155
+ // Parse with Babel
156
+ const ast = parser.parse(code, {
157
+ sourceType: 'module',
158
+ plugins: ['typescript', 'jsx']
159
+ });
160
+ // Traverse AST to extract imports and JSX elements
161
+ (0, traverse_1.default)(ast, {
162
+ // Detect imports
163
+ ImportDeclaration: (path) => {
164
+ const importPath = path.node.source.value;
165
+ // Extract default import: import ChatInput from '...'
166
+ const defaultSpecifier = path.node.specifiers.find(s => t.isImportDefaultSpecifier(s));
167
+ if (defaultSpecifier && t.isImportDefaultSpecifier(defaultSpecifier)) {
168
+ const componentName = defaultSpecifier.local.name;
169
+ importMap.set(componentName, importPath);
170
+ }
171
+ // Extract named imports: import { Button } from '...'
172
+ path.node.specifiers
173
+ .filter(s => t.isImportSpecifier(s))
174
+ .forEach(specifier => {
175
+ if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
176
+ const componentName = specifier.imported.name;
177
+ importMap.set(componentName, importPath);
178
+ }
179
+ });
180
+ },
181
+ // Extract JSX elements
182
+ JSXElement: (path) => {
183
+ this.extractElement(path, sourceFileName, filePath, importMap);
184
+ },
185
+ // PHASE 1: Detect conditional rendering patterns
186
+ JSXExpressionContainer: (path) => {
187
+ this.detectConditionalElements(path, sourceFileName, filePath, importMap);
188
+ }
189
+ });
190
+ }
191
+ /**
192
+ * Smart element filter - determines if element should be scanned
193
+ */
194
+ shouldScanElement(tagName, attributes, textContent, path) {
195
+ const lowercaseTag = tagName.toLowerCase();
196
+ // 1. Always scan form elements
197
+ const formElements = ['input', 'button', 'textarea', 'select', 'form'];
198
+ if (formElements.includes(lowercaseTag))
199
+ return true;
200
+ // 2. Always scan links (a, Link)
201
+ if (lowercaseTag === 'a' || tagName === 'Link')
202
+ return true;
203
+ // 3. Scan headings with text content
204
+ if (/^h[1-6]$/.test(lowercaseTag) && textContent)
205
+ return true;
206
+ // 4. Scan images with alt text
207
+ if (lowercaseTag === 'img' && attributes['alt'])
208
+ return true;
209
+ // 5. Scan elements with identifying attributes
210
+ const hasIdentifier = attributes['id'] ||
211
+ attributes['name'] ||
212
+ attributes['data-testid'] ||
213
+ attributes['data-test-id'] ||
214
+ attributes['aria-label'] ||
215
+ attributes['ariaLabel'];
216
+ if (hasIdentifier)
217
+ return true;
218
+ // 6. Scan semantic components (ChatInput, SubmitButton, UserProfile, etc.)
219
+ // Pattern: *Input, *Field, *TextArea, *Select, *Button, *Link, *Form
220
+ const semanticPatterns = [
221
+ /Input$/, // ChatInput, MessageInput
222
+ /Field$/, // TextField, EmailField
223
+ /TextArea$/, // MessageTextArea
224
+ /Select$/, // CountrySelect
225
+ /Button$/, // SubmitButton, CancelButton
226
+ /Link$/, // NavLink
227
+ /Form$/, // LoginForm
228
+ /Avatar$/, // UserAvatar
229
+ /Icon$/, // SearchIcon
230
+ /Image$/, // ProfileImage
231
+ /Card$/, // UserCard
232
+ /List$/, // MessageList
233
+ /Item$/ // ListItem
234
+ ];
235
+ if (semanticPatterns.some(pattern => pattern.test(tagName))) {
236
+ return true;
237
+ }
238
+ // 7. Scan text containers with content
239
+ const textContainers = ['p', 'span', 'div', 'section', 'article'];
240
+ if (textContainers.includes(lowercaseTag) && textContent && textContent.length > 0) {
241
+ return true;
242
+ }
243
+ // 7.5. PHASE 1.5: Scan error/success message elements by className pattern (even without text)
244
+ const className = attributes['className'] || '';
245
+ const isErrorOrSuccessMessage = className.includes('text-red') ||
246
+ className.includes('text-green') ||
247
+ className.includes('bg-red') ||
248
+ className.includes('bg-green') ||
249
+ className.includes('error') ||
250
+ className.includes('success') ||
251
+ className.includes('alert');
252
+ if (textContainers.includes(lowercaseTag) && isErrorOrSuccessMessage) {
253
+ return true;
254
+ }
255
+ // 7.6. PHASE 1.6: Scan timestamp/metadata elements by className pattern
256
+ // Fix for elements with dynamic expressions like {timestamp.toLocaleTimeString()}
257
+ const isTimestampOrMetadata = className.includes('timestamp') ||
258
+ className.includes('time') ||
259
+ (className.includes('text-xs') && className.includes('text-gray')) ||
260
+ (className.includes('text-sm') && className.includes('text-gray') && className.includes('mt-'));
261
+ if (textContainers.includes(lowercaseTag) && isTimestampOrMetadata) {
262
+ return true;
263
+ }
264
+ // 8. NEW: Smart container detection for structural elements
265
+ if (['div', 'section', 'article', 'main', 'aside', 'nav'].includes(lowercaseTag)) {
266
+ if (path && this.shouldScanContainer(tagName, attributes, path)) {
267
+ return true;
268
+ }
269
+ }
270
+ return false; // Skip everything else
271
+ }
272
+ /**
273
+ * Smart container detection - checks if container is structurally important
274
+ * NEW: Phase 1 - Task 1
275
+ */
276
+ shouldScanContainer(tagName, attributes, path) {
277
+ // 1. Has important children (form elements, buttons, custom components)?
278
+ const children = path.node.children.filter(child => t.isJSXElement(child));
279
+ for (const child of children) {
280
+ const childTag = this.getTagName(child.openingElement.name);
281
+ const childTagLower = childTag.toLowerCase();
282
+ // Has form elements
283
+ if (['input', 'button', 'textarea', 'select', 'form'].includes(childTagLower)) {
284
+ return true;
285
+ }
286
+ // Has custom components (PascalCase)
287
+ if (/^[A-Z]/.test(childTag)) {
288
+ return true;
289
+ }
290
+ }
291
+ // 2. Semantic className keywords
292
+ const className = attributes['className'] || '';
293
+ const semanticKeywords = [
294
+ 'message', 'messages', 'chat',
295
+ 'list', 'items',
296
+ 'container', 'wrapper', 'content',
297
+ 'scroll', 'overflow',
298
+ 'grid', 'flex'
299
+ ];
300
+ const hasSemanticClass = semanticKeywords.some(keyword => className.toLowerCase().includes(keyword));
301
+ if (hasSemanticClass) {
302
+ return true;
303
+ }
304
+ // 3. Has scroll behavior (overflow-auto, overflow-y-auto, etc.)
305
+ if (className.includes('overflow')) {
306
+ return true;
307
+ }
308
+ // 4. Has ARIA role
309
+ if (attributes['role']) {
310
+ return true;
311
+ }
312
+ // 5. Has ref (often used for important containers)
313
+ if (attributes['ref']) {
314
+ return true;
315
+ }
316
+ return false;
317
+ }
318
+ /**
319
+ * Extract UI element from JSX node
320
+ */
321
+ extractElement(path, sourceFile, fullFilePath, importMap) {
322
+ const openingElement = path.node.openingElement;
323
+ const tagName = this.getTagName(openingElement.name);
324
+ // Extract attributes and text first (needed for filtering)
325
+ const attributes = this.extractAttributes(openingElement.attributes);
326
+ const textContent = this.extractTextContent(path.node);
327
+ // Check if this is a custom component (starts with uppercase)
328
+ const isCustomComponent = /^[A-Z]/.test(tagName);
329
+ // If it's a custom component and we have an import for it, track it for scanning
330
+ // UPDATED: Phase 1 - Task 2 - Track ALL PascalCase components, not just semantic patterns
331
+ if (isCustomComponent && importMap.has(tagName)) {
332
+ const importPath = importMap.get(tagName);
333
+ // Check if not already tracked
334
+ const alreadyTracked = this.detectedComponents.some(c => c.name === tagName && c.importPath === importPath);
335
+ if (!alreadyTracked) {
336
+ this.detectedComponents.push({
337
+ name: tagName,
338
+ importPath,
339
+ sourceFile: fullFilePath
340
+ });
341
+ if (this.config.verbose) {
342
+ console.log(` Found component: ${tagName} from ${importPath}`);
343
+ }
344
+ }
345
+ }
346
+ // Use smart filter instead of static whitelist (pass path for container detection)
347
+ if (!this.shouldScanElement(tagName, attributes, textContent, path)) {
348
+ return; // Skip non-scannable elements
349
+ }
350
+ // Build UI Element
351
+ const element = {
352
+ key: `e${++this.elementCounter}`,
353
+ tag: tagName.toLowerCase(),
354
+ role: attributes['role'] || this.inferRole(tagName),
355
+ name: attributes['name'],
356
+ id: attributes['id'],
357
+ placeholder: attributes['placeholder'],
358
+ ariaLabel: attributes['aria-label'] || attributes['ariaLabel'],
359
+ testId: attributes['data-testid'] || attributes['data-test-id'],
360
+ text: textContent || attributes['value'],
361
+ source: sourceFile,
362
+ props: attributes
363
+ };
364
+ // Add label if associated
365
+ if (attributes['aria-labelledby']) {
366
+ element.label = `[ref:${attributes['aria-labelledby']}]`;
367
+ }
368
+ this.elements.push(element);
369
+ }
370
+ /**
371
+ * PHASE 1: Detect and extract conditionally rendered elements
372
+ * Handles patterns: {condition && <Element />}, {condition ? <A /> : <B />}, {arr.map(...)}
373
+ * PHASE 1.5: Now also traverses nested children
374
+ */
375
+ detectConditionalElements(path, sourceFile, fullFilePath, importMap) {
376
+ const expr = path.node.expression;
377
+ // Pattern 1: Logical AND (condition && <Element />)
378
+ if (t.isLogicalExpression(expr, { operator: '&&' })) {
379
+ const rightSide = expr.right;
380
+ if (t.isJSXElement(rightSide)) {
381
+ // Extract the direct element
382
+ this.extractConditionalElement(rightSide, sourceFile, fullFilePath, importMap, 'conditional-and');
383
+ // PHASE 1.5: Also traverse nested children
384
+ this.traverseConditionalChildren(rightSide, sourceFile, fullFilePath, importMap, 'conditional-nested');
385
+ }
386
+ else if (t.isJSXFragment(rightSide)) {
387
+ // Handle {condition && (<><Element1 /><Element2 /></>)}
388
+ this.extractFragmentElements(rightSide, sourceFile, fullFilePath, importMap, 'conditional-and');
389
+ }
390
+ }
391
+ // Pattern 2: Ternary operator (condition ? <A /> : <B />)
392
+ if (t.isConditionalExpression(expr)) {
393
+ const consequent = expr.consequent;
394
+ const alternate = expr.alternate;
395
+ if (t.isJSXElement(consequent)) {
396
+ this.extractConditionalElement(consequent, sourceFile, fullFilePath, importMap, 'conditional-true');
397
+ // PHASE 1.5: Traverse nested children
398
+ this.traverseConditionalChildren(consequent, sourceFile, fullFilePath, importMap, 'conditional-nested');
399
+ }
400
+ if (t.isJSXElement(alternate)) {
401
+ this.extractConditionalElement(alternate, sourceFile, fullFilePath, importMap, 'conditional-false');
402
+ // PHASE 1.5: Traverse nested children
403
+ this.traverseConditionalChildren(alternate, sourceFile, fullFilePath, importMap, 'conditional-nested');
404
+ }
405
+ }
406
+ // Pattern 3: Array.map() rendering (arr.map(item => <Element />))
407
+ if (t.isCallExpression(expr)) {
408
+ const callee = expr.callee;
409
+ // Check if it's a .map() call
410
+ if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: 'map' })) {
411
+ const mapCallback = expr.arguments[0];
412
+ if (t.isArrowFunctionExpression(mapCallback) || t.isFunctionExpression(mapCallback)) {
413
+ const body = mapCallback.body;
414
+ // Case 1: Direct return - arr.map(item => <Element />)
415
+ if (t.isJSXElement(body)) {
416
+ this.extractConditionalElement(body, sourceFile, fullFilePath, importMap, 'loop-item');
417
+ }
418
+ // Case 2: Block with return - arr.map(item => { return <Element /> })
419
+ if (t.isBlockStatement(body)) {
420
+ for (const statement of body.body) {
421
+ if (t.isReturnStatement(statement) && statement.argument && t.isJSXElement(statement.argument)) {
422
+ this.extractConditionalElement(statement.argument, sourceFile, fullFilePath, importMap, 'loop-item');
423
+ }
424
+ }
425
+ }
426
+ }
427
+ }
428
+ }
429
+ }
430
+ /**
431
+ * Extract elements from JSX Fragment
432
+ */
433
+ extractFragmentElements(fragment, sourceFile, fullFilePath, importMap, renderType) {
434
+ for (const child of fragment.children) {
435
+ if (t.isJSXElement(child)) {
436
+ this.extractConditionalElement(child, sourceFile, fullFilePath, importMap, renderType);
437
+ }
438
+ }
439
+ }
440
+ /**
441
+ * PHASE 1.5: Traverse nested children of conditional elements
442
+ * Example: {error && <div><p>{error}</p></div>} - detect the nested <p> tag
443
+ */
444
+ traverseConditionalChildren(element, sourceFile, fullFilePath, importMap, renderType) {
445
+ for (const child of element.children) {
446
+ // Traverse nested JSX elements
447
+ if (t.isJSXElement(child)) {
448
+ const openingElement = child.openingElement;
449
+ const tagName = this.getTagName(openingElement.name);
450
+ const attributes = this.extractAttributes(openingElement.attributes);
451
+ const textContent = this.extractTextContent(child);
452
+ // Check if this nested element should be scanned
453
+ if (this.shouldScanElement(tagName, attributes, textContent, undefined)) {
454
+ this.extractConditionalElement(child, sourceFile, fullFilePath, importMap, renderType);
455
+ }
456
+ // Recursively traverse deeper children
457
+ this.traverseConditionalChildren(child, sourceFile, fullFilePath, importMap, renderType);
458
+ }
459
+ // Traverse JSX expression containers (for nested dynamic content)
460
+ if (t.isJSXExpressionContainer(child)) {
461
+ const expr = child.expression;
462
+ // Handle nested JSX elements in expressions
463
+ if (t.isJSXElement(expr)) {
464
+ this.extractConditionalElement(expr, sourceFile, fullFilePath, importMap, renderType);
465
+ }
466
+ }
467
+ }
468
+ }
469
+ /**
470
+ * Extract a conditionally rendered JSX element
471
+ */
472
+ extractConditionalElement(jsxElement, sourceFile, fullFilePath, importMap, renderType) {
473
+ const openingElement = jsxElement.openingElement;
474
+ const tagName = this.getTagName(openingElement.name);
475
+ // Extract attributes and text
476
+ const attributes = this.extractAttributes(openingElement.attributes);
477
+ const textContent = this.extractTextContent(jsxElement);
478
+ // Check if this is a custom component
479
+ const isCustomComponent = /^[A-Z]/.test(tagName);
480
+ if (isCustomComponent && importMap.has(tagName)) {
481
+ const importPath = importMap.get(tagName);
482
+ const alreadyTracked = this.detectedComponents.some(c => c.name === tagName && c.importPath === importPath);
483
+ if (!alreadyTracked) {
484
+ this.detectedComponents.push({
485
+ name: tagName,
486
+ importPath,
487
+ sourceFile: fullFilePath
488
+ });
489
+ }
490
+ }
491
+ // Use smart filter to decide if we should scan this element
492
+ if (!this.shouldScanElement(tagName, attributes, textContent, undefined)) {
493
+ return;
494
+ }
495
+ // Build UI Element with conditional marker
496
+ const element = {
497
+ key: `e${++this.elementCounter}`,
498
+ tag: tagName.toLowerCase(),
499
+ role: attributes['role'] || this.inferRole(tagName),
500
+ name: attributes['name'],
501
+ id: attributes['id'],
502
+ placeholder: attributes['placeholder'],
503
+ ariaLabel: attributes['aria-label'] || attributes['ariaLabel'],
504
+ testId: attributes['data-testid'] || attributes['data-test-id'],
505
+ text: textContent || attributes['value'],
506
+ source: sourceFile,
507
+ props: {
508
+ ...attributes,
509
+ isConditional: renderType // Mark as conditional with type
510
+ }
511
+ };
512
+ if (attributes['aria-labelledby']) {
513
+ element.label = `[ref:${attributes['aria-labelledby']}]`;
514
+ }
515
+ this.elements.push(element);
516
+ if (this.config.verbose) {
517
+ console.log(` Found conditional element: ${tagName} (${renderType})`);
518
+ }
519
+ }
520
+ /**
521
+ * Get tag name from JSX element
522
+ */
523
+ getTagName(name) {
524
+ if (t.isJSXIdentifier(name)) {
525
+ return name.name;
526
+ }
527
+ if (t.isJSXMemberExpression(name)) {
528
+ // Handle cases like <Form.Input />
529
+ return this.getTagName(name.property);
530
+ }
531
+ return 'unknown';
532
+ }
533
+ /**
534
+ * Extract attributes from JSX element
535
+ */
536
+ extractAttributes(attributes) {
537
+ const result = {};
538
+ for (const attr of attributes) {
539
+ if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
540
+ const name = attr.name.name;
541
+ const value = this.getAttributeValue(attr.value);
542
+ if (value !== null) {
543
+ result[name] = value;
544
+ }
545
+ }
546
+ }
547
+ return result;
548
+ }
549
+ /**
550
+ * Get attribute value
551
+ */
552
+ getAttributeValue(value) {
553
+ if (!value)
554
+ return null;
555
+ if (t.isStringLiteral(value)) {
556
+ return value.value;
557
+ }
558
+ if (t.isJSXExpressionContainer(value)) {
559
+ const expr = value.expression;
560
+ // Handle string literals in expressions
561
+ if (t.isStringLiteral(expr)) {
562
+ return expr.value;
563
+ }
564
+ // Handle template literals
565
+ if (t.isTemplateLiteral(expr) && expr.quasis.length === 1) {
566
+ return expr.quasis[0].value.cooked || '';
567
+ }
568
+ // For complex expressions, return placeholder
569
+ return '[expression]';
570
+ }
571
+ return null;
572
+ }
573
+ /**
574
+ * Extract text content from JSX element
575
+ * PHASE 1 ENHANCED: Extract text from dynamic expressions
576
+ */
577
+ extractTextContent(node) {
578
+ const children = node.children;
579
+ const textParts = [];
580
+ for (const child of children) {
581
+ if (t.isJSXText(child)) {
582
+ const text = child.value.trim();
583
+ if (text)
584
+ textParts.push(text);
585
+ }
586
+ if (t.isJSXExpressionContainer(child)) {
587
+ const expr = child.expression;
588
+ // Static string literal
589
+ if (t.isStringLiteral(expr)) {
590
+ textParts.push(expr.value);
591
+ }
592
+ // PHASE 1: Extract text from ternary (condition ? 'Text A' : 'Text B')
593
+ if (t.isConditionalExpression(expr)) {
594
+ const texts = [];
595
+ if (t.isStringLiteral(expr.consequent)) {
596
+ texts.push(expr.consequent.value);
597
+ }
598
+ if (t.isStringLiteral(expr.alternate)) {
599
+ texts.push(expr.alternate.value);
600
+ }
601
+ if (texts.length > 0) {
602
+ textParts.push(texts.join(' / ')); // e.g., "Copy / Copied!"
603
+ }
604
+ }
605
+ // PHASE 1: Extract text from logical OR (defaultValue || 'Fallback')
606
+ if (t.isLogicalExpression(expr, { operator: '||' })) {
607
+ if (t.isStringLiteral(expr.right)) {
608
+ textParts.push(expr.right.value);
609
+ }
610
+ }
611
+ }
612
+ }
613
+ return textParts.length > 0 ? textParts.join(' ') : null;
614
+ }
615
+ /**
616
+ * Infer ARIA role from tag name
617
+ */
618
+ inferRole(tagName) {
619
+ const roleMap = {
620
+ 'button': 'button',
621
+ 'input': 'textbox',
622
+ 'textarea': 'textbox',
623
+ 'select': 'combobox',
624
+ 'a': 'link',
625
+ 'form': 'form'
626
+ };
627
+ return roleMap[tagName.toLowerCase()];
628
+ }
629
+ /**
630
+ * Resolve component import path to actual file path
631
+ */
632
+ resolveComponentPath(importPath, sourceFile) {
633
+ try {
634
+ // Handle different import path formats
635
+ let resolvedPath;
636
+ if (importPath.startsWith('@/')) {
637
+ // Alias import: @/components/ChatInput → PROJECT_ROOT/components/ChatInput.tsx
638
+ // Note: @ alias points to project root, not sourceRoot (app/)
639
+ const projectRoot = path.resolve(this.config.sourceRoot, '..');
640
+ const relativePath = importPath.replace('@/', '');
641
+ resolvedPath = path.join(projectRoot, relativePath);
642
+ }
643
+ else if (importPath.startsWith('./') || importPath.startsWith('../')) {
644
+ // Relative import: ./components/ChatInput
645
+ const sourceDir = path.dirname(sourceFile);
646
+ resolvedPath = path.join(sourceDir, importPath);
647
+ }
648
+ else {
649
+ // Absolute or node_modules import - skip
650
+ return null;
651
+ }
652
+ // Try different file extensions
653
+ const extensions = ['.tsx', '.ts', '.jsx', '.js'];
654
+ for (const ext of extensions) {
655
+ const fullPath = resolvedPath + ext;
656
+ if (fs.existsSync(fullPath)) {
657
+ return fullPath;
658
+ }
659
+ }
660
+ // Try index files
661
+ for (const ext of extensions) {
662
+ const indexPath = path.join(resolvedPath, `index${ext}`);
663
+ if (fs.existsSync(indexPath)) {
664
+ return indexPath;
665
+ }
666
+ }
667
+ return null;
668
+ }
669
+ catch (error) {
670
+ if (this.config.verbose) {
671
+ console.log(` Could not resolve: ${importPath}`);
672
+ }
673
+ return null;
674
+ }
675
+ }
676
+ /**
677
+ * NEW: Recursively scan components at multiple depths
678
+ * @param components - List of components to scan
679
+ * @param currentDepth - Current depth level
680
+ * @param maxDepth - Maximum depth to scan
681
+ */
682
+ async scanComponentsRecursive(components, currentDepth, maxDepth) {
683
+ if (currentDepth > maxDepth) {
684
+ return; // Stop recursion at max depth
685
+ }
686
+ const startTime = Date.now();
687
+ const componentsScanned = [];
688
+ // Scan all components at current level
689
+ for (const component of components) {
690
+ const componentPath = this.resolveComponentPath(component.importPath, component.sourceFile);
691
+ if (!componentPath) {
692
+ continue; // Skip if path cannot be resolved
693
+ }
694
+ // Skip node_modules
695
+ if (componentPath.includes('node_modules')) {
696
+ if (this.config.verbose) {
697
+ console.log(` Skipping node_modules: ${componentPath}`);
698
+ }
699
+ continue;
700
+ }
701
+ // Skip if already scanned (avoid duplicates)
702
+ if (this.scannedComponentPaths.has(componentPath)) {
703
+ continue;
704
+ }
705
+ // Mark as scanned
706
+ this.scannedComponentPaths.add(componentPath);
707
+ // Store the count of detected components before scanning
708
+ const detectedCountBefore = this.detectedComponents.length;
709
+ // Scan the component file
710
+ await this.scanComponentFile(componentPath, component.name);
711
+ // Track newly detected components from this scan
712
+ const newlyDetected = this.detectedComponents.slice(detectedCountBefore);
713
+ componentsScanned.push(...newlyDetected);
714
+ }
715
+ const elapsed = Date.now() - startTime;
716
+ if (this.config.verbose && componentsScanned.length > 0) {
717
+ console.log(` [Depth ${currentDepth}] Scanned ${components.length} component(s), found ${componentsScanned.length} sub-component(s) (${elapsed}ms)`);
718
+ }
719
+ // Recursively scan newly detected components at next depth
720
+ if (componentsScanned.length > 0 && currentDepth < maxDepth) {
721
+ await this.scanComponentsRecursive(componentsScanned, currentDepth + 1, maxDepth);
722
+ }
723
+ }
724
+ /**
725
+ * Scan component file and extract elements
726
+ */
727
+ async scanComponentFile(componentPath, componentName) {
728
+ if (this.config.verbose) {
729
+ console.log(` Scanning component: ${componentName} at ${componentPath}`);
730
+ }
731
+ const code = fs.readFileSync(componentPath, 'utf-8');
732
+ // Parse with Babel
733
+ const ast = parser.parse(code, {
734
+ sourceType: 'module',
735
+ plugins: ['typescript', 'jsx']
736
+ });
737
+ const importMap = new Map(); // Empty import map for component scanning
738
+ // Traverse AST and extract JSX elements (no nested component scanning)
739
+ (0, traverse_1.default)(ast, {
740
+ JSXElement: (path) => {
741
+ const openingElement = path.node.openingElement;
742
+ const tagName = this.getTagName(openingElement.name);
743
+ // Extract attributes and text
744
+ const attributes = this.extractAttributes(openingElement.attributes);
745
+ const textContent = this.extractTextContent(path.node);
746
+ // Use smart filter (pass path for container detection)
747
+ if (!this.shouldScanElement(tagName, attributes, textContent, path)) {
748
+ return;
749
+ }
750
+ // Build UI Element with component context
751
+ const element = {
752
+ key: `e${++this.elementCounter}`,
753
+ tag: tagName.toLowerCase(),
754
+ role: attributes['role'] || this.inferRole(tagName),
755
+ name: attributes['name'],
756
+ id: attributes['id'],
757
+ placeholder: attributes['placeholder'],
758
+ ariaLabel: attributes['aria-label'] || attributes['ariaLabel'],
759
+ testId: attributes['data-testid'] || attributes['data-test-id'],
760
+ text: textContent || attributes['value'],
761
+ source: `${componentName}.tsx`, // Mark as from component
762
+ props: attributes
763
+ };
764
+ // Add label if associated
765
+ if (attributes['aria-labelledby']) {
766
+ element.label = `[ref:${attributes['aria-labelledby']}]`;
767
+ }
768
+ this.elements.push(element);
769
+ },
770
+ // PHASE 1: Detect conditional rendering in components too
771
+ JSXExpressionContainer: (path) => {
772
+ this.detectConditionalElements(path, `${componentName}.tsx`, componentPath, importMap);
773
+ }
774
+ });
775
+ }
776
+ /**
777
+ * Generate hash for cache key
778
+ */
779
+ generateHash(elements) {
780
+ const crypto = require('crypto');
781
+ const content = JSON.stringify(elements);
782
+ return crypto.createHash('sha256').update(content).digest('hex');
783
+ }
784
+ }
785
+ exports.ReactScanner = ReactScanner;
786
+ // ============================================================================
787
+ // Factory Function
788
+ // ============================================================================
789
+ async function buildUIModel(screenId, config) {
790
+ const scanner = new ReactScanner(config);
791
+ return scanner.buildUIModel(screenId);
792
+ }
793
+ async function discoverScreens(config) {
794
+ const scanner = new ReactScanner(config);
795
+ return scanner.discoverScreens();
796
+ }
797
+ //# sourceMappingURL=react-scanner.js.map