@sun-asterisk/sungen 3.2.28 → 3.2.30

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 (486) hide show
  1. package/dist/capabilities/discover.d.ts +29 -0
  2. package/dist/capabilities/discover.d.ts.map +1 -1
  3. package/dist/capabilities/discover.js +144 -10
  4. package/dist/capabilities/discover.js.map +1 -1
  5. package/dist/capabilities/registry.d.ts +18 -0
  6. package/dist/capabilities/registry.d.ts.map +1 -1
  7. package/dist/capabilities/registry.js +25 -0
  8. package/dist/capabilities/registry.js.map +1 -1
  9. package/dist/cli/commands/audit.d.ts.map +1 -1
  10. package/dist/cli/commands/audit.js +9 -0
  11. package/dist/cli/commands/audit.js.map +1 -1
  12. package/dist/cli/commands/capability.js +1 -1
  13. package/dist/cli/commands/capability.js.map +1 -1
  14. package/dist/cli/commands/delivery.d.ts.map +1 -1
  15. package/dist/cli/commands/delivery.js +2 -1
  16. package/dist/cli/commands/delivery.js.map +1 -1
  17. package/dist/cli/commands/generate.d.ts.map +1 -1
  18. package/dist/cli/commands/generate.js +6 -2
  19. package/dist/cli/commands/generate.js.map +1 -1
  20. package/dist/cli/commands/inspect.js +1 -1
  21. package/dist/cli/commands/inspect.js.map +1 -1
  22. package/dist/cli/commands/results-merge.d.ts.map +1 -1
  23. package/dist/cli/commands/results-merge.js +9 -2
  24. package/dist/cli/commands/results-merge.js.map +1 -1
  25. package/dist/cli/commands/results-sanitize.d.ts +24 -0
  26. package/dist/cli/commands/results-sanitize.d.ts.map +1 -0
  27. package/dist/cli/commands/results-sanitize.js +126 -0
  28. package/dist/cli/commands/results-sanitize.js.map +1 -0
  29. package/dist/cli/commands/script-check.d.ts.map +1 -1
  30. package/dist/cli/commands/script-check.js +3 -1
  31. package/dist/cli/commands/script-check.js.map +1 -1
  32. package/dist/cli/commands/update.d.ts.map +1 -1
  33. package/dist/cli/commands/update.js +3 -0
  34. package/dist/cli/commands/update.js.map +1 -1
  35. package/dist/dashboard/templates/index.html +1 -1
  36. package/dist/exporters/api-testcase-formatter.d.ts +3 -6
  37. package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
  38. package/dist/exporters/api-testcase-formatter.js +7 -10
  39. package/dist/exporters/api-testcase-formatter.js.map +1 -1
  40. package/dist/exporters/feature-parser.d.ts +1 -1
  41. package/dist/exporters/feature-parser.js +1 -1
  42. package/dist/exporters/matrix/build.d.ts.map +1 -1
  43. package/dist/exporters/matrix/build.js +18 -3
  44. package/dist/exporters/matrix/build.js.map +1 -1
  45. package/dist/exporters/matrix/item-labels.d.ts +35 -0
  46. package/dist/exporters/matrix/item-labels.d.ts.map +1 -0
  47. package/dist/exporters/matrix/item-labels.js +90 -0
  48. package/dist/exporters/matrix/item-labels.js.map +1 -0
  49. package/dist/exporters/matrix/render-coverage-sheet.d.ts +14 -0
  50. package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -0
  51. package/dist/exporters/matrix/render-coverage-sheet.js +162 -0
  52. package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -0
  53. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  54. package/dist/exporters/matrix/render-csv.js +3 -1
  55. package/dist/exporters/matrix/render-csv.js.map +1 -1
  56. package/dist/exporters/matrix/render-overview-sheet.d.ts +20 -0
  57. package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -0
  58. package/dist/exporters/matrix/render-overview-sheet.js +32 -0
  59. package/dist/exporters/matrix/render-overview-sheet.js.map +1 -0
  60. package/dist/exporters/matrix/render-testcase-sheet.d.ts +30 -0
  61. package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -0
  62. package/dist/exporters/matrix/render-testcase-sheet.js +156 -0
  63. package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -0
  64. package/dist/exporters/matrix/render-xlsx.d.ts +41 -31
  65. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  66. package/dist/exporters/matrix/render-xlsx.js +72 -425
  67. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  68. package/dist/exporters/matrix/result-totals.d.ts +23 -0
  69. package/dist/exporters/matrix/result-totals.d.ts.map +1 -0
  70. package/dist/exporters/matrix/result-totals.js +21 -0
  71. package/dist/exporters/matrix/result-totals.js.map +1 -0
  72. package/dist/exporters/matrix/testcase-summary-band.d.ts +30 -0
  73. package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -0
  74. package/dist/exporters/matrix/testcase-summary-band.js +71 -0
  75. package/dist/exporters/matrix/testcase-summary-band.js.map +1 -0
  76. package/dist/exporters/matrix/wording.d.ts.map +1 -1
  77. package/dist/exporters/matrix/wording.js +13 -0
  78. package/dist/exporters/matrix/wording.js.map +1 -1
  79. package/dist/exporters/matrix/xlsx-cells.d.ts +38 -0
  80. package/dist/exporters/matrix/xlsx-cells.d.ts.map +1 -0
  81. package/dist/exporters/matrix/xlsx-cells.js +52 -0
  82. package/dist/exporters/matrix/xlsx-cells.js.map +1 -0
  83. package/dist/exporters/qa-env-secret-denylist.js +2 -2
  84. package/dist/exporters/qa-env-secret-denylist.js.map +1 -1
  85. package/dist/exporters/report-path-sanitizer.d.ts +38 -0
  86. package/dist/exporters/report-path-sanitizer.d.ts.map +1 -0
  87. package/dist/exporters/report-path-sanitizer.js +137 -0
  88. package/dist/exporters/report-path-sanitizer.js.map +1 -0
  89. package/dist/exporters/result-variants.d.ts.map +1 -1
  90. package/dist/exporters/result-variants.js +2 -1
  91. package/dist/exporters/result-variants.js.map +1 -1
  92. package/dist/exporters/sensitive-key.d.ts +31 -0
  93. package/dist/exporters/sensitive-key.d.ts.map +1 -0
  94. package/dist/exporters/sensitive-key.js +50 -0
  95. package/dist/exporters/sensitive-key.js.map +1 -0
  96. package/dist/exporters/test-data-resolver.d.ts +4 -1
  97. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  98. package/dist/exporters/test-data-resolver.js +12 -2
  99. package/dist/exporters/test-data-resolver.js.map +1 -1
  100. package/dist/exporters/xlsx-report-builder.d.ts +12 -1
  101. package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
  102. package/dist/exporters/xlsx-report-builder.js +10 -2
  103. package/dist/exporters/xlsx-report-builder.js.map +1 -1
  104. package/dist/generators/gherkin-parser/index.d.ts +10 -0
  105. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  106. package/dist/generators/gherkin-parser/index.js +20 -12
  107. package/dist/generators/gherkin-parser/index.js.map +1 -1
  108. package/dist/generators/gherkin-parser/parent-scope-clause.d.ts +54 -0
  109. package/dist/generators/gherkin-parser/parent-scope-clause.d.ts.map +1 -0
  110. package/dist/generators/gherkin-parser/parent-scope-clause.js +109 -0
  111. package/dist/generators/gherkin-parser/parent-scope-clause.js.map +1 -0
  112. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +23 -18
  113. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  114. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +4 -19
  115. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
  116. package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
  117. package/dist/generators/test-generator/adapters/appium/os-support.d.ts +53 -0
  118. package/dist/generators/test-generator/adapters/appium/os-support.d.ts.map +1 -0
  119. package/dist/generators/test-generator/adapters/appium/os-support.js +200 -0
  120. package/dist/generators/test-generator/adapters/appium/os-support.js.map +1 -0
  121. package/dist/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
  122. package/dist/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
  123. package/dist/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
  124. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
  125. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
  126. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
  127. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
  128. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
  129. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
  130. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
  131. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
  132. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
  133. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
  134. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
  135. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
  136. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
  137. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
  138. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
  139. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
  140. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
  141. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
  142. package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
  143. package/dist/generators/test-generator/adapters/index.d.ts +1 -1
  144. package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
  145. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +4 -19
  146. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  147. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  148. package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
  149. package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
  150. package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
  151. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  152. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
  153. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
  154. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
  155. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
  156. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
  157. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
  158. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
  159. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
  160. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
  161. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
  162. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
  163. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
  164. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
  165. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
  166. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
  167. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
  168. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
  169. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
  170. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
  171. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
  172. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  173. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
  174. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
  175. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
  176. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
  177. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
  178. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
  179. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
  180. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
  181. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
  182. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
  183. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
  184. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
  185. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
  186. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
  187. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
  188. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
  189. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
  190. package/dist/generators/test-generator/code-generator.d.ts +37 -0
  191. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  192. package/dist/generators/test-generator/code-generator.js +165 -40
  193. package/dist/generators/test-generator/code-generator.js.map +1 -1
  194. package/dist/generators/test-generator/diagnostics.d.ts +116 -6
  195. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  196. package/dist/generators/test-generator/diagnostics.js +115 -5
  197. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  198. package/dist/generators/test-generator/patterns/index.d.ts +57 -11
  199. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  200. package/dist/generators/test-generator/patterns/index.js +163 -21
  201. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  202. package/dist/generators/test-generator/patterns/types.d.ts +8 -0
  203. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  204. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +18 -0
  205. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -0
  206. package/dist/generators/test-generator/patterns/with-parent-scope.js +40 -0
  207. package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -0
  208. package/dist/generators/test-generator/step-mapper.d.ts +103 -10
  209. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  210. package/dist/generators/test-generator/step-mapper.js +266 -45
  211. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  212. package/dist/generators/test-generator/template-engine.d.ts +4 -19
  213. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  214. package/dist/generators/test-generator/template-engine.js +17 -12
  215. package/dist/generators/test-generator/template-engine.js.map +1 -1
  216. package/dist/generators/test-generator/utils/data-resolver.d.ts +7 -0
  217. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  218. package/dist/generators/test-generator/utils/data-resolver.js +19 -2
  219. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  220. package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts +41 -0
  221. package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts.map +1 -0
  222. package/dist/generators/test-generator/utils/dialog-scope-identity.js +61 -0
  223. package/dist/generators/test-generator/utils/dialog-scope-identity.js.map +1 -0
  224. package/dist/generators/test-generator/utils/escape-js-string.d.ts +17 -0
  225. package/dist/generators/test-generator/utils/escape-js-string.d.ts.map +1 -0
  226. package/dist/generators/test-generator/utils/escape-js-string.js +29 -0
  227. package/dist/generators/test-generator/utils/escape-js-string.js.map +1 -0
  228. package/dist/generators/test-generator/utils/nearest-match.d.ts +24 -0
  229. package/dist/generators/test-generator/utils/nearest-match.d.ts.map +1 -0
  230. package/dist/generators/test-generator/utils/nearest-match.js +56 -0
  231. package/dist/generators/test-generator/utils/nearest-match.js.map +1 -0
  232. package/dist/generators/test-generator/utils/selector-entry-fields.d.ts +58 -0
  233. package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -0
  234. package/dist/generators/test-generator/utils/selector-entry-fields.js +119 -0
  235. package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -0
  236. package/dist/generators/test-generator/utils/selector-entry-walk.d.ts +25 -0
  237. package/dist/generators/test-generator/utils/selector-entry-walk.d.ts.map +1 -0
  238. package/dist/generators/test-generator/utils/selector-entry-walk.js +54 -0
  239. package/dist/generators/test-generator/utils/selector-entry-walk.js.map +1 -0
  240. package/dist/generators/test-generator/utils/selector-nth-validation.d.ts +59 -0
  241. package/dist/generators/test-generator/utils/selector-nth-validation.d.ts.map +1 -0
  242. package/dist/generators/test-generator/utils/selector-nth-validation.js +91 -0
  243. package/dist/generators/test-generator/utils/selector-nth-validation.js.map +1 -0
  244. package/dist/generators/test-generator/utils/selector-resolver.d.ts +53 -2
  245. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  246. package/dist/generators/test-generator/utils/selector-resolver.js +273 -27
  247. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  248. package/dist/generators/test-generator/utils/selector-type-validation.d.ts +51 -0
  249. package/dist/generators/test-generator/utils/selector-type-validation.d.ts.map +1 -0
  250. package/dist/generators/test-generator/utils/selector-type-validation.js +77 -0
  251. package/dist/generators/test-generator/utils/selector-type-validation.js.map +1 -0
  252. package/dist/harness/audit.d.ts +3 -1
  253. package/dist/harness/audit.d.ts.map +1 -1
  254. package/dist/harness/audit.js +51 -28
  255. package/dist/harness/audit.js.map +1 -1
  256. package/dist/harness/capability-plan.d.ts +4 -0
  257. package/dist/harness/capability-plan.d.ts.map +1 -1
  258. package/dist/harness/capability-plan.js +32 -2
  259. package/dist/harness/capability-plan.js.map +1 -1
  260. package/dist/harness/catalog/drivers.yaml +1 -1
  261. package/dist/harness/catalog/universal-viewpoints.yaml +145 -0
  262. package/dist/harness/data-driven-lint.d.ts.map +1 -1
  263. package/dist/harness/data-driven-lint.js +217 -33
  264. package/dist/harness/data-driven-lint.js.map +1 -1
  265. package/dist/harness/parse.d.ts +6 -0
  266. package/dist/harness/parse.d.ts.map +1 -1
  267. package/dist/harness/parse.js +1 -1
  268. package/dist/harness/parse.js.map +1 -1
  269. package/dist/harness/repair.d.ts.map +1 -1
  270. package/dist/harness/repair.js +8 -1
  271. package/dist/harness/repair.js.map +1 -1
  272. package/dist/harness/script-check.d.ts +2 -2
  273. package/dist/harness/script-check.d.ts.map +1 -1
  274. package/dist/harness/script-check.js +186 -25
  275. package/dist/harness/script-check.js.map +1 -1
  276. package/dist/harness/sensors.d.ts +48 -0
  277. package/dist/harness/sensors.d.ts.map +1 -1
  278. package/dist/harness/sensors.js +26 -1
  279. package/dist/harness/sensors.js.map +1 -1
  280. package/dist/harness/viewpoint-ledger.d.ts +10 -0
  281. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  282. package/dist/harness/viewpoint-ledger.js +23 -2
  283. package/dist/harness/viewpoint-ledger.js.map +1 -1
  284. package/dist/index.d.ts +2 -0
  285. package/dist/index.d.ts.map +1 -1
  286. package/dist/index.js +10 -1
  287. package/dist/index.js.map +1 -1
  288. package/dist/orchestrator/project-initializer.d.ts +6 -0
  289. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  290. package/dist/orchestrator/project-initializer.js +16 -0
  291. package/dist/orchestrator/project-initializer.js.map +1 -1
  292. package/dist/orchestrator/report-sanitize-reporter-install.d.ts +24 -0
  293. package/dist/orchestrator/report-sanitize-reporter-install.d.ts.map +1 -0
  294. package/dist/orchestrator/report-sanitize-reporter-install.js +161 -0
  295. package/dist/orchestrator/report-sanitize-reporter-install.js.map +1 -0
  296. package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -3
  297. package/dist/orchestrator/templates/ai-src/commands/run-test.md +9 -1
  298. package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
  299. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
  300. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
  301. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
  302. package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
  303. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
  304. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
  305. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
  306. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
  307. package/dist/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
  308. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
  309. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
  310. package/dist/orchestrator/templates/playwright.config.ts +7 -0
  311. package/dist/orchestrator/templates/readme.md +1 -1
  312. package/dist/orchestrator/templates/specs-checked-state.d.ts +83 -0
  313. package/dist/orchestrator/templates/specs-checked-state.d.ts.map +1 -0
  314. package/dist/orchestrator/templates/specs-checked-state.js +261 -0
  315. package/dist/orchestrator/templates/specs-checked-state.js.map +1 -0
  316. package/dist/orchestrator/templates/specs-checked-state.ts +324 -0
  317. package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  318. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts +36 -0
  319. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts.map +1 -0
  320. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js +155 -0
  321. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js.map +1 -0
  322. package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
  323. package/dist/orchestrator/templates/specs-url-assert.d.ts +50 -25
  324. package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
  325. package/dist/orchestrator/templates/specs-url-assert.js +65 -24
  326. package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
  327. package/dist/orchestrator/templates/specs-url-assert.ts +101 -28
  328. package/dist/orchestrator/templates/wdio.conf.ts +105 -1
  329. package/dist/utils/selector-types.d.ts +43 -1
  330. package/dist/utils/selector-types.d.ts.map +1 -1
  331. package/dist/utils/selector-types.js +51 -7
  332. package/dist/utils/selector-types.js.map +1 -1
  333. package/package.json +3 -3
  334. package/src/capabilities/discover.ts +146 -10
  335. package/src/capabilities/registry.ts +30 -0
  336. package/src/cli/commands/audit.ts +9 -0
  337. package/src/cli/commands/capability.ts +1 -1
  338. package/src/cli/commands/delivery.ts +2 -1
  339. package/src/cli/commands/generate.ts +5 -2
  340. package/src/cli/commands/inspect.ts +1 -1
  341. package/src/cli/commands/results-merge.ts +9 -2
  342. package/src/cli/commands/results-sanitize.ts +98 -0
  343. package/src/cli/commands/script-check.ts +3 -1
  344. package/src/cli/commands/update.ts +3 -0
  345. package/src/dashboard/templates/index.html +1 -1
  346. package/src/exporters/api-testcase-formatter.ts +5 -7
  347. package/src/exporters/feature-parser.ts +1 -1
  348. package/src/exporters/matrix/build.ts +17 -3
  349. package/src/exporters/matrix/item-labels.ts +78 -0
  350. package/src/exporters/matrix/render-coverage-sheet.ts +170 -0
  351. package/src/exporters/matrix/render-csv.ts +3 -1
  352. package/src/exporters/matrix/render-overview-sheet.ts +51 -0
  353. package/src/exporters/matrix/render-testcase-sheet.ts +178 -0
  354. package/src/exporters/matrix/render-xlsx.ts +67 -448
  355. package/src/exporters/matrix/result-totals.ts +37 -0
  356. package/src/exporters/matrix/testcase-summary-band.ts +74 -0
  357. package/src/exporters/matrix/wording.ts +13 -0
  358. package/src/exporters/matrix/xlsx-cells.ts +56 -0
  359. package/src/exporters/qa-env-secret-denylist.ts +1 -1
  360. package/src/exporters/report-path-sanitizer.ts +144 -0
  361. package/src/exporters/result-variants.ts +2 -1
  362. package/src/exporters/sensitive-key.ts +48 -0
  363. package/src/exporters/test-data-resolver.ts +12 -2
  364. package/src/exporters/xlsx-report-builder.ts +16 -2
  365. package/src/generators/gherkin-parser/index.ts +22 -11
  366. package/src/generators/gherkin-parser/parent-scope-clause.ts +130 -0
  367. package/src/generators/test-generator/adapters/adapter-interface.ts +25 -3
  368. package/src/generators/test-generator/adapters/appium/appium-adapter.ts +4 -4
  369. package/src/generators/test-generator/adapters/appium/os-support.ts +176 -0
  370. package/src/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
  371. package/src/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
  372. package/src/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
  373. package/src/generators/test-generator/adapters/appium/templates/steps/actions/alert-fill-action.hbs +9 -2
  374. package/src/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
  375. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
  376. package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
  377. package/src/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
  378. package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
  379. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-action.hbs +6 -2
  380. package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
  381. package/src/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
  382. package/src/generators/test-generator/adapters/appium/templates/steps/actions/unknown-element-action.hbs +9 -0
  383. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
  384. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
  385. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
  386. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/go-back-action.hbs +21 -0
  387. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
  388. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
  389. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/set-geolocation-action.hbs +16 -0
  390. package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
  391. package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +62 -23
  392. package/src/generators/test-generator/adapters/index.ts +1 -1
  393. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +4 -4
  394. package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
  395. package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
  396. package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
  397. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  398. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
  399. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
  400. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
  401. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
  402. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +7 -2
  403. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
  404. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
  405. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
  406. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
  407. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
  408. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
  409. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
  410. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
  411. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
  412. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
  413. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
  414. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
  415. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
  416. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
  417. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
  418. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
  419. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +21 -3
  420. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
  421. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
  422. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
  423. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
  424. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
  425. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -2
  426. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
  427. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
  428. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -1
  429. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
  430. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +8 -8
  431. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
  432. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
  433. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
  434. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
  435. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
  436. package/src/generators/test-generator/code-generator.ts +181 -46
  437. package/src/generators/test-generator/diagnostics.ts +117 -6
  438. package/src/generators/test-generator/patterns/index.ts +175 -24
  439. package/src/generators/test-generator/patterns/types.ts +8 -0
  440. package/src/generators/test-generator/patterns/with-parent-scope.ts +41 -0
  441. package/src/generators/test-generator/step-mapper.ts +277 -43
  442. package/src/generators/test-generator/template-engine.ts +21 -21
  443. package/src/generators/test-generator/utils/data-resolver.ts +23 -2
  444. package/src/generators/test-generator/utils/dialog-scope-identity.ts +71 -0
  445. package/src/generators/test-generator/utils/escape-js-string.ts +24 -0
  446. package/src/generators/test-generator/utils/nearest-match.ts +55 -0
  447. package/src/generators/test-generator/utils/selector-entry-fields.ts +131 -0
  448. package/src/generators/test-generator/utils/selector-entry-walk.ts +58 -0
  449. package/src/generators/test-generator/utils/selector-nth-validation.ts +99 -0
  450. package/src/generators/test-generator/utils/selector-resolver.ts +333 -28
  451. package/src/generators/test-generator/utils/selector-type-validation.ts +87 -0
  452. package/src/harness/audit.ts +55 -30
  453. package/src/harness/capability-plan.ts +33 -1
  454. package/src/harness/catalog/drivers.yaml +1 -1
  455. package/src/harness/catalog/universal-viewpoints.yaml +145 -0
  456. package/src/harness/data-driven-lint.ts +192 -32
  457. package/src/harness/parse.ts +7 -1
  458. package/src/harness/repair.ts +8 -1
  459. package/src/harness/script-check.ts +186 -21
  460. package/src/harness/sensors.ts +75 -1
  461. package/src/harness/viewpoint-ledger.ts +26 -5
  462. package/src/index.ts +7 -0
  463. package/src/orchestrator/project-initializer.ts +17 -0
  464. package/src/orchestrator/report-sanitize-reporter-install.ts +109 -0
  465. package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -3
  466. package/src/orchestrator/templates/ai-src/commands/run-test.md +9 -1
  467. package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
  468. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -5
  469. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
  470. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
  471. package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
  472. package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
  473. package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
  474. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
  475. package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
  476. package/src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
  477. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
  478. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
  479. package/src/orchestrator/templates/playwright.config.ts +7 -0
  480. package/src/orchestrator/templates/readme.md +1 -1
  481. package/src/orchestrator/templates/specs-checked-state.ts +324 -0
  482. package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  483. package/src/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
  484. package/src/orchestrator/templates/specs-url-assert.ts +101 -28
  485. package/src/orchestrator/templates/wdio.conf.ts +105 -1
  486. package/src/utils/selector-types.ts +54 -5
@@ -10,6 +10,13 @@
10
10
  * SG-W002 — step parsed a {{dataRef}} value but the generated code never uses it
11
11
  * SG-W003 — `name` filter defaulted from the Gherkin reference on a name-from-content
12
12
  * role (status/alert/…) — such a filter can never match; opt out with `name: null`
13
+ * SG-W004 — a selectors.yaml entry declares a field no consumer reads, so writing it has no
14
+ * effect on the generated test. Reserved for this in the original diagnostics spec
15
+ * (`exact: true` with no construct it applies to) and implemented for the wider class
16
+ * by #712, where `pagination:` and `contenteditable:` were public, documented,
17
+ * plumbed — and read by nothing. The field partition lives in
18
+ * utils/selector-entry-fields.ts; a field added there without a named consumer is
19
+ * the bug this code exists to catch.
13
20
  * SG-W005 — qa/app.yaml problem (unknown key, unknown preset, unparseable)
14
21
  * SG-W006 — qa/app.<env>.yaml found (per-environment profiles are unsupported by design)
15
22
  * SG-W007 — browser-alert handler step written AFTER an action step: the listener
@@ -45,6 +52,12 @@
45
52
  * "3 cards are shown" gets an assertion that can only pass if the card's text
46
53
  * IS the digit. Count semantics exist on row/table ("see [T] table with {{n}}",
47
54
  * "see [Ref] row with {{n}}") and lists ("should have count") only
55
+ * SG-W016 — a table step on a table located by CSS/testid whose value does not mention `table`
56
+ * and that declares no `rows:`. The table templates find rows by `getByRole('row')`;
57
+ * on a <div> list that is 0 elements, so `is hidden` / `is empty` pass without checking
58
+ * anything and counts/clicks time out (issue #688). A heuristic — the compiler cannot
59
+ * see the DOM — so a warning that names both ways out: `rows: '<row shape>'` on the
60
+ * table entry, or `role: table`. Once per table per feature
48
61
  * SG-E024 — a mobile app-lifecycle step (restart / reinstall) in a feature that declares no
49
62
  * `Path:` app id. The templates resolve the app through a helper the test-file only
50
63
  * emits when the id is present, so the spec used to compile clean and then die at
@@ -53,6 +66,23 @@
53
66
  * but the generated code is a BARE VISIBILITY check: the clause was swallowed by the
54
67
  * catch-all and the test would pass whatever the element says. Four separate defects
55
68
  * have arrived this way, so the step compiles to a runtime throw instead.
69
+ * SG-W017 — a step needs a selector-entry field the entry does not declare, so there is nothing
70
+ * honest to compile. Today: a table paginate step whose table declares no
71
+ * `pagination.next`/`.prev` (#712). The mirror of SG-W004 — that one reports a field
72
+ * written that nothing reads, this one a field a consumer needs that nobody wrote.
73
+ * Compiles the step to a loud runtime throw rather than guessing a locator, which is
74
+ * the #690 failure (a locator no page has, failing far from the cause).
75
+ * SG-W018 — a selectors.yaml entry declares an `nth:` the compiler cannot use (#720). `nth:` was
76
+ * the one entry field whose VALUE nothing checked: the key is known (SG-W004 quiet) and
77
+ * the `type:` is valid (SG-E027 quiet), so `nth: -1`, `nth: 'last'`, `nth: 1.5` and
78
+ * `nth: -2` all compiled clean — the web side dropped the filter entirely (identical to
79
+ * deleting the line, then a strict-mode violation naming the DOM) while the mobile side
80
+ * emitted `$$('~x')[-1]` / `[last]`, undefined-indexing and a bare identifier that even
81
+ * the SG-E022 parse check reads as valid JavaScript. The contract is an integer `>= -1`
82
+ * (`0..N` a zero-based index, `-1` the last match); anything else is normalised away
83
+ * before it reaches a template, and reported here so "ignored" is stated rather than
84
+ * discovered. A warning, on SG-W004's reasoning — the value is inert once dropped and
85
+ * `--strict` already turns the channel non-zero
56
86
  * SG-E020 — the step matched a pattern whose template the ACTIVE adapter does not ship. Before
57
87
  * the platform SPI this was an unhandled `Template not found` that killed the WHOLE
58
88
  * feature file and named neither the step nor the adapter. The step now compiles to a
@@ -74,7 +104,10 @@
74
104
  * (11), the clause vanished, and the step compiled to `toHaveURL(...)` — asserting the
75
105
  * page IS displayed, the exact opposite of what it reads as, and passing while doing so.
76
106
  * The pattern layer declares what it accounts for via `StepPattern.states`; anything
77
- * undeclared reports here and compiles to a loud `throw`
107
+ * undeclared reports here and compiles to a loud `throw`. One shape is NOT the author's:
108
+ * a pattern NAMED for the state (`is-hidden`) with no `states` at all is a
109
+ * @sungen/driver-* older than core — the message then names `sungen update` as the
110
+ * fix, and discovery prefers core's own copy of a bundled driver over a stale project one
78
111
  * SG-W022 — a `page` assertion on the mobile adapter that emitted NO executable code. A native app
79
112
  * has no URL, so `Then User see [X] page` compiles to a bare comment: the step reads as
80
113
  * an assertion, checks nothing, and the scenario PASSES regardless. Worse than the
@@ -91,6 +124,40 @@
91
124
  * mobile suite already carrying one of these steps. The remedy is a feature-level reset
92
125
  * tier (`@reset:data`), which is what the message names — app state is reset between
93
126
  * scenarios in the `beforeEach` hook, not mid-scenario by a step.
127
+ * SG-E025 — a feature that declares `@platform:ios` uses a step the Appium adapter does NOT serve
128
+ * on iOS. The template ships and the step compiles, so nothing about the feature file
129
+ * looks wrong; on a simulator it either throws deep in the run (set-connectivity,
130
+ * location-services, open-notifications) or — worse — silently does nothing
131
+ * (hide-keyboard, guarded `if (!driver.isIOS …)`). Derived from the template body via
132
+ * the per-OS axis of the step-support matrix, so it cannot disagree with the adapter.
133
+ * SCOPE, stated plainly because the name oversells it: only `@platform:ios` is caught.
134
+ * A feature tagged `@platform:mobile` runs on whichever OS `MOBILE_PLATFORM` selects at
135
+ * RUN time, so the compiler cannot know — the matrix, not this code, is the net that
136
+ * covers that case. Reported as an E-code and compiled to a loud throw, because the
137
+ * feature has declared the one OS where the step is known not to work.
138
+ * SG-E026 — a click step names a POSITION (`at position "top-left"`, `at offset x=…, y=…`) that
139
+ * would not be honoured: the keyword is misspelt, a value is outside the grammar (not a
140
+ * number, negative, above 100%, a missing axis, an unknown preset), or another click form
141
+ * claimed the step first (`try to click`, a `with {{v}}` text filter, `… and accept [OK]
142
+ * alert`). Each of those would compile to a click on the element's CENTRE and pass — for a
143
+ * backdrop-dismiss overlay that is the one outcome that proves nothing — so the step
144
+ * compiles to a loud throw instead
145
+ * SG-W026 — a mobile ACTIVE-NAVIGATION step that emitted NO executable code, so a promised screen
146
+ * change never happens. `When User open [Settings] page` compiles to the one-line
147
+ * `navigation` template — a comment noting the app was already launched by the wdio
148
+ * capabilities — so the step reads as "go to Settings" and goes nowhere. Pair it with a
149
+ * `page` assertion (itself a no-op, reported as SG-W022) and the scenario passes without
150
+ * ever touching the app. Completes a half-finished class: `route-assertion` already
151
+ * throws and `page-assertion` already reports W022; only `navigation` was silent.
152
+ * Scoped to the ACTIVE forms (`open [X] page`, `navigate to [X] page`). The `is on [X]
153
+ * page|screen` anchor is EXCLUDED on purpose: that is mobile's app-launch directive and
154
+ * its empty output is correct, so warning on it would cry wolf on valid features — and a
155
+ * diagnostic that cries wolf gets filtered out, taking the real ones with it.
156
+ * Like W021/W022/W023 this stays a WARNING by default. `generate --strict` already fails
157
+ * on ANY diagnostic, so this code is blocking under it from the day it lands — which
158
+ * means a project running --strict today with an `open [X] page` step starts failing.
159
+ * That is the intended outcome (the step was never navigating), but it is a migration
160
+ * step, not a silent one: the message names the tap/gesture rewrite.
94
161
  * SG-W024 — two or more scenarios in one feature share a name and at least ONE carries a `@reset:`
95
162
  * tag. The generated per-scenario lookup is keyed on the scenario NAME (a @cases title is
96
163
  * built at runtime, so no compile-time key can match the rendered title), so every
@@ -101,6 +168,15 @@
101
168
  * Reported rather than resolved by precedence — two tests genuinely sharing one title
102
169
  * cannot be told apart by a name-keyed lookup, so the only honest fix is a rename. Silently
103
170
  * picking a winner would be the same silent-discard shape as SG-W021
171
+ * SG-E027 — a selectors.yaml entry declares a `type:` that is not a selector type at all. YAML is
172
+ * untyped at run time, so `type: 'testId'` (capital I), `'xpth'`, `'rol'` or any other
173
+ * misspelling used to compile clean and resolve through the strategy switch's
174
+ * `default:` branch as `getByPlaceholder('<the value>')` — a locator that cannot
175
+ * match, failing much later as a timeout naming placeholder text the author never
176
+ * wrote. Checked where the selector FILE is loaded rather than in the switch: `page`
177
+ * legitimately reaches that `default:` on every page assertion, and the load point can
178
+ * name the entry key and the nearest valid spelling. Reported once per entry, and
179
+ * every step naming that entry compiles to a `throw`
104
180
  * SG-E022 — the generated spec is not parseable JS/TS, so NOTHING in the file runs — Playwright
105
181
  * reports one SyntaxError and every scenario in the unit is lost. A compiler self-check
106
182
  * (@babel/parser) on the emitted code, added after a field report where the runtime-data
@@ -109,16 +185,50 @@
109
185
  * compiler, not the Gherkin: it should be impossible, and it is reported so a broken
110
186
  * build names itself at generate time instead of one step further downstream
111
187
  *
188
+ * SG-W028 — a step's trailing scope clause was DROPPED, so the step runs against more of the page
189
+ * than its sentence names. Two causes, one code: the `<word>` after `in [X]` is not a
190
+ * container type (a typo, or a leaf element used as a parent), or the by-content form
191
+ * `in [X] <type> with {{v}}` was written for the mobile adapter, which chains a parent
192
+ * element and has no content filter. Before this, both compiled clean and silently
193
+ * widened the assertion to the whole screen — the failure mode that only a diff of the
194
+ * generated spec against the Gherkin could reveal (#667)
195
+ * SG-W029 — a mobile (appium) feature compiled with NO usable app-package `Path:` — either the line
196
+ * is missing outright, or it holds a web-style route (`Path: /applied-jobs`) that the
197
+ * package guard rejects. Both used to be silent, and both cost the same two things: the
198
+ * per-scenario `beforeEach` was not emitted at all, so Background dropped to Mocha's
199
+ * `before()` (once per FILE, every scenario sharing one continuous app session — a tab
200
+ * switch or a scroll in one scenario stranding elements off-screen for every later one),
201
+ * and the `@reset:` tier ladder went with it, leaving the tag inert. The spec now always
202
+ * emits the reset machinery and resolves the app id from the session capability that
203
+ * wdio.conf sets, throwing a named error when nothing supplies one — so this is a
204
+ * warning about an under-declared feature file, not a broken build (#669)
205
+ * SG-W030 — a selectors.yaml `expanded.class`/`expanded.attribute` carries a character outside the
206
+ * accepted class/attribute-name set (whitespace, a quote, a backslash, `$`, `{`, `}`).
207
+ * The value is pasted into the generated spec (string literal, regex, classList argument),
208
+ * and selectors.yaml is often generated from the page under test, so it is refused and the
209
+ * field dropped — the step falls back to driving/asserting `aria-expanded`. Reported once
210
+ * per entry and field. A WARNING rather than a refusal because the fallback still tests
211
+ * something; the checked/selected signal has no fallback and is refused outright instead
212
+ *
213
+ * SG-E031 — a selectors.yaml `checked:`/`selected:` declaration the compiler refuses: the two
214
+ * spellings disagree, a class token or attribute name carries whitespace/a quote/a
215
+ * backslash, or one entry declares both a class and an attribute. Each is silent at run
216
+ * time — the matcher would never match and the step would time out blaming the
217
+ * component — so the declaration is refused rather than compiled. Unlike the expanded
218
+ * signal (SG-W030) it is not dropped-and-warned: with no signal the step is back on the
219
+ * failure the declaration exists to fix. Recorded here AND thrown, so a pattern that
220
+ * resolves selectors inside a `catch` cannot swallow it silently
112
221
  * Diagnostics never change the EXIT CODE by themselves; `sungen generate --strict` turns any
113
222
  * collected diagnostic into a non-zero exit. They are not all inert, though: SG-W001, SG-W011,
114
- * SG-E020, SG-E021, SG-W020, SG-E023 and SG-E024 additionally compile the offending step to a runtime
115
- * `throw`, because a step that reads as a check and silently checks nothing is worse than one that
116
- * fails loudly. (SG-E022 is the one exception to the "blame the Gherkin" rule and throws nothing: the
117
- * file is still written so the user keeps the artifact to inspect.)
223
+ * SG-E020, SG-E021, SG-W020, SG-E023, SG-E024, SG-E025, SG-E026 and SG-E027 additionally compile
224
+ * the offending step to a runtime `throw` — a step that reads as a check and silently checks
225
+ * nothing is worse than one that fails loudly — and SG-E031 refuses the file outright. (SG-E022 is
226
+ * the one exception to the "blame the Gherkin" rule and throws nothing: the file is still written
227
+ * so the user keeps the artifact to inspect.)
118
228
  * Generation always COMPLETES — the rest of the scenario and the rest of the file still compile.
119
229
  */
120
230
 
121
- export type DiagnosticCode = 'SG-W001' | 'SG-W002' | 'SG-W003' | 'SG-W005' | 'SG-W006' | 'SG-W007' | 'SG-W008' | 'SG-W009' | 'SG-W010' | 'SG-W011' | 'SG-W012' | 'SG-W013' | 'SG-W014' | 'SG-W015' | 'SG-E020' | 'SG-E021' | 'SG-W020' | 'SG-W021' | 'SG-W022' | 'SG-W023' | 'SG-W024' | 'SG-E022' | 'SG-E023' | 'SG-E024';
231
+ export type DiagnosticCode = 'SG-W001' | 'SG-W002' | 'SG-W003' | 'SG-W004' | 'SG-W005' | 'SG-W006' | 'SG-W007' | 'SG-W008' | 'SG-W009' | 'SG-W010' | 'SG-W011' | 'SG-W012' | 'SG-W013' | 'SG-W014' | 'SG-W015' | 'SG-W016' | 'SG-W017' | 'SG-W018' | 'SG-E020' | 'SG-E021' | 'SG-W020' | 'SG-W021' | 'SG-W022' | 'SG-W023' | 'SG-W024' | 'SG-W026' | 'SG-E025' | 'SG-E026' | 'SG-E022' | 'SG-E023' | 'SG-E024' | 'SG-E027' | 'SG-W028' | 'SG-W029' | 'SG-W030' | 'SG-E031';
122
232
 
123
233
  export interface Diagnostic {
124
234
  code: DiagnosticCode;
@@ -142,6 +252,7 @@ export class DiagnosticsCollector {
142
252
  return this.items.length;
143
253
  }
144
254
 
255
+
145
256
  /** One line per diagnostic, ready for CLI output. */
146
257
  formatLines(): string[] {
147
258
  return this.items.map((d) => {
@@ -1,10 +1,13 @@
1
1
  import { ParsedStep } from '../../gherkin-parser';
2
2
  import { MappedStep } from '../step-mapper';
3
- import { StepPattern, PatternContext, Platform } from './types';
3
+ import { StepPattern, PatternContext, Platform, StateClause } from './types';
4
4
  import { capabilityRegistry } from '../../../capabilities/registry';
5
5
  import { discoverAndRegisterCapabilities } from '../../../capabilities/discover';
6
6
  import { maskRefsForMatching } from '../utils/mask-refs-for-matching';
7
7
  import { unsupportedStepCode } from './unsupported-step-code';
8
+ import { osSupportOfTemplate } from '../adapters/appium/os-support';
9
+ import { withParentScope } from './with-parent-scope';
10
+ import { escapeSingleQuoted } from '../utils/escape-js-string';
8
11
 
9
12
  // Both helpers moved out of this file so the Gherkin parser (state-clause extraction) and the
10
13
  // step-mapper (SG-W001 no-pattern fallback) can use them without importing the pattern registry.
@@ -31,12 +34,18 @@ const TAP_GESTURE_FORMS = /\bdouble[-\s]?tap|\btap(?:s)?\b[^.]*\b(?:top of|at th
31
34
  * The rewrite is ADDITIVE — `tap` becomes `tap click`, it does not become `click`. Two reasons, and
32
35
  * the first one cost a full golden run to learn:
33
36
  *
34
- * 1. `@sungen/driver-mobile` is registered on WEB projects too (same non-opt-in bundling as
35
- * driver-ui). Substituting the verb re-keys `mobile-tap` onto "click", where its priority 15
36
- * outranks the generic `click-element` (10) — so it captured every plain click on every WEB
37
- * feature and relabelled it a tap. 8 golden fixtures caught it. Adding a verb instead of
38
- * swapping one means text with no "tap" in it is returned untouched, so web output cannot
39
- * change here BY CONSTRUCTION rather than by our vigilance.
37
+ * 1. `@sungen/driver-mobile` can be registered on a WEB project. (It is NOT bundled — an earlier
38
+ * version of this comment said it was, which was never true: it is not in `BUNDLED_DRIVERS`
39
+ * and not a core dependency. Discovery simply loaded whatever it could resolve, which in this
40
+ * monorepo is everything; discovery now gates an opt-in platform driver by the project
41
+ * `platform:`, so this reaches web only when both drivers are present and no platform is
42
+ * declared.) Substituting the verb re-keys `mobile-tap` onto "click", where its
43
+ * priority 15 outranks the generic `click-element` (10) — so it captured every plain click on
44
+ * every WEB feature and relabelled it a tap. 8 golden fixtures caught it. Adding a verb instead
45
+ * of swapping one means text with no "tap" in it is returned untouched, so web output cannot
46
+ * change here BY CONSTRUCTION rather than by our vigilance. `platforms:` does not remove the
47
+ * need for that: `mobile-tap` resolves to `click-action`, which both adapters ship, so it is
48
+ * one of the two mobile patterns that must stay UNDECLARED.
40
49
  * 2. Both vocabularies then see their own verb, and ordinary PRIORITY decides the winner —
41
50
  * no matcher has to learn about the other. `tap … and accept alert` reaches
42
51
  * `click-with-alert` (21); `tap … in [T] table row 2` reaches `table-action-in-row-nth` (19);
@@ -128,6 +137,10 @@ export class PatternRegistry {
128
137
  // Matching mirrors findPattern exactly: refs masked FIRST (so `[Tap Water]` is not a
129
138
  // verb), then `tap` → `click` normalisation for the mobile vocabulary.
130
139
  const matchStep: ParsedStep = { ...step, text: normalizeVerbs(maskRefsForMatching(step.text)) };
140
+ // The step's parent scope, resolved ONCE for the whole search. Not per candidate pattern: a
141
+ // resolver may decline and hand the step to the next one, and re-resolving here would report
142
+ // the mobile by-content refusal (SG-W028) once per attempt instead of once per step.
143
+ const parentScope = PatternRegistry.resolveParentLocator(step, context);
131
144
  for (const pattern of this.patterns) {
132
145
  if (!this.matchesPattern(matchStep, pattern.matcher)) continue;
133
146
 
@@ -137,12 +150,28 @@ export class PatternRegistry {
137
150
  const platformMiss = PatternRegistry.platformMiss(pattern, context, step);
138
151
  if (platformMiss) return platformMiss;
139
152
 
153
+ // Shared by BOTH code paths below. The injection used to live inside the resolver branch, so
154
+ // a `generator` pattern discarded a perfectly parsed scope: `see [Tag] header with {{label}}
155
+ // in [Job Card] section` routes to `see-with-variable` (a generator) and asserted against the
156
+ // whole page (#667). Scope that is parsed and then dropped widens the step just as silently
157
+ // as scope that never parsed at all.
158
+ // `table-*` patterns opt out by name — they resolve the container from the step text
159
+ // themselves and would otherwise scope it twice.
160
+ const parentLocator = pattern.name.startsWith('table-') ? undefined : parentScope;
161
+ const scoped = parentLocator ? withParentScope(context, parentLocator) : context;
162
+
140
163
  try {
141
164
  // Prefer resolver (framework-agnostic) over generator (legacy)
142
165
  if (pattern.resolver) {
143
- const resolved = pattern.resolver(step, context);
166
+ const resolved = pattern.resolver(step, scoped);
144
167
  if (!resolved) continue; // resolver declined — fall through
145
168
 
169
+ // iOS gate — AFTER the resolver, because it needs the template the step actually reached.
170
+ // The sibling of platformMiss above: that one refuses a pattern off-platform, this one
171
+ // refuses a template the declared OS cannot serve.
172
+ const iosMiss = PatternRegistry.iosUnsupported(resolved.templateName, context, step);
173
+ if (iosMiss) return iosMiss;
174
+
146
175
  // State-clause gate. Deliberately AFTER the resolver, not before it: a resolver may return
147
176
  // null to say "not mine after all", and the search then continues to a lower-priority
148
177
  // pattern that may well be the one that asserts the state. Gating earlier judged a pattern
@@ -154,17 +183,16 @@ export class PatternRegistry {
154
183
  if (resolverStateMiss) return resolverStateMiss;
155
184
 
156
185
  // Auto-inject parent scoping if step has parentRef
157
- // Skip for table-* patterns — they resolve the table name internally from step text
158
- if (step.parentRef && step.parentType && !pattern.name.startsWith('table-')) {
159
- resolved.data.parentLocator = PatternRegistry.resolveParentLocator(
160
- step.parentRef, step.parentType, context
161
- );
162
- }
186
+ if (parentLocator) resolved.data.parentLocator = parentLocator;
163
187
 
164
188
  const code = context.templateEngine.renderStep(resolved.templateName, resolved.data);
189
+ // The compiler's post-map guards need to know WHICH form won and what it resolved to (e.g.
190
+ // a refusal a resolver recorded in its data) — without re-matching.
165
191
  return {
166
192
  code,
167
193
  comment: resolved.comment,
194
+ pattern: pattern.name,
195
+ templateData: resolved.data,
168
196
  };
169
197
  }
170
198
 
@@ -172,7 +200,9 @@ export class PatternRegistry {
172
200
  // A legacy generator has no decline path, so this pattern owns the step already.
173
201
  const generatorStateMiss = PatternRegistry.stateMiss(pattern, context, step);
174
202
  if (generatorStateMiss) return generatorStateMiss;
175
- return pattern.generator(step, context);
203
+ // A generator returning nothing still falls through to the no-pattern path.
204
+ const generated = pattern.generator(step, scoped);
205
+ return generated ? { ...generated, pattern: pattern.name } : null;
176
206
  }
177
207
 
178
208
  return null;
@@ -190,6 +220,45 @@ export class PatternRegistry {
190
220
  /**
191
221
  * SG-W020 — the matched pattern declares `platforms` and the active one is not among them.
192
222
  */
223
+ /**
224
+ * SG-E025 — the feature says `@platform:ios`, and the template it reached does not work there.
225
+ *
226
+ * Derived from the template body (`osSupportOfTemplate`), never from a list, so it cannot drift
227
+ * from the adapter the way a hand-kept table would. Two states are refused, for different
228
+ * reasons: `refuses` would throw deep inside a device run instead of at compile time, and `noop`
229
+ * would not fail at all — the step would run, do nothing, and the scenario would pass.
230
+ *
231
+ * Only an EXPLICIT `@platform:ios` is gated. `@platform:mobile` picks its OS from
232
+ * MOBILE_PLATFORM at run time, so gating it would mean guessing; the per-OS matrix columns are
233
+ * what cover that case, and they are the primary deliverable of this axis.
234
+ */
235
+ private static iosUnsupported(
236
+ templateName: string, context: PatternContext, step: ParsedStep
237
+ ): MappedStep | null {
238
+ if (context.featurePlatform !== 'ios') return null;
239
+ if ((context.platform ?? 'web') !== 'mobile') return null;
240
+
241
+ const pair = osSupportOfTemplate(templateName);
242
+ // No appium template of that name is a different failure, already reported by template
243
+ // resolution — a second message here would give one cause two names.
244
+ if (!pair || pair.ios === 'yes' || pair.ios === 'inherit') return null;
245
+
246
+ const why = pair.ios === 'noop'
247
+ ? 'does nothing on iOS — it is guarded out with no error, so the step would run and the scenario would PASS having done nothing'
248
+ : 'throws on iOS — the template refuses there, so the failure would surface deep inside a device run instead of here';
249
+ const reason =
250
+ `step "${step.text}" compiles to \`${templateName}\`, which ${why}. ` +
251
+ `This feature declares @platform:ios. Either drop to @platform:android (the OS that serves this step), ` +
252
+ `move the step out of the iOS feature, or tag the scenario @manual:M10 (device/OS capability). ` +
253
+ `See the Android/iOS columns in docs/spec/step-support-matrix.md.`;
254
+
255
+ context.diagnostics?.add('SG-E025', reason, { feature: context.featureName, step: step.text });
256
+ return {
257
+ code: unsupportedStepCode(reason),
258
+ comment: `iOS-unsupported step in an @platform:ios feature — see SG-E025`,
259
+ };
260
+ }
261
+
193
262
  private static platformMiss(
194
263
  pattern: StepPattern, context: PatternContext, step: ParsedStep
195
264
  ): MappedStep | null {
@@ -241,7 +310,8 @@ export class PatternRegistry {
241
310
  `("${pattern.name}") does not assert that state — the clause would be SILENTLY DROPPED and the ` +
242
311
  `step would check something other than what it reads as. Use a step form that owns the state ` +
243
312
  `(e.g. "User see [Ref] <type> is ${state}" on the element itself), or drop the clause if the ` +
244
- `bare assertion is what you meant. If sungen cannot express the check, tag the scenario @manual.`;
313
+ `bare assertion is what you meant. If sungen cannot express the check, tag the scenario @manual.` +
314
+ PatternRegistry.stateMissSkewHint(pattern, state);
245
315
 
246
316
  context.diagnostics?.add('SG-E021', reason, {
247
317
  feature: context.featureName,
@@ -253,6 +323,23 @@ export class PatternRegistry {
253
323
  };
254
324
  }
255
325
 
326
+ /**
327
+ * The one SG-E021 that is NOT the author's to fix. A pattern NAMED for the state (`is-hidden`,
328
+ * `should-be-disabled`) that declares no `states` at all is not under-annotated — it is a driver
329
+ * built before the field existed, loaded against a core that requires it (a stale project copy of
330
+ * @sungen/driver-ui). The generic message then tells the author to use the exact form they wrote,
331
+ * which cost a QA team a day of Gherkin rewrites that could never work. Name the real cause.
332
+ */
333
+ private static stateMissSkewHint(pattern: StepPattern, state: StateClause): string {
334
+ const namesTheState = pattern.name.includes(state.replace(/\s+/g, '-'));
335
+ if (pattern.states !== undefined || !namesTheState) return '';
336
+ return (
337
+ ` NOTE: "${pattern.name}" is named for this very state yet declares no states at all — that is a ` +
338
+ `@sungen/driver-* package older than sungen itself, not a Gherkin problem. Run \`sungen update\` in the ` +
339
+ `project so the drivers match the sungen version, then generate again.`
340
+ );
341
+ }
342
+
256
343
  /**
257
344
  * SG-E020 — the pattern is in-platform but the active adapter ships no template for it. A gap in
258
345
  * the adapter, not in the authored Gherkin: name every coordinate a reader needs to act on it.
@@ -277,14 +364,23 @@ export class PatternRegistry {
277
364
  }
278
365
 
279
366
  /**
280
- * Resolve parent scoping to a Playwright locator string.
281
- * Tries YAML lookup first, falls back to auto-infer from parentType.
367
+ * Resolve a step's `in [Parent] <type> [with <value>]` scope to a locator string, or `undefined`
368
+ * when the step carries no scope.
282
369
  *
283
- * Parent type → Playwright role:
284
- * table → 'table', list → 'list', section → 'region',
285
- * dialog → 'dialog', form → 'form'
370
+ * Tries YAML lookup first, falls back to auto-inferring a role from the container type with the
371
+ * reference as the accessible name. A reference written as `{{var}}` is resolved through
372
+ * test-data before it reaches that name — containers are routinely labelled with the text under
373
+ * test, and a literal `{{var}}` in the name matches nothing.
286
374
  */
287
- private static resolveParentLocator(
375
+ private static resolveParentLocator(step: ParsedStep, context: PatternContext): string | undefined {
376
+ const { parentRef, parentType } = step;
377
+ if (!parentRef || !parentType) return undefined;
378
+
379
+ const base = PatternRegistry.parentContainerLocator(parentRef, parentType, context);
380
+ return PatternRegistry.filterParentByValue(base, step, context);
381
+ }
382
+
383
+ private static parentContainerLocator(
288
384
  parentRef: string, parentType: string, context: PatternContext
289
385
  ): string {
290
386
  // Try resolving from selectors YAML
@@ -300,13 +396,68 @@ export class PatternRegistry {
300
396
  const roleMap: Record<string, string> = {
301
397
  table: 'table',
302
398
  list: 'list',
399
+ 'list-item': 'listitem',
400
+ listitem: 'listitem',
401
+ item: 'listitem',
402
+ row: 'row',
303
403
  section: 'region',
404
+ container: 'region',
405
+ panel: 'region',
406
+ card: 'region',
407
+ group: 'group',
304
408
  dialog: 'dialog',
409
+ modal: 'dialog',
410
+ drawer: 'dialog',
411
+ overlay: 'dialog',
305
412
  form: 'form',
413
+ tab: 'tabpanel',
414
+ menu: 'menu',
306
415
  };
307
416
  const role = roleMap[parentType] || parentType;
308
- const escapedName = parentRef.replace(/'/g, "\\'");
309
- return `page.getByRole('${role}', { name: '${escapedName}' })`;
417
+ const name = escapeSingleQuoted(PatternRegistry.resolveInlineData(parentRef, context));
418
+ return `page.getByRole('${role}', { name: '${name}' })`;
419
+ }
420
+
421
+ /**
422
+ * Narrow the container to the ONE whose content matches the step's parent value — the
423
+ * `with {{job_title}}` tail of `see [Tag] header with {{label}} in [Job Card] card with
424
+ * {{job_title}}`. Without it a list of identical cards leaves the assertion matching whichever
425
+ * one Playwright reaches first.
426
+ *
427
+ * Web-only, and refused rather than approximated elsewhere: the Appium partial chains a parent
428
+ * with `$()`, which has no content filter, so emitting one would be invalid code and pretending
429
+ * the scope applied would be the very silence this whole fix exists to end (SG-W028).
430
+ */
431
+ private static filterParentByValue(
432
+ base: string, step: ParsedStep, context: PatternContext
433
+ ): string {
434
+ const raw = step.parentValueRef
435
+ ? PatternRegistry.resolveInlineData(`{{${step.parentValueRef}}}`, context)
436
+ : step.parentValueText;
437
+ if (raw === undefined) return base;
438
+
439
+ if (context.platform === 'mobile') {
440
+ context.diagnostics?.add('SG-W028',
441
+ `scoping a container BY CONTENT ("in [${step.parentRef}] ${step.parentType} with …") is web-only — the mobile adapter chains a parent element, which has no content filter, so this step would search every ${step.parentType} on the screen. Give the container an accessibility id that identifies it and scope by that instead, or assert on the element the value belongs to`,
442
+ { feature: context.featureName, step: step.text });
443
+ return base;
444
+ }
445
+ return `${base}.filter({ hasText: '${escapeSingleQuoted(raw)}' })`;
446
+ }
447
+
448
+ /**
449
+ * Resolve a `{{var}}` written where literal text is expected, leaving anything else untouched.
450
+ * An unknown variable stays as written rather than throwing — the locator is then wrong in a way
451
+ * the author can read, which beats losing the whole step.
452
+ */
453
+ private static resolveInlineData(text: string, context: PatternContext): string {
454
+ const match = text.match(/^\{\{([a-z0-9\-._]+)\}\}$/i);
455
+ if (!match) return text;
456
+ try {
457
+ return context.dataResolver.resolveData(match[1], context.featureName);
458
+ } catch {
459
+ return text;
460
+ }
310
461
  }
311
462
 
312
463
  /**
@@ -84,6 +84,14 @@ export interface PatternContext {
84
84
  effectiveKeyword?: string;
85
85
  /** The platform the ACTIVE adapter compiles for. Absent = 'web' (back-compat default). */
86
86
  platform?: Platform;
87
+ /**
88
+ * The OS the FEATURE declares via `@platform:<mobile|android|ios>` — distinct from `platform`
89
+ * above, which is the adapter. Only `ios` is actionable at compile time: it is the single case
90
+ * where the compiler knows which mobile OS will run, so it can refuse a step that does nothing
91
+ * (or throws) there. `mobile` means both OSes and is deliberately NOT gated — the real OS is
92
+ * chosen at run time by MOBILE_PLATFORM, so a compile-time verdict would be a guess.
93
+ */
94
+ featurePlatform?: 'mobile' | 'android' | 'ios';
87
95
  /** The adapter's own name ('playwright' | 'appium' | …) — quoted verbatim in SG-E020/SG-W020. */
88
96
  adapterName?: string;
89
97
  /** Compile-diagnostics channel, so the pattern layer can report instead of throwing. */
@@ -0,0 +1,41 @@
1
+ import { PatternContext } from './types';
2
+
3
+ /**
4
+ * Return a `PatternContext` in which every selector the pattern resolves comes back already scoped
5
+ * to `parentLocator`.
6
+ *
7
+ * Why a wrapped context rather than one assignment. A `resolver` pattern hands its template data
8
+ * back to the registry, which can stamp `parentLocator` on it; a `generator` pattern renders its own
9
+ * code and never exposes that object, so the registry had no seam and the scope was simply lost
10
+ * (#667). The seam both kinds share is where they ASK for a selector — `selectorResolver` and
11
+ * `renderLocator` — so the scope is attached there instead, and every locator partial (Playwright
12
+ * and Appium alike) already knows what to do with a `parentLocator` field.
13
+ *
14
+ * Only the target's own scope is stamped; anything a pattern resolves that ALREADY carries a
15
+ * `parentLocator` is left alone, so a pattern that builds its own container chain (table rows) keeps
16
+ * winning over the generic one.
17
+ */
18
+ export function withParentScope(context: PatternContext, parentLocator: string): PatternContext {
19
+ const scope = <T>(resolved: T): T =>
20
+ resolved && typeof resolved === 'object' && !(resolved as any).parentLocator
21
+ ? { ...(resolved as any), parentLocator }
22
+ : resolved;
23
+
24
+ // A Proxy rather than a copy: SelectorResolver carries more than the one method patterns call,
25
+ // and a hand-written stand-in would silently drop whatever it forgot.
26
+ const selectorResolver = new Proxy(context.selectorResolver, {
27
+ get(target, prop, receiver) {
28
+ if (prop === 'resolveSelector') {
29
+ return (...args: unknown[]) => scope((target as any).resolveSelector(...args));
30
+ }
31
+ const value = Reflect.get(target, prop, receiver);
32
+ return typeof value === 'function' ? value.bind(target) : value;
33
+ },
34
+ });
35
+
36
+ return {
37
+ ...context,
38
+ selectorResolver,
39
+ renderLocator: (resolved: any) => context.renderLocator(scope(resolved)),
40
+ };
41
+ }