@sun-asterisk/sungen 3.2.18 → 3.2.19

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 (249) hide show
  1. package/dist/capabilities/discover.d.ts.map +1 -1
  2. package/dist/capabilities/discover.js +4 -1
  3. package/dist/capabilities/discover.js.map +1 -1
  4. package/dist/cli/commands/add.d.ts.map +1 -1
  5. package/dist/cli/commands/add.js +4 -2
  6. package/dist/cli/commands/add.js.map +1 -1
  7. package/dist/cli/commands/dashboard.d.ts.map +1 -1
  8. package/dist/cli/commands/dashboard.js +10 -1
  9. package/dist/cli/commands/dashboard.js.map +1 -1
  10. package/dist/cli/commands/delivery.d.ts.map +1 -1
  11. package/dist/cli/commands/delivery.js +19 -1
  12. package/dist/cli/commands/delivery.js.map +1 -1
  13. package/dist/cli/commands/generate.d.ts.map +1 -1
  14. package/dist/cli/commands/generate.js +4 -1
  15. package/dist/cli/commands/generate.js.map +1 -1
  16. package/dist/dashboard/html-renderer.d.ts.map +1 -1
  17. package/dist/dashboard/html-renderer.js +7 -2
  18. package/dist/dashboard/html-renderer.js.map +1 -1
  19. package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
  20. package/dist/dashboard/snapshot-builder.js +3 -0
  21. package/dist/dashboard/snapshot-builder.js.map +1 -1
  22. package/dist/dashboard/types.d.ts +4 -0
  23. package/dist/dashboard/types.d.ts.map +1 -1
  24. package/dist/exporters/api-environment.d.ts.map +1 -1
  25. package/dist/exporters/api-environment.js +4 -24
  26. package/dist/exporters/api-environment.js.map +1 -1
  27. package/dist/exporters/api-testcase-formatter.d.ts +6 -0
  28. package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
  29. package/dist/exporters/api-testcase-formatter.js +11 -4
  30. package/dist/exporters/api-testcase-formatter.js.map +1 -1
  31. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  32. package/dist/exporters/csv-exporter.js +40 -9
  33. package/dist/exporters/csv-exporter.js.map +1 -1
  34. package/dist/exporters/env-qa.d.ts +13 -0
  35. package/dist/exporters/env-qa.d.ts.map +1 -0
  36. package/dist/exporters/env-qa.js +82 -0
  37. package/dist/exporters/env-qa.js.map +1 -0
  38. package/dist/exporters/feature-parser.d.ts.map +1 -1
  39. package/dist/exporters/feature-parser.js +16 -33
  40. package/dist/exporters/feature-parser.js.map +1 -1
  41. package/dist/exporters/json-exporter.d.ts.map +1 -1
  42. package/dist/exporters/json-exporter.js +57 -20
  43. package/dist/exporters/json-exporter.js.map +1 -1
  44. package/dist/exporters/matrix/build.d.ts.map +1 -1
  45. package/dist/exporters/matrix/build.js +6 -5
  46. package/dist/exporters/matrix/build.js.map +1 -1
  47. package/dist/exporters/matrix/gates.d.ts.map +1 -1
  48. package/dist/exporters/matrix/gates.js +3 -2
  49. package/dist/exporters/matrix/gates.js.map +1 -1
  50. package/dist/exporters/matrix/step-buckets.d.ts +13 -0
  51. package/dist/exporters/matrix/step-buckets.d.ts.map +1 -0
  52. package/dist/exporters/matrix/step-buckets.js +7 -0
  53. package/dist/exporters/matrix/step-buckets.js.map +1 -0
  54. package/dist/exporters/qa-env-secret-denylist.d.ts +43 -0
  55. package/dist/exporters/qa-env-secret-denylist.d.ts.map +1 -0
  56. package/dist/exporters/qa-env-secret-denylist.js +143 -0
  57. package/dist/exporters/qa-env-secret-denylist.js.map +1 -0
  58. package/dist/exporters/scenario-merger.d.ts +20 -13
  59. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  60. package/dist/exporters/scenario-merger.js +55 -30
  61. package/dist/exporters/scenario-merger.js.map +1 -1
  62. package/dist/exporters/step-formatter.d.ts +42 -33
  63. package/dist/exporters/step-formatter.d.ts.map +1 -1
  64. package/dist/exporters/step-formatter.js +68 -68
  65. package/dist/exporters/step-formatter.js.map +1 -1
  66. package/dist/exporters/types.d.ts +9 -8
  67. package/dist/exporters/types.d.ts.map +1 -1
  68. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +1 -0
  69. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  70. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +1 -0
  71. package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
  72. package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
  73. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/keyboard-global-action.hbs +3 -1
  74. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +1 -0
  75. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  76. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  77. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  78. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +3 -1
  79. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -1
  80. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/storage-key-assertion.hbs +4 -0
  81. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/tab-order-assertion.hbs +30 -0
  82. package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +1 -4
  83. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/dialog-root.hbs +1 -1
  84. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +10 -0
  85. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  86. package/dist/generators/test-generator/code-generator.js +70 -7
  87. package/dist/generators/test-generator/code-generator.js.map +1 -1
  88. package/dist/generators/test-generator/diagnostics.d.ts +7 -1
  89. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  90. package/dist/generators/test-generator/diagnostics.js +6 -0
  91. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  92. package/dist/generators/test-generator/recipe-expander.d.ts +1 -1
  93. package/dist/generators/test-generator/recipe-expander.d.ts.map +1 -1
  94. package/dist/generators/test-generator/recipe-expander.js +1 -1
  95. package/dist/generators/test-generator/recipe-expander.js.map +1 -1
  96. package/dist/generators/test-generator/step-mapper.d.ts +17 -0
  97. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  98. package/dist/generators/test-generator/step-mapper.js +108 -17
  99. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  100. package/dist/generators/test-generator/template-engine.d.ts +1 -0
  101. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  102. package/dist/generators/test-generator/template-engine.js +1 -1
  103. package/dist/generators/test-generator/template-engine.js.map +1 -1
  104. package/dist/generators/test-generator/utils/data-resolver.d.ts +7 -1
  105. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  106. package/dist/generators/test-generator/utils/data-resolver.js +8 -4
  107. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  108. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts +2 -2
  109. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -1
  110. package/dist/generators/test-generator/utils/runtime-data-transformer.js +56 -11
  111. package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -1
  112. package/dist/generators/test-generator/utils/selector-resolver.d.ts +18 -2
  113. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  114. package/dist/generators/test-generator/utils/selector-resolver.js +29 -6
  115. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  116. package/dist/harness/audit.d.ts.map +1 -1
  117. package/dist/harness/audit.js +8 -7
  118. package/dist/harness/audit.js.map +1 -1
  119. package/dist/harness/capability-plan.d.ts.map +1 -1
  120. package/dist/harness/capability-plan.js +2 -3
  121. package/dist/harness/capability-plan.js.map +1 -1
  122. package/dist/harness/catalog/drivers.yaml +1 -1
  123. package/dist/harness/challenge.d.ts.map +1 -1
  124. package/dist/harness/challenge.js +1 -55
  125. package/dist/harness/challenge.js.map +1 -1
  126. package/dist/harness/data-driven-lint.d.ts.map +1 -1
  127. package/dist/harness/data-driven-lint.js +14 -9
  128. package/dist/harness/data-driven-lint.js.map +1 -1
  129. package/dist/harness/depth-lint.d.ts.map +1 -1
  130. package/dist/harness/depth-lint.js +1 -3
  131. package/dist/harness/depth-lint.js.map +1 -1
  132. package/dist/harness/flow-check.d.ts.map +1 -1
  133. package/dist/harness/flow-check.js +9 -7
  134. package/dist/harness/flow-check.js.map +1 -1
  135. package/dist/harness/flow-plan.d.ts.map +1 -1
  136. package/dist/harness/flow-plan.js +4 -3
  137. package/dist/harness/flow-plan.js.map +1 -1
  138. package/dist/harness/manifest.js +2 -2
  139. package/dist/harness/manifest.js.map +1 -1
  140. package/dist/harness/parse.d.ts +12 -0
  141. package/dist/harness/parse.d.ts.map +1 -1
  142. package/dist/harness/parse.js +28 -1
  143. package/dist/harness/parse.js.map +1 -1
  144. package/dist/harness/script-check.d.ts.map +1 -1
  145. package/dist/harness/script-check.js +52 -30
  146. package/dist/harness/script-check.js.map +1 -1
  147. package/dist/harness/secret-scan.d.ts +3 -1
  148. package/dist/harness/secret-scan.d.ts.map +1 -1
  149. package/dist/harness/secret-scan.js +14 -10
  150. package/dist/harness/secret-scan.js.map +1 -1
  151. package/dist/harness/sensors.d.ts.map +1 -1
  152. package/dist/harness/sensors.js +15 -4
  153. package/dist/harness/sensors.js.map +1 -1
  154. package/dist/harness/trace.js +1 -1
  155. package/dist/harness/trace.js.map +1 -1
  156. package/dist/harness/unit-paths.d.ts +16 -0
  157. package/dist/harness/unit-paths.d.ts.map +1 -1
  158. package/dist/harness/unit-paths.js +39 -2
  159. package/dist/harness/unit-paths.js.map +1 -1
  160. package/dist/index.d.ts +1 -0
  161. package/dist/index.d.ts.map +1 -1
  162. package/dist/index.js +3 -1
  163. package/dist/index.js.map +1 -1
  164. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  165. package/dist/orchestrator/screen-manager.js +8 -2
  166. package/dist/orchestrator/screen-manager.js.map +1 -1
  167. package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -1
  168. package/dist/orchestrator/templates/ai-src/commands/run-test.md +1 -1
  169. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +2 -0
  170. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +51 -2
  171. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +6 -0
  172. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +6 -0
  173. package/dist/orchestrator/templates/playwright.config.ts +33 -2
  174. package/dist/orchestrator/templates/specs-mock.d.ts +66 -0
  175. package/dist/orchestrator/templates/specs-mock.d.ts.map +1 -0
  176. package/dist/orchestrator/templates/specs-mock.js +137 -0
  177. package/dist/orchestrator/templates/specs-mock.js.map +1 -0
  178. package/dist/orchestrator/templates/specs-mock.ts +179 -0
  179. package/dist/orchestrator/test-data-guide.d.ts.map +1 -1
  180. package/dist/orchestrator/test-data-guide.js +4 -0
  181. package/dist/orchestrator/test-data-guide.js.map +1 -1
  182. package/package.json +3 -3
  183. package/src/capabilities/discover.ts +4 -1
  184. package/src/cli/commands/add.ts +4 -2
  185. package/src/cli/commands/dashboard.ts +10 -1
  186. package/src/cli/commands/delivery.ts +19 -1
  187. package/src/cli/commands/generate.ts +4 -1
  188. package/src/dashboard/html-renderer.ts +8 -2
  189. package/src/dashboard/snapshot-builder.ts +3 -0
  190. package/src/dashboard/types.ts +4 -0
  191. package/src/exporters/api-environment.ts +3 -20
  192. package/src/exporters/api-testcase-formatter.ts +8 -2
  193. package/src/exporters/csv-exporter.ts +47 -8
  194. package/src/exporters/env-qa.ts +41 -0
  195. package/src/exporters/feature-parser.ts +17 -38
  196. package/src/exporters/json-exporter.ts +71 -24
  197. package/src/exporters/matrix/build.ts +6 -5
  198. package/src/exporters/matrix/gates.ts +3 -2
  199. package/src/exporters/matrix/step-buckets.ts +15 -0
  200. package/src/exporters/qa-env-secret-denylist.ts +118 -0
  201. package/src/exporters/scenario-merger.ts +80 -42
  202. package/src/exporters/step-formatter.ts +67 -66
  203. package/src/exporters/types.ts +9 -8
  204. package/src/generators/test-generator/adapters/adapter-interface.ts +1 -1
  205. package/src/generators/test-generator/adapters/appium/appium-adapter.ts +1 -1
  206. package/src/generators/test-generator/adapters/appium/templates/steps/actions/keyboard-global-action.hbs +3 -1
  207. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +1 -1
  208. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  209. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +3 -1
  210. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/page-assertion.hbs +1 -1
  211. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/storage-key-assertion.hbs +4 -0
  212. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/tab-order-assertion.hbs +30 -0
  213. package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +1 -4
  214. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/dialog-root.hbs +1 -1
  215. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +10 -0
  216. package/src/generators/test-generator/code-generator.ts +82 -7
  217. package/src/generators/test-generator/diagnostics.ts +7 -1
  218. package/src/generators/test-generator/recipe-expander.ts +2 -2
  219. package/src/generators/test-generator/step-mapper.ts +106 -15
  220. package/src/generators/test-generator/template-engine.ts +2 -2
  221. package/src/generators/test-generator/utils/data-resolver.ts +8 -5
  222. package/src/generators/test-generator/utils/runtime-data-transformer.ts +57 -11
  223. package/src/generators/test-generator/utils/selector-resolver.ts +29 -5
  224. package/src/harness/audit.ts +10 -9
  225. package/src/harness/capability-plan.ts +2 -2
  226. package/src/harness/catalog/drivers.yaml +1 -1
  227. package/src/harness/challenge.ts +2 -3
  228. package/src/harness/data-driven-lint.ts +13 -9
  229. package/src/harness/depth-lint.ts +2 -4
  230. package/src/harness/flow-check.ts +9 -7
  231. package/src/harness/flow-plan.ts +4 -3
  232. package/src/harness/manifest.ts +3 -3
  233. package/src/harness/parse.ts +28 -1
  234. package/src/harness/script-check.ts +52 -32
  235. package/src/harness/secret-scan.ts +11 -7
  236. package/src/harness/sensors.ts +15 -4
  237. package/src/harness/trace.ts +2 -2
  238. package/src/harness/unit-paths.ts +39 -2
  239. package/src/index.ts +1 -0
  240. package/src/orchestrator/screen-manager.ts +7 -2
  241. package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -1
  242. package/src/orchestrator/templates/ai-src/commands/run-test.md +1 -1
  243. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +2 -0
  244. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +51 -2
  245. package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +6 -0
  246. package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +6 -0
  247. package/src/orchestrator/templates/playwright.config.ts +33 -2
  248. package/src/orchestrator/templates/specs-mock.ts +179 -0
  249. package/src/orchestrator/test-data-guide.ts +4 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Denylist of RESOLVED `${QA_*}` secret values, for redacting runtime failure text
3
+ * (the CSV/XLSX `Note` column and the dashboard snapshot's `errorMessage`).
4
+ *
5
+ * A failed assertion's message carries the credential the runtime already substituted
6
+ * (`Expected: "<real password>"`), and delivery lifts that message into files that get
7
+ * committed permanently (qa/deliverables/*.csv, qa/dashboard/history/*.json). Key-based
8
+ * masking can't help there — the secret appears as a free-standing VALUE — so we build a
9
+ * value denylist and erase every occurrence.
10
+ *
11
+ * Selection = env-var names referenced as `${QA_*}` in the unit's test data, INTERSECTED
12
+ * with a sensitive-name signal on the ENV VAR NAME: QA_ADMIN_PASSWORD / QA_ACCESS_TOKEN
13
+ * are denylisted, QA_BASE_URL / QA_ADMIN_EMAIL are not — non-secret values must stay
14
+ * readable so the deliverable keeps its reproduction value.
15
+ *
16
+ * Values resolve like the runtime does (specs-test-data loadEnvQa precedence):
17
+ * shell/CI env highest > .env.qa.<SUNGEN_ENV> > .env.qa. Reading process.env is
18
+ * deliberate — on CI (where deliverables are actually committed) the .env.qa file is
19
+ * gitignored and usually absent; secrets arrive via env, and a parse-file-only denylist
20
+ * would be empty exactly where it matters. `.env.qa.example` (committed placeholders) is
21
+ * never read. This module only BUILDS the denylist — values are erased from output,
22
+ * never rendered into it.
23
+ */
24
+ export interface QaEnvSecretDenylist {
25
+ /** Resolved secret values to erase, deduped, longest-first (so a longer secret wins over its substring). */
26
+ values: string[];
27
+ /** Sensitive `${QA_*}` names referenced by the unit that resolved to no usable value. */
28
+ unresolved: string[];
29
+ }
30
+ /**
31
+ * Build the denylist for one unit from its LOADED test-data map (values still carry the
32
+ * literal `${QA_*}` refs — delivery never resolves them into cells). `cwd` is the project
33
+ * root the delivery CLI runs from, where .env.qa files live.
34
+ */
35
+ export declare function collectQaEnvSecretDenylist(testData: Record<string, string>, cwd?: string): QaEnvSecretDenylist;
36
+ /**
37
+ * Fail-loud seam: a unit references sensitive `${QA_*}` vars whose values can't be
38
+ * resolved here, AND the run has failures whose messages may embed those very values
39
+ * (resolved by the runtime in a different shell, e.g. CI artifacts exported locally).
40
+ * Silence would mean exporting unredacted secrets without a trace — warn instead.
41
+ */
42
+ export declare function warnIfRedactionIncomplete(denylist: QaEnvSecretDenylist, hasFailures: boolean, unitLabel: string): void;
43
+ //# sourceMappingURL=qa-env-secret-denylist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-env-secret-denylist.d.ts","sourceRoot":"","sources":["../../src/exporters/qa-env-secret-denylist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAWH,MAAM,WAAW,mBAAmB;IAClC,4GAA4G;IAC5G,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,yFAAyF;IACzF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,GAAG,GAAE,MAAsB,GAC1B,mBAAmB,CAuBrB;AA0BD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,mBAAmB,EAC7B,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,GAChB,IAAI,CAUN"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /**
3
+ * Denylist of RESOLVED `${QA_*}` secret values, for redacting runtime failure text
4
+ * (the CSV/XLSX `Note` column and the dashboard snapshot's `errorMessage`).
5
+ *
6
+ * A failed assertion's message carries the credential the runtime already substituted
7
+ * (`Expected: "<real password>"`), and delivery lifts that message into files that get
8
+ * committed permanently (qa/deliverables/*.csv, qa/dashboard/history/*.json). Key-based
9
+ * masking can't help there — the secret appears as a free-standing VALUE — so we build a
10
+ * value denylist and erase every occurrence.
11
+ *
12
+ * Selection = env-var names referenced as `${QA_*}` in the unit's test data, INTERSECTED
13
+ * with a sensitive-name signal on the ENV VAR NAME: QA_ADMIN_PASSWORD / QA_ACCESS_TOKEN
14
+ * are denylisted, QA_BASE_URL / QA_ADMIN_EMAIL are not — non-secret values must stay
15
+ * readable so the deliverable keeps its reproduction value.
16
+ *
17
+ * Values resolve like the runtime does (specs-test-data loadEnvQa precedence):
18
+ * shell/CI env highest > .env.qa.<SUNGEN_ENV> > .env.qa. Reading process.env is
19
+ * deliberate — on CI (where deliverables are actually committed) the .env.qa file is
20
+ * gitignored and usually absent; secrets arrive via env, and a parse-file-only denylist
21
+ * would be empty exactly where it matters. `.env.qa.example` (committed placeholders) is
22
+ * never read. This module only BUILDS the denylist — values are erased from output,
23
+ * never rendered into it.
24
+ */
25
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ var desc = Object.getOwnPropertyDescriptor(m, k);
28
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29
+ desc = { enumerable: true, get: function() { return m[k]; } };
30
+ }
31
+ Object.defineProperty(o, k2, desc);
32
+ }) : (function(o, m, k, k2) {
33
+ if (k2 === undefined) k2 = k;
34
+ o[k2] = m[k];
35
+ }));
36
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
37
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
38
+ }) : function(o, v) {
39
+ o["default"] = v;
40
+ });
41
+ var __importStar = (this && this.__importStar) || (function () {
42
+ var ownKeys = function(o) {
43
+ ownKeys = Object.getOwnPropertyNames || function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
54
+ __setModuleDefault(result, mod);
55
+ return result;
56
+ };
57
+ })();
58
+ Object.defineProperty(exports, "__esModule", { value: true });
59
+ exports.collectQaEnvSecretDenylist = collectQaEnvSecretDenylist;
60
+ exports.warnIfRedactionIncomplete = warnIfRedactionIncomplete;
61
+ const fs = __importStar(require("fs"));
62
+ const path = __importStar(require("path"));
63
+ // Sensitive-name signal shared with the API exporter's key/body-field classifier —
64
+ // here it is applied to the ENV VAR NAME (QA_ACCESS_TOKEN), not the yaml key.
65
+ const api_testcase_formatter_1 = require("./api-testcase-formatter");
66
+ /** `${QA_*}` env reference — same shape the runtime resolver allowlists (uppercase, QA_ prefix). */
67
+ const QA_ENV_REF = /\$\{(QA_[A-Z0-9_]+)\}/g;
68
+ /**
69
+ * Build the denylist for one unit from its LOADED test-data map (values still carry the
70
+ * literal `${QA_*}` refs — delivery never resolves them into cells). `cwd` is the project
71
+ * root the delivery CLI runs from, where .env.qa files live.
72
+ */
73
+ function collectQaEnvSecretDenylist(testData, cwd = process.cwd()) {
74
+ const referenced = new Set();
75
+ for (const v of Object.values(testData)) {
76
+ if (typeof v !== 'string')
77
+ continue;
78
+ for (const m of v.matchAll(QA_ENV_REF))
79
+ referenced.add(m[1]);
80
+ }
81
+ const sensitive = [...referenced].filter((n) => api_testcase_formatter_1.SENSITIVE_NAME.test(n));
82
+ if (sensitive.length === 0)
83
+ return { values: [], unresolved: [] };
84
+ const fileEnv = readEnvQaFiles(cwd);
85
+ const values = [];
86
+ const unresolved = [];
87
+ for (const name of sensitive) {
88
+ const v = process.env[name] !== undefined ? process.env[name] : fileEnv[name];
89
+ // Values shorter than 3 chars are unusable as a denylist entry (they'd mask
90
+ // coincidental text); treat them as unresolved so coverage gaps stay visible.
91
+ if (typeof v === 'string' && v.length >= 3)
92
+ values.push(v);
93
+ else
94
+ unresolved.push(name);
95
+ }
96
+ return {
97
+ values: [...new Set(values)].sort((a, b) => b.length - a.length),
98
+ unresolved,
99
+ };
100
+ }
101
+ /**
102
+ * Read .env.qa files into a local map (never mutating process.env), with the runtime's
103
+ * precedence: first file that sets a key wins, and `.env.qa.<SUNGEN_ENV>` is read before
104
+ * the base `.env.qa`. Callers give process.env priority over everything here.
105
+ */
106
+ function readEnvQaFiles(cwd) {
107
+ const out = {};
108
+ const env = process.env.SUNGEN_ENV;
109
+ for (const name of [env ? `.env.qa.${env}` : '', '.env.qa']) {
110
+ // .env.qa.example is a committed placeholder file, never a source of real values.
111
+ if (!name || name === '.env.qa.example')
112
+ continue;
113
+ const p = path.join(cwd, name);
114
+ if (!fs.existsSync(p))
115
+ continue;
116
+ for (const line of fs.readFileSync(p, 'utf-8').split('\n')) {
117
+ const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
118
+ if (m && out[m[1]] === undefined)
119
+ out[m[1]] = m[2].replace(/^["']|["']$/g, '');
120
+ }
121
+ }
122
+ return out;
123
+ }
124
+ /** Keys already warned about, so per-variant exporter loops don't repeat themselves. */
125
+ const warnedUnits = new Set();
126
+ /**
127
+ * Fail-loud seam: a unit references sensitive `${QA_*}` vars whose values can't be
128
+ * resolved here, AND the run has failures whose messages may embed those very values
129
+ * (resolved by the runtime in a different shell, e.g. CI artifacts exported locally).
130
+ * Silence would mean exporting unredacted secrets without a trace — warn instead.
131
+ */
132
+ function warnIfRedactionIncomplete(denylist, hasFailures, unitLabel) {
133
+ if (!hasFailures || denylist.unresolved.length === 0)
134
+ return;
135
+ const key = `${unitLabel}:${denylist.unresolved.join(',')}`;
136
+ if (warnedUnits.has(key))
137
+ return;
138
+ warnedUnits.add(key);
139
+ console.warn(`⚠ [${unitLabel}] redaction coverage incomplete: ${denylist.unresolved.join(', ')} ` +
140
+ 'referenced in test-data but not resolvable here — failure notes in the deliverable ' +
141
+ 'may contain unredacted secret values. Set the variable(s) in the shell/CI env or .env.qa before exporting.');
142
+ }
143
+ //# sourceMappingURL=qa-env-secret-denylist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-env-secret-denylist.js","sourceRoot":"","sources":["../../src/exporters/qa-env-secret-denylist.ts"],"names":[],"mappings":"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"}
@@ -28,27 +28,34 @@ export interface MergedScenario {
28
28
  /** Matched compiled test from .spec.ts, or null if not compiled. */
29
29
  spec: SpecTest | null;
30
30
  /**
31
- * When/Then/Given steps with any `@extend:<name>` chain pre-resolved
32
- * against the matching `@steps:<name>` base scenario (its steps are
33
- * prepended). Use these for surfaces that show the test case text
34
- * (dashboard Steps section) so we get the canonical feature wording
35
- * without re-parsing compiled spec.ts comments.
31
+ * Feature Background steps, kept separate from `resolvedSteps` so the
32
+ * exporters render them in the Pre-condition column. Inlining them into
33
+ * Steps shifted the step numbering against the .feature source, which made
34
+ * QA's Gherkin-vs-export review a manual re-mapping exercise.
36
35
  */
37
- resolvedWhenSteps: string[];
38
- resolvedThenSteps: string[];
39
- resolvedGivenSteps: string[];
36
+ resolvedBackgroundSteps: OrderedStep[];
40
37
  /**
41
38
  * Steps section for display, in chronological order:
42
- * Background (all) → @extend base (all incl. its Then) → own up to the
43
- * first `Then`. Base's `Then` stays here because it's mid-flow setup,
44
- * not the scenario's final assertion.
39
+ * @extend base (all incl. its Then) → own given/when-bucket steps.
40
+ * Base's `Then` stays here because it's mid-flow setup, not the
41
+ * scenario's final assertion. Background is NOT included — it renders
42
+ * as Pre-condition (see `resolvedBackgroundSteps`).
45
43
  */
46
44
  resolvedSteps: OrderedStep[];
47
45
  /**
48
- * Expected results — own scenario's first `Then` onwards. Empty when the
49
- * scenario has no `Then`.
46
+ * Expected results — own scenario's then-bucket steps (a `When` after a
47
+ * `Then` starts a new action and goes back to Steps; an `And` follows its
48
+ * preceding explicit keyword). Empty when the scenario has no `Then`.
50
49
  */
51
50
  resolvedExpected: OrderedStep[];
51
+ /**
52
+ * Count of anchor-eligible action lines (@extend base + own given/when
53
+ * steps). This — NOT the rendered Steps length — is the reference for the
54
+ * "is any assertion mid-flow?" check in groupExpectedByAnchor: manual-comment
55
+ * steps are appended to resolvedSteps but never participate in anchoring,
56
+ * so counting them would falsely mark @manual scenarios as interleaved.
57
+ */
58
+ resolvedAnchorActionCount: number;
52
59
  }
53
60
  /**
54
61
  * Merge features and spec data, excluding base @steps and scaffold scenarios.
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-merger.d.ts","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjG;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,CAwBzG;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,OAAO,EAAE,gBAAgB,CAAC;IAE1B,oEAAoE;IACpE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAEtB;;;;;;OAMG;IACH,iBAAiB,EAAG,MAAM,EAAE,CAAC;IAC7B,iBAAiB,EAAG,MAAM,EAAE,CAAC;IAC7B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B;;;OAGG;IACH,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,YAAY,GACjB,cAAc,EAAE,CAkElB"}
1
+ {"version":3,"file":"scenario-merger.d.ts","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjG;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,CAwBzG;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,OAAO,EAAE,gBAAgB,CAAC;IAE1B,oEAAoE;IACpE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAEtB;;;;;OAKG;IACH,uBAAuB,EAAE,WAAW,EAAE,CAAC;IACvC;;;;;;OAMG;IACH,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B;;;;OAIG;IACH,gBAAgB,EAAE,WAAW,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,YAAY,GACjB,cAAc,EAAE,CAwElB"}
@@ -69,19 +69,40 @@ function mergeFeatureAndSpec(feature, spec) {
69
69
  continue; // skip @steps base scenarios
70
70
  if ((0, feature_parser_1.isSampleScaffoldScenario)(scenario))
71
71
  continue; // skip default sample
72
- const specTest = findMatchingSpecTest(scenario, spec.tests);
72
+ const specTest = findMatchingSpecTest(scenario, spec.tests, feature.scenarios);
73
73
  const base = scenario.extendsName ? stepsBaseByName.get(scenario.extendsName) : undefined;
74
74
  // Order of execution for a runnable scenario:
75
- // 1. Feature Background (once) — all buckets are setup, stay in Steps.
75
+ // 1. Feature Background (once) — setup state, rendered as Pre-condition
76
+ // so Steps numbering stays aligned with the .feature scenario.
76
77
  // 2. @extend base scenario's own steps (if any) — *including* its Then,
77
78
  // because the base's Then is a mid-flow assertion, not the scenario's
78
79
  // final verification.
79
- // 3. This scenario's own steps in original sequence, split at the
80
- // first `Then`: pre-Then → Steps, Then-onwards → Expected results.
80
+ // 3. This scenario's own steps, partitioned by BUCKET (not by position):
81
+ // given/when → Steps, then → Expected results. A positional split at
82
+ // the first `Then` broke interleaved scenarios (When → Then → When →
83
+ // Then …): every later `When` action was exported as an "expected
84
+ // result". classifySteps already resolves `And` to its preceding
85
+ // explicit keyword, so an `And` after `Then` stays an assertion and
86
+ // an `And` after `When` stays an action. Relative order is preserved
87
+ // within each column.
88
+ // Each assertion also records its ANCHOR — the 1-based index of the
89
+ // last action before it in the rendered Steps column (@extend base
90
+ // steps count toward the numbering; Background does not, it renders
91
+ // as Pre-condition). The exporters use anchors to append
92
+ // "— after step N" when a scenario interleaves actions and
93
+ // assertions, restoring the correspondence the 2-column layout loses.
81
94
  const ownOrdered = scenario.orderedSteps;
82
- const firstThenIdx = ownOrdered.findIndex((s) => s.bucket === 'then');
83
- const ownPreThen = firstThenIdx >= 0 ? ownOrdered.slice(0, firstThenIdx) : ownOrdered;
84
- const ownPostThen = firstThenIdx >= 0 ? ownOrdered.slice(firstThenIdx) : [];
95
+ const baseLen = base?.orderedSteps.length ?? 0;
96
+ const ownActions = [];
97
+ const ownAssertions = [];
98
+ for (const s of ownOrdered) {
99
+ if (s.bucket === 'then') {
100
+ ownAssertions.push({ ...s, anchorStep: baseLen + ownActions.length });
101
+ }
102
+ else {
103
+ ownActions.push(s);
104
+ }
105
+ }
85
106
  // A @manual scenario carries no Gherkin steps — its tester procedure lives in the
86
107
  // `# Tester verifies:` comment block. Parse it into Steps (Setup/Action) + Expected
87
108
  // (Observable/Oracle) so the delivery report shows the real manual procedure, not
@@ -92,48 +113,52 @@ function mergeFeatureAndSpec(feature, spec) {
92
113
  result.push({
93
114
  feature: scenario,
94
115
  spec: specTest,
95
- resolvedWhenSteps: [
96
- ...feature.backgroundWhenSteps,
97
- ...(base?.rawWhenSteps ?? []),
98
- ...scenario.rawWhenSteps,
99
- ],
100
- resolvedThenSteps: [
101
- ...feature.backgroundThenSteps,
102
- ...(base?.rawThenSteps ?? []),
103
- ...scenario.rawThenSteps,
104
- ],
105
- resolvedGivenSteps: [
106
- ...feature.backgroundGivenSteps,
107
- ...(base?.rawGivenSteps ?? []),
108
- ...scenario.rawGivenSteps,
109
- ],
116
+ resolvedBackgroundSteps: feature.backgroundOrderedSteps,
110
117
  resolvedSteps: [
111
- ...feature.backgroundOrderedSteps,
112
118
  ...(base?.orderedSteps ?? []),
113
- ...ownPreThen,
119
+ ...ownActions,
114
120
  ...manualParsed.steps,
115
121
  ],
116
- resolvedExpected: [...ownPostThen, ...manualParsed.expected],
122
+ resolvedExpected: [...ownAssertions, ...manualParsed.expected],
123
+ resolvedAnchorActionCount: baseLen + ownActions.length,
117
124
  });
118
125
  }
119
126
  return result;
120
127
  }
128
+ /** `@manual` / `@manual:<reason>` — a manual scenario has no automated test by definition. */
129
+ function isManualScenario(scenario) {
130
+ return scenario.tags.some((t) => t === '@manual' || t.startsWith('@manual:'));
131
+ }
121
132
  /**
122
133
  * Find the spec test that corresponds to a given feature scenario.
123
134
  * Match by scenario title (exact match on the scenario name).
135
+ *
136
+ * The VP-ID fallback exists only to survive small TITLE drift between compile
137
+ * and export — it must never RE-ASSIGN a result to a different scenario. Field
138
+ * report: a feature carried the same VP id on many scenarios (VP-NAV-001 ×14,
139
+ * mixing @manual and automated); the old first-match fallback attached an
140
+ * automated sibling's executed result to every @manual sibling, so 7 testcases
141
+ * nobody ever ran shipped as "Passed" in the client deliverable. Two guards:
142
+ * 1. a @manual scenario never matches ANY test;
143
+ * 2. the fallback applies only when the vpId is UNIQUE on both sides —
144
+ * exactly one test AND exactly one automatable scenario carry it.
145
+ * Ambiguity → null → the row reports an honest "Pending".
124
146
  */
125
- function findMatchingSpecTest(scenario, tests) {
147
+ function findMatchingSpecTest(scenario, tests, allScenarios) {
148
+ if (isManualScenario(scenario))
149
+ return null;
126
150
  // Exact title match
127
151
  const exact = tests.find((t) => t.scenarioName === scenario.name);
128
152
  if (exact)
129
153
  return exact;
130
- // Fallback: match by VP-ID prefix (ignore trailing text differences)
154
+ // Fallback: match by VP-ID prefix only when unique both ways (see above).
131
155
  const vpMatch = scenario.name.match(feature_parser_2.SCENARIO_ID);
132
156
  if (vpMatch) {
133
157
  const vpId = vpMatch[1];
134
- const byVp = tests.find((t) => t.vpId === vpId);
135
- if (byVp)
136
- return byVp;
158
+ const testsWithVp = tests.filter((t) => t.vpId === vpId);
159
+ const scenariosWithVp = allScenarios.filter((s) => !isManualScenario(s) && s.name.match(feature_parser_2.SCENARIO_ID)?.[1] === vpId);
160
+ if (testsWithVp.length === 1 && scenariosWithVp.length === 1)
161
+ return testsWithVp[0];
137
162
  }
138
163
  return null;
139
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scenario-merger.js","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scenario-merger.js","sourceRoot":"","sources":["../../src/exporters/scenario-merger.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,9 @@
1
1
  /**
2
- * Convert raw Gherkin step text OR generated .spec.ts comment lines into
3
- * concise, numbered natural language for the CSV Steps/Expected columns.
2
+ * Convert raw Gherkin step text into concise natural language for the
3
+ * CSV Steps/Expected columns.
4
4
  *
5
5
  * Deterministic — no AI calls.
6
6
  */
7
- /**
8
- * Format a list of raw step lines for the Steps / Expected Results columns.
9
- *
10
- * - 0 lines → empty string
11
- * - 1 line → the line verbatim (no "1. " prefix — avoids Google Sheets clutter)
12
- * - ≥ 2 → each line on its own row, "1. ", "2. ", … prefixes, newline-joined
13
- * so spreadsheet cells auto-wrap one step per visual line.
14
- */
15
- export declare function formatNumberedSteps(lines: string[]): string;
16
7
  /**
17
8
  * Strip the leading actor (`User `) from a raw Gherkin step and capitalise
18
9
  * the first letter. Brackets `[ref]`, `{{var}}` placeholders and element
@@ -27,34 +18,52 @@ export declare function stripActor(raw: string): string;
27
18
  */
28
19
  export declare function keepActor(raw: string): string;
29
20
  /**
30
- * Number a list of raw feature steps. Mirrors `formatNumberedSteps` but
31
- * preserves the original Gherkin punctuation (no bracket-to-quote conversion).
32
- * The mapper picks between `stripActor` (When/Then) and `keepActor`
33
- * (Given) so the actor word matches the step's grammatical role.
34
- * Use this for feature-direct rendering (dashboard + delivery).
35
- */
36
- export declare function formatFeatureSteps(lines: string[], mapper?: (s: string) => string): string;
37
- /**
38
- * Clean a raw step line (either Gherkin text or .spec.ts comment).
21
+ * Group formatted Expected-results lines by their anchor step.
22
+ *
23
+ * Single source of truth for the anchor rendering (used by csv-exporter AND
24
+ * json-exporter so the delivery sheet and the dashboard cannot drift). Final
25
+ * format per user review 2026-08-06:
26
+ *
27
+ * - When assertions verify DIFFERENT moments (more than one distinct
28
+ * anchor, or the single anchor is not the final action), the cell is
29
+ * rendered as groups — a "— after step N" header line (anchor 0
30
+ * "— before step 1") followed by that group's assertions. Within a
31
+ * group, lines are numbered 1..k only when the group has more than one
32
+ * assertion; a lone assertion stays bare.
33
+ * - When ALL assertions verify the final action (the common shape — every
34
+ * Then after the last When), no headers appear and the caller renders
35
+ * the plain 1..M checklist exactly as before the anchor feature.
36
+ * - Pure-assertion scenarios (actionCount 0) and manual-comment entries
37
+ * (no anchor) never produce headers; unanchored entries trail as their
38
+ * own headerless group.
39
+ *
40
+ * `grouped` tells the caller headers were emitted, so it can force-number
41
+ * the Steps cell even when it has a single line (headers reference step
42
+ * numbers QA must be able to see) and must join the lines verbatim instead
43
+ * of applying checklist numbering.
39
44
  *
40
- * Handles patterns like:
41
- * "User click [login] button" → "Click 'login' button"
42
- * "User fill [Email] field with {{email}}" "Fill 'Email' field with {{email}}"
43
- * "Click Signature 2025 Creator" → "Click 'Signature 2025 Creator'"
44
- * "Assert title error has text err_xxx" → "Title error has text err_xxx"
45
- * "Open awards page" → "Open awards page"
45
+ * Anchors are computed against the merger's action list; formatted gherkin
46
+ * lines are never empty (keepActor/stripActor on non-empty text), so the
47
+ * rendered numbering cannot drift from the anchor indices.
46
48
  */
47
- export declare function cleanStepLine(raw: string): string;
49
+ export declare function groupExpectedByAnchor(entries: Array<{
50
+ text: string;
51
+ anchorStep?: number;
52
+ }>, actionCount: number): {
53
+ lines: string[];
54
+ grouped: boolean;
55
+ };
48
56
  /**
49
- * Pre-condition — login/auth context only.
57
+ * Pre-condition — login/auth context + feature Background steps.
50
58
  *
51
59
  * `@auth:user` → `Logged in as user`
52
60
  * `@no-auth` → `Not authenticated`
53
- * (no auth tag) → empty string
61
+ * (no auth tag) → no auth line
54
62
  *
55
- * Background and Given steps are no longer echoed here — they're rendered as
56
- * the first entries in the Steps list so the chain of actions reads as one
57
- * uninterrupted sequence.
63
+ * `backgroundLines` (formatted feature Background steps) follow the auth
64
+ * line, one per line. Background belongs here rather than in Steps: inlining
65
+ * it shifted the Steps numbering against the .feature scenario, forcing QA
66
+ * to re-map step numbers between Gherkin and the exported sheet.
58
67
  */
59
- export declare function formatPrecondition(authRole: string | null, _givenLines?: string[]): string;
68
+ export declare function formatPrecondition(authRole: string | null, backgroundLines?: string[]): string;
60
69
  //# sourceMappingURL=step-formatter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"step-formatter.d.ts","sourceRoot":"","sources":["../../src/exporters/step-formatter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAK3D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAmB,GAAG,MAAM,CAKtG;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,GAAE,MAAM,EAAO,GAAG,MAAM,CAI9F"}
1
+ {"version":3,"file":"step-formatter.d.ts","sourceRoot":"","sources":["../../src/exporters/step-formatter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACrD,WAAW,EAAE,MAAM,GAClB;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAyBvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,eAAe,GAAE,MAAM,EAAO,GAAG,MAAM,CAMlG"}