@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,572 @@
1
+ /**
2
+ * Auto-Tagging Tool - v3.1
3
+ *
4
+ * Automatically injects stable data-testid attributes into React/Vue/HTML source code
5
+ *
6
+ * Key Features:
7
+ * 1. Idempotent (skips if data-testid already exists)
8
+ * 2. Preserves code formatting (Prettier/ESLint compatible)
9
+ * 3. Generates stable, semantic IDs (screen-element-type)
10
+ * 4. Supports React, Vue, HTML
11
+ * 5. Dry-run mode for preview
12
+ *
13
+ * Philosophy: Proactive solution - add test IDs BEFORE you need them
14
+ */
15
+
16
+ import * as parser from '@babel/parser';
17
+ import traverse, { NodePath } from '@babel/traverse';
18
+ import generate from '@babel/generator';
19
+ import * as t from '@babel/types';
20
+ import * as fs from 'fs';
21
+ import * as path from 'path';
22
+
23
+ // ============================================================================
24
+ // TYPES
25
+ // ============================================================================
26
+
27
+ export interface AutoTagConfig {
28
+ sourceRoot: string;
29
+ projectRoot: string;
30
+ screenName?: string; // Specific screen or all
31
+ dryRun: boolean; // Preview changes without writing
32
+ force: boolean; // Overwrite existing data-testid
33
+ verbose: boolean;
34
+ preserveFormatting: boolean; // Use Prettier if available
35
+ }
36
+
37
+ export interface TaggingResult {
38
+ filePath: string;
39
+ totalElements: number;
40
+ taggedElements: number;
41
+ skippedElements: number;
42
+ changes: ElementChange[];
43
+ modified: boolean;
44
+ }
45
+
46
+ export interface ElementChange {
47
+ line: number;
48
+ tag: string;
49
+ generatedId: string;
50
+ action: 'added' | 'skipped' | 'overwritten';
51
+ reason?: string;
52
+ }
53
+
54
+ export interface TaggingStats {
55
+ totalFiles: number;
56
+ modifiedFiles: number;
57
+ totalElements: number;
58
+ taggedElements: number;
59
+ skippedElements: number;
60
+ processingTime: number;
61
+ }
62
+
63
+ // ============================================================================
64
+ // TEST ID GENERATOR
65
+ // ============================================================================
66
+
67
+ class TestIDGenerator {
68
+ private screenName: string;
69
+ private usedIds = new Set<string>();
70
+
71
+ constructor(screenName: string) {
72
+ this.screenName = this.normalize(screenName);
73
+ }
74
+
75
+ /**
76
+ * Generate stable, semantic test ID
77
+ *
78
+ * Format: {screen}-{element}-{type}
79
+ * Examples:
80
+ * - login-email-input
81
+ * - login-password-input
82
+ * - login-submit-btn
83
+ * - dashboard-user-menu-btn
84
+ */
85
+ generate(element: any, index: number): string {
86
+ const tag = element.tag?.toLowerCase() || 'element';
87
+ const props = element.props || {};
88
+
89
+ let elementName = '';
90
+
91
+ // Strategy 1: Use existing name/id/placeholder
92
+ if (props.name) {
93
+ elementName = this.normalize(props.name);
94
+ } else if (props.id) {
95
+ elementName = this.normalize(props.id);
96
+ } else if (props.placeholder) {
97
+ elementName = this.normalize(props.placeholder);
98
+ } else if (element.text && ['button', 'a'].includes(tag)) {
99
+ elementName = this.normalize(element.text);
100
+ } else if (props['aria-label']) {
101
+ elementName = this.normalize(props['aria-label']);
102
+ }
103
+
104
+ // Strategy 2: Use type-based naming
105
+ if (!elementName && props.type) {
106
+ elementName = this.normalize(props.type);
107
+ }
108
+
109
+ // Strategy 3: Fallback to index
110
+ if (!elementName) {
111
+ elementName = `${tag}-${index}`;
112
+ }
113
+
114
+ // Add suffix based on tag
115
+ const suffix = this.getSuffix(tag, props.type);
116
+
117
+ // Combine: screen-element-suffix
118
+ const baseId = `${this.screenName}-${elementName}${suffix}`;
119
+
120
+ // Ensure uniqueness
121
+ let finalId = baseId;
122
+ let counter = 1;
123
+ while (this.usedIds.has(finalId)) {
124
+ finalId = `${baseId}-${counter}`;
125
+ counter++;
126
+ }
127
+
128
+ this.usedIds.add(finalId);
129
+ return finalId;
130
+ }
131
+
132
+ private getSuffix(tag: string, type?: string): string {
133
+ if (tag === 'input') {
134
+ if (type === 'submit') return '-btn';
135
+ return '-input';
136
+ }
137
+
138
+ const suffixMap: Record<string, string> = {
139
+ 'button': '-btn',
140
+ 'a': '-link',
141
+ 'select': '-select',
142
+ 'textarea': '-textarea',
143
+ 'form': '-form',
144
+ };
145
+
146
+ return suffixMap[tag] || '';
147
+ }
148
+
149
+ private normalize(str: string): string {
150
+ return str
151
+ .toLowerCase()
152
+ .replace(/[^a-z0-9]+/g, '-')
153
+ .replace(/^-+|-+$/g, '');
154
+ }
155
+
156
+ reset() {
157
+ this.usedIds.clear();
158
+ }
159
+ }
160
+
161
+ // ============================================================================
162
+ // AST ELEMENT EXTRACTOR
163
+ // ============================================================================
164
+
165
+ class ElementExtractor {
166
+ /**
167
+ * Extract element data from JSX node
168
+ */
169
+ extract(node: t.JSXElement): any {
170
+ const openingElement = node.openingElement;
171
+ const tag = this.getTagName(openingElement.name);
172
+
173
+ // Extract props
174
+ const props: Record<string, any> = {};
175
+ for (const attr of openingElement.attributes) {
176
+ if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
177
+ const name = attr.name.name;
178
+ const value = this.getAttributeValue(attr.value);
179
+ props[name] = value;
180
+ }
181
+ }
182
+
183
+ // Extract text content
184
+ const text = this.extractTextContent(node);
185
+
186
+ return { tag, props, text, node, openingElement };
187
+ }
188
+
189
+ private getTagName(name: any): string {
190
+ if (t.isJSXIdentifier(name)) {
191
+ return name.name.toLowerCase();
192
+ }
193
+ if (t.isJSXMemberExpression(name)) {
194
+ // Handle <Form.Input> → "input"
195
+ return this.getTagName(name.property);
196
+ }
197
+ return 'unknown';
198
+ }
199
+
200
+ private getAttributeValue(value: any): any {
201
+ if (!value) return true; // Boolean attribute
202
+ if (t.isStringLiteral(value)) return value.value;
203
+ if (t.isJSXExpressionContainer(value)) {
204
+ if (t.isStringLiteral(value.expression)) {
205
+ return value.expression.value;
206
+ }
207
+ if (t.isBooleanLiteral(value.expression)) {
208
+ return value.expression.value;
209
+ }
210
+ }
211
+ return undefined;
212
+ }
213
+
214
+ private extractTextContent(node: t.JSXElement): string | null {
215
+ const children = node.children || [];
216
+
217
+ for (const child of children) {
218
+ if (t.isJSXText(child)) {
219
+ const text = child.value.trim();
220
+ if (text) return text;
221
+ }
222
+ if (t.isJSXExpressionContainer(child)) {
223
+ if (t.isStringLiteral(child.expression)) {
224
+ return child.expression.value;
225
+ }
226
+ }
227
+ }
228
+
229
+ return null;
230
+ }
231
+ }
232
+
233
+ // ============================================================================
234
+ // AUTO TAGGER (Main Class)
235
+ // ============================================================================
236
+
237
+ export class AutoTagger {
238
+ private config: AutoTagConfig;
239
+ private extractor = new ElementExtractor();
240
+ private stats: TaggingStats = {
241
+ totalFiles: 0,
242
+ modifiedFiles: 0,
243
+ totalElements: 0,
244
+ taggedElements: 0,
245
+ skippedElements: 0,
246
+ processingTime: 0,
247
+ };
248
+
249
+ // Interactive elements that should have data-testid
250
+ private readonly INTERACTIVE_TAGS = ['input', 'button', 'a', 'select', 'textarea', 'form'];
251
+
252
+ constructor(config: AutoTagConfig) {
253
+ this.config = config;
254
+ }
255
+
256
+ /**
257
+ * Tag a specific screen or all screens
258
+ */
259
+ async tag(): Promise<TaggingStats> {
260
+ const startTime = Date.now();
261
+
262
+ if (this.config.screenName) {
263
+ await this.tagScreen(this.config.screenName);
264
+ } else {
265
+ await this.tagAllScreens();
266
+ }
267
+
268
+ this.stats.processingTime = Date.now() - startTime;
269
+ return this.stats;
270
+ }
271
+
272
+ /**
273
+ * Tag a specific screen
274
+ */
275
+ private async tagScreen(screenName: string): Promise<void> {
276
+ const files = this.findSourceFiles(screenName);
277
+
278
+ if (files.length === 0) {
279
+ console.log(`⚠️ No source files found for screen: ${screenName}`);
280
+ return;
281
+ }
282
+
283
+ console.log(`📂 Found ${files.length} files for screen: ${screenName}\n`);
284
+
285
+ for (const file of files) {
286
+ await this.tagFile(file, screenName);
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Tag all screens (scan entire source root)
292
+ */
293
+ private async tagAllScreens(): Promise<void> {
294
+ console.log('📂 Scanning all source files...\n');
295
+
296
+ const allFiles = this.findAllSourceFiles(this.config.sourceRoot);
297
+ console.log(`Found ${allFiles.length} files\n`);
298
+
299
+ for (const file of allFiles) {
300
+ const screenName = this.inferScreenName(file);
301
+ await this.tagFile(file, screenName);
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Tag a single file
307
+ */
308
+ private async tagFile(filePath: string, screenName: string): Promise<TaggingResult> {
309
+ this.stats.totalFiles++;
310
+
311
+ const relativePath = path.relative(this.config.projectRoot, filePath);
312
+ console.log(`📄 Processing: ${relativePath}`);
313
+
314
+ // Read file
315
+ const code = fs.readFileSync(filePath, 'utf-8');
316
+
317
+ // Parse with Babel
318
+ let ast;
319
+ try {
320
+ ast = parser.parse(code, {
321
+ sourceType: 'module',
322
+ plugins: ['jsx', 'typescript'],
323
+ });
324
+ } catch (error) {
325
+ console.log(` ⚠️ Parse error, skipping\n`);
326
+ return this.createEmptyResult(filePath);
327
+ }
328
+
329
+ // Tag elements in AST
330
+ const result = await this.tagAST(ast, filePath, screenName);
331
+
332
+ // Write back if modified and not dry-run
333
+ if (result.modified && !this.config.dryRun) {
334
+ const newCode = generate(ast, {
335
+ retainLines: true,
336
+ comments: true,
337
+ }).code;
338
+
339
+ fs.writeFileSync(filePath, newCode, 'utf-8');
340
+ this.stats.modifiedFiles++;
341
+
342
+ console.log(` ✓ Modified (${result.taggedElements} elements tagged)\n`);
343
+ } else if (result.modified && this.config.dryRun) {
344
+ console.log(` 🔍 Would modify (${result.taggedElements} elements)\n`);
345
+ } else {
346
+ console.log(` ○ No changes needed\n`);
347
+ }
348
+
349
+ return result;
350
+ }
351
+
352
+ /**
353
+ * Tag elements in AST
354
+ */
355
+ private async tagAST(ast: any, filePath: string, screenName: string): Promise<TaggingResult> {
356
+ const idGenerator = new TestIDGenerator(screenName);
357
+ const changes: ElementChange[] = [];
358
+ let totalElements = 0;
359
+ let taggedElements = 0;
360
+ let skippedElements = 0;
361
+ let modified = false;
362
+
363
+ let elementIndex = 0;
364
+
365
+ traverse(ast, {
366
+ JSXElement: (path: NodePath<t.JSXElement>) => {
367
+ const node = path.node;
368
+ const element = this.extractor.extract(node);
369
+
370
+ // Only process interactive elements
371
+ if (!this.shouldTag(element)) {
372
+ return;
373
+ }
374
+
375
+ totalElements++;
376
+ elementIndex++;
377
+
378
+ // Check if already has data-testid
379
+ const existingTestId = this.findAttribute(element.openingElement, 'data-testid');
380
+
381
+ if (existingTestId && !this.config.force) {
382
+ skippedElements++;
383
+ changes.push({
384
+ line: node.loc?.start.line || 0,
385
+ tag: element.tag,
386
+ generatedId: existingTestId,
387
+ action: 'skipped',
388
+ reason: 'Already has data-testid',
389
+ });
390
+ return;
391
+ }
392
+
393
+ // Generate test ID
394
+ const testId = idGenerator.generate(element, elementIndex);
395
+
396
+ // Add or replace data-testid attribute
397
+ if (existingTestId && this.config.force) {
398
+ // Overwrite
399
+ this.setAttribute(element.openingElement, 'data-testid', testId);
400
+ taggedElements++;
401
+ modified = true;
402
+ changes.push({
403
+ line: node.loc?.start.line || 0,
404
+ tag: element.tag,
405
+ generatedId: testId,
406
+ action: 'overwritten',
407
+ reason: `Replaced ${existingTestId}`,
408
+ });
409
+ } else {
410
+ // Add new
411
+ this.addAttribute(element.openingElement, 'data-testid', testId);
412
+ taggedElements++;
413
+ modified = true;
414
+ changes.push({
415
+ line: node.loc?.start.line || 0,
416
+ tag: element.tag,
417
+ generatedId: testId,
418
+ action: 'added',
419
+ });
420
+ }
421
+ },
422
+ });
423
+
424
+ this.stats.totalElements += totalElements;
425
+ this.stats.taggedElements += taggedElements;
426
+ this.stats.skippedElements += skippedElements;
427
+
428
+ return {
429
+ filePath,
430
+ totalElements,
431
+ taggedElements,
432
+ skippedElements,
433
+ changes,
434
+ modified,
435
+ };
436
+ }
437
+
438
+ /**
439
+ * Determine if element should be tagged
440
+ */
441
+ private shouldTag(element: any): boolean {
442
+ const tag = element.tag?.toLowerCase();
443
+ return this.INTERACTIVE_TAGS.includes(tag);
444
+ }
445
+
446
+ /**
447
+ * Find existing attribute value
448
+ */
449
+ private findAttribute(openingElement: t.JSXOpeningElement, name: string): string | null {
450
+ for (const attr of openingElement.attributes) {
451
+ if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name) {
452
+ if (t.isStringLiteral(attr.value)) {
453
+ return attr.value.value;
454
+ }
455
+ }
456
+ }
457
+ return null;
458
+ }
459
+
460
+ /**
461
+ * Set attribute value (replace if exists)
462
+ */
463
+ private setAttribute(openingElement: t.JSXOpeningElement, name: string, value: string): void {
464
+ for (const attr of openingElement.attributes) {
465
+ if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === name) {
466
+ attr.value = t.stringLiteral(value);
467
+ return;
468
+ }
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Add new attribute
474
+ */
475
+ private addAttribute(openingElement: t.JSXOpeningElement, name: string, value: string): void {
476
+ const newAttr = t.jsxAttribute(
477
+ t.jsxIdentifier(name),
478
+ t.stringLiteral(value)
479
+ );
480
+ openingElement.attributes.push(newAttr);
481
+ }
482
+
483
+ /**
484
+ * Find source files for a screen
485
+ */
486
+ private findSourceFiles(screenName: string): string[] {
487
+ const patterns = [
488
+ path.join(this.config.sourceRoot, `${screenName}/page.tsx`),
489
+ path.join(this.config.sourceRoot, `${screenName}/index.tsx`),
490
+ path.join(this.config.sourceRoot, `${screenName}.tsx`),
491
+ path.join(this.config.sourceRoot, `${screenName}/page.js`),
492
+ path.join(this.config.sourceRoot, `${screenName}/index.js`),
493
+ path.join(this.config.sourceRoot, `${screenName}.js`),
494
+ ];
495
+
496
+ const found: string[] = [];
497
+ for (const pattern of patterns) {
498
+ if (fs.existsSync(pattern)) {
499
+ found.push(pattern);
500
+ }
501
+ }
502
+
503
+ return found;
504
+ }
505
+
506
+ /**
507
+ * Find all source files recursively
508
+ */
509
+ private findAllSourceFiles(dir: string): string[] {
510
+ const files: string[] = [];
511
+
512
+ const scan = (currentDir: string) => {
513
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
514
+
515
+ for (const entry of entries) {
516
+ const fullPath = path.join(currentDir, entry.name);
517
+
518
+ // Skip node_modules, .git, etc.
519
+ if (entry.name.startsWith('.') || entry.name === 'node_modules') {
520
+ continue;
521
+ }
522
+
523
+ if (entry.isDirectory()) {
524
+ scan(fullPath);
525
+ } else if (entry.isFile()) {
526
+ // Only process .tsx, .jsx, .ts, .js files
527
+ if (/\.(tsx|jsx|ts|js)$/.test(entry.name)) {
528
+ files.push(fullPath);
529
+ }
530
+ }
531
+ }
532
+ };
533
+
534
+ scan(dir);
535
+ return files;
536
+ }
537
+
538
+ /**
539
+ * Infer screen name from file path
540
+ */
541
+ private inferScreenName(filePath: string): string {
542
+ const relativePath = path.relative(this.config.sourceRoot, filePath);
543
+ const parts = relativePath.split(path.sep);
544
+
545
+ // Use first directory as screen name
546
+ if (parts.length > 1) {
547
+ return parts[0];
548
+ }
549
+
550
+ // Use filename without extension
551
+ const fileName = path.basename(filePath, path.extname(filePath));
552
+ return fileName === 'page' || fileName === 'index' ? 'app' : fileName;
553
+ }
554
+
555
+ private createEmptyResult(filePath: string): TaggingResult {
556
+ return {
557
+ filePath,
558
+ totalElements: 0,
559
+ taggedElements: 0,
560
+ skippedElements: 0,
561
+ changes: [],
562
+ modified: false,
563
+ };
564
+ }
565
+
566
+ /**
567
+ * Get statistics
568
+ */
569
+ getStats(): TaggingStats {
570
+ return { ...this.stats };
571
+ }
572
+ }