@sun-asterisk/sungen 1.0.20 → 1.0.21

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 (286) hide show
  1. package/dist/cli/commands/add.d.ts +3 -0
  2. package/dist/cli/commands/add.d.ts.map +1 -0
  3. package/dist/cli/commands/add.js +27 -0
  4. package/dist/cli/commands/add.js.map +1 -0
  5. package/dist/cli/commands/cache-clear.d.ts +3 -0
  6. package/dist/cli/commands/cache-clear.d.ts.map +1 -0
  7. package/dist/cli/commands/cache-clear.js +24 -0
  8. package/dist/cli/commands/cache-clear.js.map +1 -0
  9. package/dist/cli/commands/full.d.ts +3 -0
  10. package/dist/cli/commands/full.d.ts.map +1 -0
  11. package/dist/cli/commands/full.js +37 -0
  12. package/dist/cli/commands/full.js.map +1 -0
  13. package/dist/cli/commands/generate.d.ts +3 -0
  14. package/dist/cli/commands/generate.d.ts.map +1 -0
  15. package/dist/cli/commands/generate.js +53 -0
  16. package/dist/cli/commands/generate.js.map +1 -0
  17. package/dist/cli/commands/init.d.ts +3 -0
  18. package/dist/cli/commands/init.d.ts.map +1 -0
  19. package/dist/cli/commands/init.js +20 -0
  20. package/dist/cli/commands/init.js.map +1 -0
  21. package/dist/cli/commands/live-scan.d.ts +3 -0
  22. package/dist/cli/commands/live-scan.d.ts.map +1 -0
  23. package/dist/cli/commands/{live-scan-command.js → live-scan.js} +8 -15
  24. package/dist/cli/commands/live-scan.js.map +1 -0
  25. package/dist/cli/commands/makeauth.d.ts +3 -0
  26. package/dist/cli/commands/makeauth.d.ts.map +1 -0
  27. package/dist/cli/commands/makeauth.js +76 -0
  28. package/dist/cli/commands/makeauth.js.map +1 -0
  29. package/dist/cli/commands/map.d.ts +3 -0
  30. package/dist/cli/commands/map.d.ts.map +1 -0
  31. package/dist/cli/commands/map.js +93 -0
  32. package/dist/cli/commands/map.js.map +1 -0
  33. package/dist/cli/commands/validate.d.ts +3 -0
  34. package/dist/cli/commands/validate.d.ts.map +1 -0
  35. package/dist/cli/commands/validate.js +43 -0
  36. package/dist/cli/commands/validate.js.map +1 -0
  37. package/dist/cli/index.js +29 -442
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/cli/types.d.ts +9 -0
  40. package/dist/cli/types.d.ts.map +1 -0
  41. package/dist/cli/types.js +7 -0
  42. package/dist/cli/types.js.map +1 -0
  43. package/dist/cli/utils.d.ts +6 -0
  44. package/dist/cli/utils.d.ts.map +1 -0
  45. package/dist/cli/utils.js +101 -0
  46. package/dist/cli/utils.js.map +1 -0
  47. package/dist/core/live-scanner/matrix-reader.d.ts.map +1 -1
  48. package/dist/core/live-scanner/matrix-reader.js +2 -40
  49. package/dist/core/live-scanner/matrix-reader.js.map +1 -1
  50. package/dist/core/live-scanner/step-replayer.d.ts.map +1 -1
  51. package/dist/core/live-scanner/step-replayer.js +7 -0
  52. package/dist/core/live-scanner/step-replayer.js.map +1 -1
  53. package/dist/core/validator/selector-validator.d.ts.map +1 -1
  54. package/dist/core/validator/selector-validator.js +2 -1
  55. package/dist/core/validator/selector-validator.js.map +1 -1
  56. package/dist/generators/scaffold-generator/index.d.ts +2 -1
  57. package/dist/generators/scaffold-generator/index.d.ts.map +1 -1
  58. package/dist/generators/scaffold-generator/index.js +21 -1
  59. package/dist/generators/scaffold-generator/index.js.map +1 -1
  60. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  61. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  62. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  63. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  64. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  65. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  66. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  67. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  68. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  69. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  70. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  71. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  72. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  73. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  74. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  75. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  76. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  77. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  78. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  79. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  80. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  81. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  82. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  83. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  84. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  85. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  86. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  87. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  88. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  89. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  90. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  91. package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
  92. package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -58
  93. package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
  94. package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -2
  95. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
  96. package/dist/generators/test-generator/patterns/form-patterns.js +34 -47
  97. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
  98. package/dist/generators/test-generator/patterns/index.d.ts +3 -1
  99. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  100. package/dist/generators/test-generator/patterns/index.js +20 -3
  101. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  102. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -1
  103. package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
  104. package/dist/generators/test-generator/patterns/interaction-patterns.js +44 -85
  105. package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
  106. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +7 -0
  107. package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +1 -0
  108. package/dist/generators/test-generator/patterns/legacy-patterns.js +98 -0
  109. package/dist/generators/test-generator/patterns/legacy-patterns.js.map +1 -0
  110. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -2
  111. package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
  112. package/dist/generators/test-generator/patterns/navigation-patterns.js +14 -42
  113. package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
  114. package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -1
  115. package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -1
  116. package/dist/generators/test-generator/patterns/setup-patterns.js +23 -35
  117. package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -1
  118. package/dist/generators/test-generator/patterns/types.d.ts +18 -3
  119. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  120. package/dist/generators/test-generator/step-mapper.d.ts +0 -15
  121. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  122. package/dist/generators/test-generator/step-mapper.js +4 -106
  123. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  124. package/dist/{executor/test-generator.d.ts → generators/test-generator/types.d.ts} +4 -25
  125. package/dist/generators/test-generator/types.d.ts.map +1 -0
  126. package/dist/generators/test-generator/types.js +106 -0
  127. package/dist/generators/test-generator/types.js.map +1 -0
  128. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  129. package/dist/generators/test-generator/utils/data-resolver.js +8 -17
  130. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  131. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  132. package/dist/generators/test-generator/utils/selector-resolver.js +10 -18
  133. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  134. package/dist/orchestrator/cache-manager.d.ts +1 -23
  135. package/dist/orchestrator/cache-manager.d.ts.map +1 -1
  136. package/dist/orchestrator/cache-manager.js +1 -87
  137. package/dist/orchestrator/cache-manager.js.map +1 -1
  138. package/dist/orchestrator/pipeline.d.ts +11 -28
  139. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  140. package/dist/orchestrator/pipeline.js +52 -371
  141. package/dist/orchestrator/pipeline.js.map +1 -1
  142. package/dist/orchestrator/reporter.d.ts +1 -1
  143. package/dist/orchestrator/reporter.d.ts.map +1 -1
  144. package/dist/orchestrator/screen-manager.js +1 -1
  145. package/dist/orchestrator/screen-manager.js.map +1 -1
  146. package/dist/utils/feature-finder.d.ts +9 -0
  147. package/dist/utils/feature-finder.d.ts.map +1 -0
  148. package/dist/utils/feature-finder.js +67 -0
  149. package/dist/utils/feature-finder.js.map +1 -0
  150. package/dist/utils/screen-paths.d.ts +10 -0
  151. package/dist/utils/screen-paths.d.ts.map +1 -0
  152. package/dist/utils/screen-paths.js +73 -0
  153. package/dist/utils/screen-paths.js.map +1 -0
  154. package/dist/utils/selector-loader.d.ts +6 -0
  155. package/dist/utils/selector-loader.d.ts.map +1 -0
  156. package/dist/utils/selector-loader.js +20 -0
  157. package/dist/utils/selector-loader.js.map +1 -0
  158. package/dist/utils/selector-types.d.ts +7 -0
  159. package/dist/utils/selector-types.d.ts.map +1 -0
  160. package/dist/utils/selector-types.js +19 -0
  161. package/dist/utils/selector-types.js.map +1 -0
  162. package/dist/utils/test-data-loader.d.ts +6 -0
  163. package/dist/utils/test-data-loader.d.ts.map +1 -0
  164. package/dist/utils/test-data-loader.js +20 -0
  165. package/dist/utils/test-data-loader.js.map +1 -0
  166. package/dist/utils/yaml-io.d.ts +14 -0
  167. package/dist/utils/yaml-io.d.ts.map +1 -0
  168. package/dist/utils/yaml-io.js +72 -0
  169. package/dist/utils/yaml-io.js.map +1 -0
  170. package/package.json +1 -1
  171. package/src/cli/commands/add.ts +25 -0
  172. package/src/cli/commands/cache-clear.ts +22 -0
  173. package/src/cli/commands/full.ts +35 -0
  174. package/src/cli/commands/generate.ts +55 -0
  175. package/src/cli/commands/init.ts +17 -0
  176. package/src/cli/commands/{live-scan-command.ts → live-scan.ts} +8 -17
  177. package/src/cli/commands/makeauth.ts +77 -0
  178. package/src/cli/commands/map.ts +97 -0
  179. package/src/cli/commands/validate.ts +43 -0
  180. package/src/cli/index.ts +32 -473
  181. package/src/cli/types.ts +9 -0
  182. package/src/cli/utils.ts +106 -0
  183. package/src/core/live-scanner/matrix-reader.ts +2 -8
  184. package/src/core/live-scanner/step-replayer.ts +7 -0
  185. package/src/core/validator/selector-validator.ts +3 -2
  186. package/src/generators/scaffold-generator/index.ts +23 -2
  187. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
  188. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
  189. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
  190. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
  191. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
  192. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
  193. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
  194. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
  195. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
  196. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
  197. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
  198. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
  199. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
  200. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
  201. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
  202. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
  203. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
  204. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
  205. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
  206. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
  207. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -1
  208. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  209. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -0
  210. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
  211. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
  212. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
  213. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
  214. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
  215. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
  216. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
  217. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
  218. package/src/generators/test-generator/patterns/assertion-patterns.ts +102 -62
  219. package/src/generators/test-generator/patterns/form-patterns.ts +38 -60
  220. package/src/generators/test-generator/patterns/index.ts +22 -4
  221. package/src/generators/test-generator/patterns/interaction-patterns.ts +47 -107
  222. package/src/generators/test-generator/patterns/legacy-patterns.ts +104 -0
  223. package/src/generators/test-generator/patterns/navigation-patterns.ts +27 -69
  224. package/src/generators/test-generator/patterns/setup-patterns.ts +23 -41
  225. package/src/generators/test-generator/patterns/types.ts +26 -9
  226. package/src/generators/test-generator/step-mapper.ts +4 -124
  227. package/src/generators/test-generator/types.ts +131 -0
  228. package/src/generators/test-generator/utils/data-resolver.ts +8 -13
  229. package/src/generators/test-generator/utils/selector-resolver.ts +15 -17
  230. package/src/orchestrator/cache-manager.ts +1 -107
  231. package/src/orchestrator/pipeline.ts +58 -433
  232. package/src/orchestrator/reporter.ts +1 -1
  233. package/src/orchestrator/screen-manager.ts +1 -1
  234. package/src/utils/feature-finder.ts +33 -0
  235. package/src/utils/screen-paths.ts +37 -0
  236. package/src/utils/selector-loader.ts +23 -0
  237. package/src/utils/selector-types.ts +17 -0
  238. package/src/utils/test-data-loader.ts +23 -0
  239. package/src/utils/yaml-io.ts +33 -0
  240. package/dist/cli/commands/auto-tag-command.d.ts +0 -8
  241. package/dist/cli/commands/auto-tag-command.d.ts.map +0 -1
  242. package/dist/cli/commands/auto-tag-command.js +0 -104
  243. package/dist/cli/commands/auto-tag-command.js.map +0 -1
  244. package/dist/cli/commands/live-scan-command.d.ts +0 -9
  245. package/dist/cli/commands/live-scan-command.d.ts.map +0 -1
  246. package/dist/cli/commands/live-scan-command.js.map +0 -1
  247. package/dist/executor/playwright/playwright-generator.d.ts +0 -33
  248. package/dist/executor/playwright/playwright-generator.d.ts.map +0 -1
  249. package/dist/executor/playwright/playwright-generator.js +0 -136
  250. package/dist/executor/playwright/playwright-generator.js.map +0 -1
  251. package/dist/executor/test-generator.d.ts.map +0 -1
  252. package/dist/executor/test-generator.js +0 -30
  253. package/dist/executor/test-generator.js.map +0 -1
  254. package/dist/generators/cli.d.ts +0 -7
  255. package/dist/generators/cli.d.ts.map +0 -1
  256. package/dist/generators/cli.js +0 -570
  257. package/dist/generators/cli.js.map +0 -1
  258. package/dist/input/cli-adapter.d.ts +0 -75
  259. package/dist/input/cli-adapter.d.ts.map +0 -1
  260. package/dist/input/cli-adapter.js +0 -218
  261. package/dist/input/cli-adapter.js.map +0 -1
  262. package/dist/input/config-adapter.d.ts +0 -25
  263. package/dist/input/config-adapter.d.ts.map +0 -1
  264. package/dist/input/config-adapter.js +0 -70
  265. package/dist/input/config-adapter.js.map +0 -1
  266. package/dist/input/input-adapter.d.ts +0 -28
  267. package/dist/input/input-adapter.d.ts.map +0 -1
  268. package/dist/input/input-adapter.js +0 -17
  269. package/dist/input/input-adapter.js.map +0 -1
  270. package/dist/input/vscode-adapter.d.ts +0 -62
  271. package/dist/input/vscode-adapter.d.ts.map +0 -1
  272. package/dist/input/vscode-adapter.js +0 -64
  273. package/dist/input/vscode-adapter.js.map +0 -1
  274. package/dist/tools/auto-tagger.d.ts +0 -107
  275. package/dist/tools/auto-tagger.d.ts.map +0 -1
  276. package/dist/tools/auto-tagger.js +0 -502
  277. package/dist/tools/auto-tagger.js.map +0 -1
  278. package/src/cli/commands/auto-tag-command.ts +0 -80
  279. package/src/executor/playwright/playwright-generator.ts +0 -125
  280. package/src/executor/test-generator.ts +0 -90
  281. package/src/generators/cli.ts +0 -640
  282. package/src/input/cli-adapter.ts +0 -233
  283. package/src/input/config-adapter.ts +0 -71
  284. package/src/input/input-adapter.ts +0 -32
  285. package/src/input/vscode-adapter.ts +0 -90
  286. package/src/tools/auto-tagger.ts +0 -572
@@ -1,640 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * CLI for Selector DSL Generator
4
- * Commands: discover, generate, validate, cache-clear, info
5
- */
6
-
7
- import { config as loadEnv } from 'dotenv';
8
- import { Command } from 'commander';
9
- import chalk from 'chalk';
10
- import ora from 'ora';
11
- import * as path from 'path';
12
- import * as fs from 'fs';
13
- import * as yaml from 'yaml';
14
-
15
- // Load environment variables
16
- loadEnv({ path: '.env.local' });
17
- loadEnv(); // Also load .env if exists
18
-
19
- // Import generators
20
- import { ReactScanner, buildUIModel, discoverScreens } from './ui-model-builder/react-scanner';
21
- import { AIMapper, mapSelectors } from './selector-mapper/ai-mapper';
22
- import { writeDSL, loadDSL, validateDSL, createOverrideTemplate } from './dsl-writer';
23
- import { CacheManager, createCacheManager } from './cache/cache-manager';
24
- import { UIModel } from './types';
25
-
26
- // ============================================================================
27
- // Configuration
28
- // ============================================================================
29
-
30
- const PROJECT_ROOT = process.cwd();
31
- const SOURCE_ROOT = path.join(PROJECT_ROOT, 'app'); // Next.js app directory
32
- const UI_MODEL_PATH = path.join(PROJECT_ROOT, 'qa/ui-models');
33
- const SELECTOR_PATH = path.join(PROJECT_ROOT, 'qa/selectors');
34
- const CACHE_PATH = path.join(PROJECT_ROOT, 'qa/selectors/.cache');
35
-
36
- const DEFAULT_CONFIG = {
37
- sourceRoot: SOURCE_ROOT,
38
- uiModelPath: UI_MODEL_PATH,
39
- selectorPath: SELECTOR_PATH,
40
- cachePath: CACHE_PATH,
41
- framework: 'react-nextjs' as const,
42
- aiProvider: (process.env.AI_PROVIDER || 'google') as 'anthropic' | 'google',
43
- enableCache: true
44
- };
45
-
46
- // ============================================================================
47
- // CLI Program
48
- // ============================================================================
49
-
50
- const program = new Command();
51
-
52
- program
53
- .name('qa-generator')
54
- .description('AI-Native QA Selector DSL Generator')
55
- .version('1.0.20');
56
-
57
- // ============================================================================
58
- // Command: discover
59
- // ============================================================================
60
-
61
- program
62
- .command('discover')
63
- .description('Discover screens and generate UI models')
64
- .option('-s, --screen <id>', 'Specific screen to discover')
65
- .option('-a, --all', 'Discover all screens')
66
- .option('-f, --force', 'Force re-scan even if cached')
67
- .option('-v, --verbose', 'Verbose output')
68
- .option('-d, --depth <number>', 'Component scan depth (default: unlimited)', '999')
69
- .action(async (options) => {
70
- const spinner = ora('Discovering screens...').start();
71
-
72
- try {
73
- const maxDepth = parseInt(options.depth, 10);
74
- const scanner = new ReactScanner({
75
- sourceRoot: SOURCE_ROOT,
76
- framework: 'react-nextjs',
77
- verbose: options.verbose,
78
- maxDepth: maxDepth
79
- });
80
-
81
- // Discover all screens
82
- const screens = await scanner.discoverScreens();
83
- spinner.succeed(`Found ${screens.length} screens`);
84
-
85
- console.log(chalk.cyan('\nScreens found:'));
86
- screens.forEach(screen => console.log(chalk.gray(` - ${screen}`)));
87
-
88
- // Build UI models
89
- const screensToScan = options.screen ? [options.screen] : (options.all ? screens : []);
90
-
91
- if (screensToScan.length === 0) {
92
- console.log(chalk.yellow('\nNo screens selected. Use --screen <id> or --all'));
93
- return;
94
- }
95
-
96
- fs.mkdirSync(UI_MODEL_PATH, { recursive: true });
97
-
98
- for (const screenId of screensToScan) {
99
- const screenSpinner = ora(`Scanning ${screenId}...`).start();
100
-
101
- try {
102
- const uiModel = await scanner.buildUIModel(screenId);
103
-
104
- // Save UI model
105
- const outputPath = path.join(UI_MODEL_PATH, `${screenId}.json`);
106
- fs.writeFileSync(outputPath, JSON.stringify(uiModel, null, 2), 'utf-8');
107
-
108
- screenSpinner.succeed(`${screenId}: ${uiModel.elements.length} elements`);
109
- } catch (error) {
110
- screenSpinner.fail(`${screenId}: ${(error as Error).message}`);
111
- }
112
- }
113
-
114
- console.log(chalk.green('\n✓ Discovery complete'));
115
- } catch (error) {
116
- spinner.fail('Discovery failed');
117
- console.error(chalk.red((error as Error).message));
118
- process.exit(1);
119
- }
120
- });
121
-
122
- // ============================================================================
123
- // Command: generate
124
- // ============================================================================
125
-
126
- program
127
- .command('generate')
128
- .description('Generate selectors from UI models')
129
- .option('-s, --screen <id>', 'Specific screen to generate')
130
- .option('-a, --all', 'Generate all screens')
131
- .option('-f, --force', 'Force re-generation (skip cache)')
132
- .option('--provider <provider>', 'AI provider (anthropic|google)', DEFAULT_CONFIG.aiProvider)
133
- .option('--model <model>', 'Specific AI model to use')
134
- .option('-v, --verbose', 'Verbose output')
135
- .action(async (options) => {
136
- const spinner = ora('Generating selectors...').start();
137
-
138
- try {
139
- // Extract selectors from Gherkin first
140
- const { GherkinSelectorExtractor } = require('./gherkin-parser/selector-extractor');
141
- const extractor = new GherkinSelectorExtractor();
142
- const featuresDir = path.join(PROJECT_ROOT, 'qa/features');
143
-
144
- const selectorsByScreen = extractor.extractSelectors(featuresDir);
145
- spinner.succeed(`Extracted selectors from Gherkin for ${Object.keys(selectorsByScreen).length} screen(s)`);
146
-
147
- // Initialize cache manager
148
- const cacheManager = createCacheManager({
149
- cachePath: CACHE_PATH,
150
- enabled: !options.force
151
- });
152
-
153
- // Get screens to generate
154
- const availableScreens = Object.keys(selectorsByScreen);
155
-
156
- const screensToGenerate = options.screen
157
- ? [options.screen]
158
- : (options.all ? availableScreens : []);
159
-
160
- if (screensToGenerate.length === 0) {
161
- console.log(chalk.yellow('No screens selected. Use --screen <id> or --all'));
162
- return;
163
- }
164
-
165
- let totalGenerated = 0;
166
- let totalCached = 0;
167
-
168
- for (const screenId of screensToGenerate) {
169
- const screenSpinner = ora(`Generating ${screenId}...`).start();
170
-
171
- try {
172
- // Load UI model
173
- const uiModelPath = path.join(UI_MODEL_PATH, `${screenId}.json`);
174
- if (!fs.existsSync(uiModelPath)) {
175
- screenSpinner.fail(`${screenId}: UI model not found`);
176
- continue;
177
- }
178
-
179
- const uiModel: UIModel = JSON.parse(fs.readFileSync(uiModelPath, 'utf-8'));
180
-
181
- // Get element IDs from Gherkin (not from UI model!)
182
- const screenSelectors = selectorsByScreen[screenId];
183
- if (!screenSelectors || Object.keys(screenSelectors).length === 0) {
184
- screenSpinner.warn(`${screenId}: No selectors referenced in Gherkin`);
185
- continue;
186
- }
187
-
188
- const elementIds = Object.keys(screenSelectors).map(elementId =>
189
- screenSelectors[elementId].fullRef
190
- );
191
-
192
- // Check cache
193
- const cacheKey = cacheManager.generateCacheKey(screenId, uiModel, elementIds);
194
- const cached = cacheManager.get(screenId, cacheKey);
195
-
196
- if (cached && !options.force) {
197
- // Use cached selectors
198
- await writeDSL(cached.selectors, {
199
- outputPath: SELECTOR_PATH,
200
- screenId
201
- });
202
-
203
- screenSpinner.succeed(`${screenId}: ${Object.keys(cached.selectors).length} selectors (cached)`);
204
- totalCached++;
205
- continue;
206
- }
207
-
208
- // Generate with AI
209
- const result = await mapSelectors(uiModel, elementIds, {
210
- provider: options.provider,
211
- model: options.model,
212
- verbose: options.verbose
213
- });
214
-
215
- // Write DSL
216
- await writeDSL(result.selectors, {
217
- outputPath: SELECTOR_PATH,
218
- screenId
219
- });
220
-
221
- // Cache result
222
- cacheManager.set(screenId, cacheKey, result.selectors, {
223
- aiModel: result.metadata.aiModel,
224
- tokenCost: result.metadata.tokenCost,
225
- framework: uiModel.framework
226
- });
227
-
228
- const tokenInfo = result.metadata.tokenCost
229
- ? chalk.gray(` (${result.metadata.tokenCost} tokens)`)
230
- : '';
231
-
232
- screenSpinner.succeed(`${screenId}: ${Object.keys(result.selectors).length} selectors${tokenInfo}`);
233
- totalGenerated++;
234
- } catch (error) {
235
- screenSpinner.fail(`${screenId}: ${(error as Error).message}`);
236
- }
237
- }
238
-
239
- console.log(chalk.green(`\n✓ Generated: ${totalGenerated}, Cached: ${totalCached}`));
240
- } catch (error) {
241
- spinner.fail('Generation failed');
242
- console.error(chalk.red((error as Error).message));
243
- process.exit(1);
244
- }
245
- });
246
-
247
- // ============================================================================
248
- // Command: validate
249
- // ============================================================================
250
-
251
- program
252
- .command('validate')
253
- .description('Validate selector DSL files')
254
- .option('-s, --screen <id>', 'Specific screen to validate')
255
- .option('-a, --all', 'Validate all screens')
256
- .action(async (options) => {
257
- const spinner = ora('Validating selectors...').start();
258
-
259
- try {
260
- const screensDir = path.join(SELECTOR_PATH, 'screens');
261
- if (!fs.existsSync(screensDir)) {
262
- spinner.fail('No selector files found');
263
- return;
264
- }
265
-
266
- const selectorFiles = fs.readdirSync(screensDir).filter(f => f.endsWith('.yaml') && !f.includes('.override.'));
267
- const availableScreens = selectorFiles.map(f => f.replace('.yaml', ''));
268
-
269
- const screensToValidate = options.screen
270
- ? [options.screen]
271
- : (options.all ? availableScreens : []);
272
-
273
- if (screensToValidate.length === 0) {
274
- spinner.fail('No screens selected');
275
- console.log(chalk.yellow('Use --screen <id> or --all'));
276
- return;
277
- }
278
-
279
- let totalValid = 0;
280
- let totalInvalid = 0;
281
-
282
- for (const screenId of screensToValidate) {
283
- const result = await validateDSL({
284
- selectorPath: SELECTOR_PATH,
285
- screenId
286
- });
287
-
288
- if (result.valid) {
289
- console.log(chalk.green(`✓ ${screenId}: Valid`));
290
- totalValid++;
291
- } else {
292
- console.log(chalk.red(`✗ ${screenId}: Invalid`));
293
- result.errors.forEach(error => {
294
- console.log(chalk.gray(` - ${error}`));
295
- });
296
- totalInvalid++;
297
- }
298
- }
299
-
300
- spinner.stop();
301
- console.log(chalk.cyan(`\nTotal: ${totalValid} valid, ${totalInvalid} invalid`));
302
-
303
- if (totalInvalid > 0) {
304
- process.exit(1);
305
- }
306
- } catch (error) {
307
- spinner.fail('Validation failed');
308
- console.error(chalk.red((error as Error).message));
309
- process.exit(1);
310
- }
311
- });
312
-
313
- // ============================================================================
314
- // Command: cache-clear
315
- // ============================================================================
316
-
317
- program
318
- .command('cache-clear')
319
- .description('Clear selector cache')
320
- .option('-s, --screen <id>', 'Clear cache for specific screen')
321
- .option('-a, --all', 'Clear all cache')
322
- .action(async (options) => {
323
- const cacheManager = createCacheManager({
324
- cachePath: CACHE_PATH,
325
- enabled: true
326
- });
327
-
328
- if (options.screen) {
329
- const count = cacheManager.invalidate(options.screen);
330
- console.log(chalk.green(`✓ Cleared ${count} cache entries for ${options.screen}`));
331
- } else if (options.all) {
332
- const count = cacheManager.clearAll();
333
- console.log(chalk.green(`✓ Cleared ${count} cache entries`));
334
- } else {
335
- console.log(chalk.yellow('Use --screen <id> or --all'));
336
- }
337
- });
338
-
339
- // ============================================================================
340
- // Command: info
341
- // ============================================================================
342
-
343
- program
344
- .command('info')
345
- .description('Show cache and selector statistics')
346
- .action(async () => {
347
- const cacheManager = createCacheManager({
348
- cachePath: CACHE_PATH,
349
- enabled: true
350
- });
351
-
352
- const stats = cacheManager.getStats();
353
-
354
- console.log(chalk.cyan('\n📊 Cache Statistics:'));
355
- console.log(chalk.gray(` Screens cached: ${stats.totalScreens}`));
356
- console.log(chalk.gray(` Cache entries: ${stats.totalEntries}`));
357
- console.log(chalk.gray(` Total size: ${(stats.totalSize / 1024).toFixed(2)} KB`));
358
-
359
- if (stats.oldestEntry) {
360
- console.log(chalk.gray(` Oldest entry: ${stats.oldestEntry}`));
361
- }
362
- if (stats.newestEntry) {
363
- console.log(chalk.gray(` Newest entry: ${stats.newestEntry}`));
364
- }
365
-
366
- // Selector statistics
367
- const screensDir = path.join(SELECTOR_PATH, 'screens');
368
- if (fs.existsSync(screensDir)) {
369
- const selectorFiles = fs.readdirSync(screensDir).filter(f => f.endsWith('.yaml') && !f.includes('.override.'));
370
-
371
- console.log(chalk.cyan('\n📁 Selector Files:'));
372
- console.log(chalk.gray(` Total screens: ${selectorFiles.length}`));
373
-
374
- for (const file of selectorFiles) {
375
- const screenId = file.replace('.yaml', '');
376
- const content = fs.readFileSync(path.join(screensDir, file), 'utf-8');
377
- const selectors = yaml.parse(content);
378
- const count = Object.keys(selectors || {}).length;
379
-
380
- console.log(chalk.gray(` - ${screenId}: ${count} selectors`));
381
- }
382
- }
383
-
384
- console.log('');
385
- });
386
-
387
- // ============================================================================
388
- // Command: generate-tests
389
- // ============================================================================
390
-
391
- program
392
- .command('generate-tests')
393
- .description('Generate Playwright tests from Gherkin feature files')
394
- .option('-f, --feature <file>', 'Specific feature file to generate')
395
- .option('-a, --all', 'Generate tests for all feature files')
396
- .option('-o, --output <dir>', 'Output directory for generated tests', 'specs/generated')
397
- .option('--ai-mapper', 'Enable AI fallback for unknown Gherkin patterns')
398
- .option('--framework <name>', 'Test framework (playwright, cypress, etc.)')
399
- .option('-v, --verbose', 'Verbose output')
400
- .action(async (options) => {
401
- const spinner = ora('Generating tests from Gherkin...').start();
402
-
403
- try {
404
- const { GherkinParser } = require('./gherkin-parser');
405
- const { CodeGenerator } = require('./test-generator/code-generator');
406
- const { ConfigLoader } = require('../config/config-loader');
407
-
408
- // Load configuration
409
- const configLoader = new ConfigLoader();
410
- const config = configLoader.load(options);
411
-
412
- const featuresDir = path.join(PROJECT_ROOT, 'qa/features');
413
- const outputDir = path.join(PROJECT_ROOT, options.output);
414
-
415
- // Discover feature files
416
- const featureFiles = options.feature
417
- ? [path.join(featuresDir, options.feature)]
418
- : GherkinParser.discoverFeatureFiles(featuresDir);
419
-
420
- if (featureFiles.length === 0) {
421
- spinner.fail('No feature files found');
422
- console.log(chalk.yellow('Create .feature files in qa/features/'));
423
- return;
424
- }
425
-
426
- spinner.succeed(`Found ${featureFiles.length} feature file(s)`);
427
-
428
- // Get framework from CLI option, config file, or default
429
- const framework = options.framework || config.testGenerator.framework || 'playwright';
430
-
431
- // Get baseURL from config (null if not set)
432
- const baseURL = config.app?.baseURL || null;
433
-
434
- // Generate tests
435
- const generator = new CodeGenerator({
436
- useAI: options.aiMapper,
437
- verbose: options.verbose,
438
- framework,
439
- baseURL
440
- });
441
- const results = await generator.generateAllTests(featuresDir, outputDir, featureFiles);
442
-
443
- if (options.aiMapper && options.verbose) {
444
- console.log(chalk.blue('\n ℹ AI-based step mapping enabled for unknown patterns'));
445
- }
446
-
447
- console.log(chalk.green(`\n✓ Generated ${results.length} test file(s) in ${options.output}`));
448
-
449
- results.forEach(result => {
450
- const relativePath = path.relative(PROJECT_ROOT, result.filePath);
451
- console.log(chalk.gray(` - ${relativePath}`));
452
- });
453
-
454
- } catch (error) {
455
- spinner.fail('Test generation failed');
456
- console.error(chalk.red((error as Error).message));
457
- if (options.verbose) {
458
- console.error(error);
459
- }
460
- process.exit(1);
461
- }
462
- });
463
-
464
- // ============================================================================
465
- // Command: full (run complete workflow)
466
- // ============================================================================
467
-
468
- program
469
- .command('full')
470
- .description('Run complete workflow: discover → generate → gen-tests')
471
- .option('-p, --provider <provider>', 'AI provider (anthropic|google)', DEFAULT_CONFIG.aiProvider)
472
- .option('--model <model>', 'Specific AI model to use')
473
- .option('--ai-mapper', 'Enable AI fallback for unknown Gherkin patterns')
474
- .option('--framework <name>', 'Test framework (playwright, cypress, etc.)')
475
- .option('-v, --verbose', 'Verbose output')
476
- .action(async (options) => {
477
- console.log(chalk.cyan.bold('\n🚀 Running Full QA Workflow\n'));
478
-
479
- // Load configuration
480
- const { ConfigLoader } = require('../config/config-loader');
481
- const configLoader = new ConfigLoader();
482
- const config = configLoader.load(options);
483
-
484
- // Step 1: Discover
485
- console.log(chalk.cyan('Step 1/3: Discovering screens...'));
486
- const discoverSpinner = ora('Scanning source code').start();
487
-
488
- try {
489
- const scanner = new ReactScanner({
490
- sourceRoot: SOURCE_ROOT,
491
- framework: 'react-nextjs',
492
- verbose: options.verbose
493
- });
494
-
495
- const screens = await scanner.discoverScreens();
496
-
497
- fs.mkdirSync(UI_MODEL_PATH, { recursive: true });
498
-
499
- for (const screenId of screens) {
500
- const uiModel = await scanner.buildUIModel(screenId);
501
- const outputPath = path.join(UI_MODEL_PATH, `${screenId}.json`);
502
- fs.writeFileSync(outputPath, JSON.stringify(uiModel, null, 2), 'utf-8');
503
- }
504
-
505
- discoverSpinner.succeed(`Discovered ${screens.length} screens`);
506
- } catch (error) {
507
- discoverSpinner.fail('Discovery failed');
508
- console.error(chalk.red((error as Error).message));
509
- process.exit(1);
510
- }
511
-
512
- // Step 2: Generate Selectors
513
- console.log(chalk.cyan('\nStep 2/3: Generating selectors with AI...'));
514
-
515
- // First, extract selectors from Gherkin
516
- const extractSpinner = ora('Extracting selectors from Gherkin').start();
517
-
518
- try {
519
- const { GherkinSelectorExtractor } = require('./gherkin-parser/selector-extractor');
520
- const extractor = new GherkinSelectorExtractor();
521
- const featuresDir = path.join(PROJECT_ROOT, 'qa/features');
522
-
523
- const selectorsByScreen = extractor.extractSelectors(featuresDir);
524
- extractSpinner.succeed(`Extracted selectors from Gherkin for ${Object.keys(selectorsByScreen).length} screen(s)`);
525
-
526
- // Now generate selectors with AI
527
- const generateSpinner = ora('Calling AI to generate selectors').start();
528
-
529
- const cacheManager = createCacheManager({
530
- cachePath: CACHE_PATH,
531
- enabled: true
532
- });
533
-
534
- const uiModelFiles = fs.readdirSync(UI_MODEL_PATH).filter(f => f.endsWith('.json'));
535
- let totalGenerated = 0;
536
- let totalCached = 0;
537
-
538
- for (const file of uiModelFiles) {
539
- const screenId = file.replace('.json', '');
540
- const uiModelPath = path.join(UI_MODEL_PATH, file);
541
- const uiModel: UIModel = JSON.parse(fs.readFileSync(uiModelPath, 'utf-8'));
542
-
543
- // Get element IDs from Gherkin (not from UI model!)
544
- const screenSelectors = selectorsByScreen[screenId];
545
- if (!screenSelectors || Object.keys(screenSelectors).length === 0) {
546
- // Skip screens with no Gherkin references
547
- continue;
548
- }
549
-
550
- const elementIds = Object.keys(screenSelectors).map(elementId =>
551
- screenSelectors[elementId].fullRef
552
- );
553
-
554
- const cacheKey = cacheManager.generateCacheKey(screenId, uiModel, elementIds);
555
- const cached = cacheManager.get(screenId, cacheKey);
556
-
557
- if (cached) {
558
- await writeDSL(cached.selectors, {
559
- outputPath: SELECTOR_PATH,
560
- screenId
561
- });
562
- totalCached++;
563
- } else {
564
- const result = await mapSelectors(uiModel, elementIds, {
565
- provider: options.provider,
566
- model: options.model,
567
- verbose: options.verbose
568
- });
569
-
570
- await writeDSL(result.selectors, {
571
- outputPath: SELECTOR_PATH,
572
- screenId
573
- });
574
-
575
- cacheManager.set(screenId, cacheKey, result.selectors, {
576
- aiModel: result.metadata.aiModel,
577
- tokenCost: result.metadata.tokenCost,
578
- framework: uiModel.framework
579
- });
580
- totalGenerated++;
581
- }
582
- }
583
-
584
- generateSpinner.succeed(`Generated selectors: ${totalGenerated} new, ${totalCached} cached`);
585
- } catch (error) {
586
- extractSpinner.fail('Selector generation failed');
587
- console.error(chalk.red((error as Error).message));
588
- process.exit(1);
589
- }
590
-
591
- // Step 3: Generate Tests
592
- console.log(chalk.cyan('\nStep 3/3: Generating Playwright tests from Gherkin...'));
593
- const testGenSpinner = ora('Parsing Gherkin and generating tests').start();
594
-
595
- try {
596
- const { GherkinParser } = require('./gherkin-parser');
597
- const { CodeGenerator } = require('./test-generator/code-generator');
598
-
599
- const featuresDir = path.join(PROJECT_ROOT, 'qa/features');
600
- const outputDir = path.join(PROJECT_ROOT, 'specs/generated');
601
-
602
- const featureFiles = GherkinParser.discoverFeatureFiles(featuresDir);
603
-
604
- if (featureFiles.length === 0) {
605
- testGenSpinner.warn('No feature files found');
606
- } else {
607
- // Get framework from CLI option, config file, or default
608
- const framework = options.framework || config.testGenerator.framework || 'playwright';
609
-
610
- // Get baseURL from config (null if not set)
611
- const baseURL = config.app?.baseURL || null;
612
-
613
- const generator = new CodeGenerator({
614
- useAI: options.aiMapper,
615
- verbose: options.verbose,
616
- framework,
617
- baseURL
618
- });
619
- const results = await generator.generateAllTests(featuresDir, outputDir, featureFiles);
620
- testGenSpinner.succeed(`Generated ${results.length} test file(s)`);
621
- }
622
- } catch (error) {
623
- testGenSpinner.fail('Test generation failed');
624
- console.error(chalk.red((error as Error).message));
625
- process.exit(1);
626
- }
627
-
628
- // Summary
629
- console.log(chalk.green.bold('\n✅ Full workflow completed!\n'));
630
- console.log(chalk.cyan('Next steps:'));
631
- console.log(chalk.gray(' 1. Review generated selectors in qa/selectors/screens/'));
632
- console.log(chalk.gray(' 2. Create override files (*.override.yaml) if needed'));
633
- console.log(chalk.gray(' 3. Run tests: npm run test:qa\n'));
634
- });
635
-
636
- // ============================================================================
637
- // Parse and Execute
638
- // ============================================================================
639
-
640
- program.parse();