create-appraisejs 0.3.1-alpha.1 → 0.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/package.json +1 -1
  2. package/templates/blank/.env.example +2 -2
  3. package/templates/blank/.prettierrc +13 -13
  4. package/templates/blank/cucumber.mjs +12 -1
  5. package/templates/blank/e2e/helpers/test-data.ts +10 -0
  6. package/templates/blank/next-env.d.ts +6 -6
  7. package/templates/blank/package-lock.json +2 -2
  8. package/templates/blank/package.json +1 -1
  9. package/templates/blank/packages/cucumber-runtime/package.json +2 -1
  10. package/templates/blank/packages/cucumber-runtime/src/paths.ts +22 -5
  11. package/templates/blank/packages/locator-picker-companion/package.json +2 -1
  12. package/templates/blank/prisma/dev.db +0 -0
  13. package/templates/blank/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  14. package/templates/blank/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  15. package/templates/blank/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  16. package/templates/blank/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  17. package/templates/blank/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  18. package/templates/blank/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  19. package/templates/blank/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  20. package/templates/blank/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  21. package/templates/blank/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  22. package/templates/blank/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  23. package/templates/blank/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  24. package/templates/blank/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  25. package/templates/blank/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  26. package/templates/blank/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  27. package/templates/blank/scripts/setup-env.ts +0 -0
  28. package/templates/blank/scripts/sync-test-cases.ts +60 -10
  29. package/templates/blank/src/components/diagram/flow-diagram-node-search.tsx +9 -2
  30. package/templates/blank/src/components/diagram/flow-diagram-toolbar.tsx +37 -3
  31. package/templates/blank/src/components/diagram/flow-diagram.test.tsx +225 -0
  32. package/templates/blank/src/components/diagram/use-flow-diagram-search.ts +2 -0
  33. package/templates/blank/src/components/diagram/use-flow-diagram.ts +93 -0
  34. package/templates/blank/src/lib/appraise-test-case-metadata.test.ts +78 -0
  35. package/templates/blank/src/lib/appraise-test-case-metadata.ts +220 -0
  36. package/templates/blank/src/lib/automation/automation-path-roots.test.ts +14 -0
  37. package/templates/blank/src/lib/automation/automation-path-roots.ts +10 -2
  38. package/templates/blank/src/lib/database-sync.ts +166 -15
  39. package/templates/blank/src/lib/executor/local-executor-adapter.ts +6 -2
  40. package/templates/blank/src/lib/feature-file-generator.ts +54 -10
  41. package/templates/blank/src/lib/gherkin-parser.test.ts +52 -0
  42. package/templates/blank/src/lib/gherkin-parser.ts +39 -1
  43. package/templates/blank/src/lib/sync/projected-feature-utils.ts +5 -1
  44. package/templates/blank/src/lib/sync/sync-pending-counts.test.ts +115 -0
  45. package/templates/blank/src/lib/sync/sync-pending-counts.ts +108 -13
  46. package/templates/blank/src/services/test-run/test-run-service.test.ts +10 -0
  47. package/templates/blank/src/services/test-run/test-run-service.ts +41 -1
  48. package/templates/starter/.env.example +2 -2
  49. package/templates/starter/.prettierrc +13 -13
  50. package/templates/starter/cucumber.mjs +12 -1
  51. package/templates/starter/e2e/helpers/test-data.ts +10 -0
  52. package/templates/starter/next-env.d.ts +6 -6
  53. package/templates/starter/package-lock.json +2 -2
  54. package/templates/starter/package.json +1 -1
  55. package/templates/starter/packages/cucumber-runtime/package.json +2 -1
  56. package/templates/starter/packages/cucumber-runtime/src/paths.ts +22 -5
  57. package/templates/starter/packages/locator-picker-companion/package.json +2 -1
  58. package/templates/starter/prisma/dev.db +0 -0
  59. package/templates/starter/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  60. package/templates/starter/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  61. package/templates/starter/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  62. package/templates/starter/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  63. package/templates/starter/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  64. package/templates/starter/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  65. package/templates/starter/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  66. package/templates/starter/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  67. package/templates/starter/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  68. package/templates/starter/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  69. package/templates/starter/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  70. package/templates/starter/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  71. package/templates/starter/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  72. package/templates/starter/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  73. package/templates/starter/scripts/setup-env.ts +0 -0
  74. package/templates/starter/scripts/sync-test-cases.ts +60 -10
  75. package/templates/starter/src/components/diagram/flow-diagram-node-search.tsx +9 -2
  76. package/templates/starter/src/components/diagram/flow-diagram-toolbar.tsx +37 -3
  77. package/templates/starter/src/components/diagram/flow-diagram.test.tsx +225 -0
  78. package/templates/starter/src/components/diagram/use-flow-diagram-search.ts +2 -0
  79. package/templates/starter/src/components/diagram/use-flow-diagram.ts +93 -0
  80. package/templates/starter/src/lib/appraise-test-case-metadata.test.ts +78 -0
  81. package/templates/starter/src/lib/appraise-test-case-metadata.ts +220 -0
  82. package/templates/starter/src/lib/automation/automation-path-roots.test.ts +14 -0
  83. package/templates/starter/src/lib/automation/automation-path-roots.ts +10 -2
  84. package/templates/starter/src/lib/database-sync.ts +166 -15
  85. package/templates/starter/src/lib/executor/local-executor-adapter.ts +6 -2
  86. package/templates/starter/src/lib/feature-file-generator.ts +54 -10
  87. package/templates/starter/src/lib/gherkin-parser.test.ts +52 -0
  88. package/templates/starter/src/lib/gherkin-parser.ts +39 -1
  89. package/templates/starter/src/lib/sync/projected-feature-utils.ts +5 -1
  90. package/templates/starter/src/lib/sync/sync-pending-counts.test.ts +115 -0
  91. package/templates/starter/src/lib/sync/sync-pending-counts.ts +108 -13
  92. package/templates/starter/src/services/test-run/test-run-service.test.ts +10 -0
  93. package/templates/starter/src/services/test-run/test-run-service.ts +41 -1
  94. package/dist/cli.e2e.test.d.ts +0 -2
  95. package/dist/cli.e2e.test.d.ts.map +0 -1
  96. package/dist/cli.e2e.test.js +0 -75
  97. package/dist/cli.e2e.test.js.map +0 -1
  98. package/dist/config.test.d.ts +0 -2
  99. package/dist/config.test.d.ts.map +0 -1
  100. package/dist/config.test.js +0 -65
  101. package/dist/config.test.js.map +0 -1
  102. package/dist/copy-template.test.d.ts +0 -2
  103. package/dist/copy-template.test.d.ts.map +0 -1
  104. package/dist/copy-template.test.js +0 -71
  105. package/dist/copy-template.test.js.map +0 -1
  106. package/dist/download-repo.test.d.ts +0 -2
  107. package/dist/download-repo.test.d.ts.map +0 -1
  108. package/dist/download-repo.test.js +0 -16
  109. package/dist/download-repo.test.js.map +0 -1
  110. package/dist/install.test.d.ts +0 -2
  111. package/dist/install.test.d.ts.map +0 -1
  112. package/dist/install.test.js +0 -120
  113. package/dist/install.test.js.map +0 -1
  114. package/dist/prompts.test.d.ts +0 -2
  115. package/dist/prompts.test.d.ts.map +0 -1
  116. package/dist/prompts.test.js +0 -58
  117. package/dist/prompts.test.js.map +0 -1
  118. package/templates/default/next-env.d.ts +0 -6
  119. package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +0 -1
  120. package/templates/default/packages/locator-picker-companion/dist/cli.js +0 -336
  121. package/templates/default/packages/locator-picker-companion/dist/index.d.ts +0 -3
  122. package/templates/default/packages/locator-picker-companion/dist/index.js +0 -3
  123. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +0 -1
  124. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +0 -660
  125. package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +0 -14
  126. package/templates/default/packages/locator-picker-companion/dist/launcher.js +0 -58
  127. package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +0 -6
  128. package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +0 -261
  129. package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +0 -30
  130. package/templates/default/packages/locator-picker-companion/dist/session-file.js +0 -162
  131. package/templates/default/packages/locator-picker-companion/dist/types.d.ts +0 -31
  132. package/templates/default/packages/locator-picker-companion/dist/types.js +0 -1
  133. package/templates/default/prisma/dev.db +0 -0
@@ -1,660 +0,0 @@
1
- export function installLocatorPickerOverlay() {
2
- var _a
3
- const globalState = window
4
- const ROOT_ID = 'appraise-locator-picker-root'
5
- const STYLE_ID = 'appraise-locator-picker-style'
6
- const HOVER_CLASS = 'appraise-locator-picker-hover'
7
- const ACTIVE_CLASS = 'appraise-locator-picker-active'
8
- const state =
9
- (_a = globalState.__appraiseLocatorPickerState) !== null && _a !== void 0
10
- ? _a
11
- : (globalState.__appraiseLocatorPickerState = {
12
- picking: false,
13
- submitting: false,
14
- hoveredElement: null,
15
- preview: null,
16
- error: '',
17
- elements: {},
18
- })
19
- function stopOverlayEvent(event) {
20
- event.preventDefault()
21
- event.stopPropagation()
22
- }
23
- function normalizeText(value) {
24
- return (value !== null && value !== void 0 ? value : '').replace(/\s+/g, ' ').trim()
25
- }
26
- function escapeForCss(value) {
27
- return value.replace(/[^a-zA-Z0-9_-]/g, match => `\\${match}`)
28
- }
29
- function escapeForSelectorText(value) {
30
- return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
31
- }
32
- function normalizeRoute(value) {
33
- if (!value) {
34
- return '/'
35
- }
36
- try {
37
- return new URL(value).pathname || '/'
38
- } catch (_a) {
39
- return value.startsWith('/') ? value : `/${value}`
40
- }
41
- }
42
- function isLikelyStableIdentifier(value) {
43
- if (!value) {
44
- return false
45
- }
46
- const normalized = value.trim()
47
- if (!normalized || normalized.length > 120) {
48
- return false
49
- }
50
- return !/\d{4,}/.test(normalized) && !/[A-Fa-f0-9]{8,}/.test(normalized)
51
- }
52
- function isFormControl(element) {
53
- return ['input', 'textarea', 'select'].includes(element.tagName.toLowerCase())
54
- }
55
- function getLabelText(element) {
56
- if (!isFormControl(element)) {
57
- return ''
58
- }
59
- const input = element
60
- if (input.labels && input.labels.length > 0) {
61
- return normalizeText(
62
- Array.from(input.labels)
63
- .map(label => label.textContent || '')
64
- .join(' '),
65
- )
66
- }
67
- return ''
68
- }
69
- function getAccessibleName(element) {
70
- const ariaLabel = normalizeText(element.getAttribute('aria-label'))
71
- if (ariaLabel) {
72
- return ariaLabel
73
- }
74
- const labelledBy = normalizeText(element.getAttribute('aria-labelledby'))
75
- if (labelledBy) {
76
- const text = labelledBy
77
- .split(/\s+/)
78
- .map(id => {
79
- var _a
80
- return ((_a = document.getElementById(id)) === null || _a === void 0 ? void 0 : _a.textContent) || ''
81
- })
82
- .join(' ')
83
- const normalized = normalizeText(text)
84
- if (normalized) {
85
- return normalized
86
- }
87
- }
88
- const labelText = getLabelText(element)
89
- if (labelText) {
90
- return labelText
91
- }
92
- const alt = normalizeText(element.getAttribute('alt'))
93
- if (alt) {
94
- return alt
95
- }
96
- const title = normalizeText(element.getAttribute('title'))
97
- if (title) {
98
- return title
99
- }
100
- const placeholder = normalizeText(element.getAttribute('placeholder'))
101
- if (placeholder) {
102
- return placeholder
103
- }
104
- return normalizeText(element.textContent).slice(0, 240)
105
- }
106
- function getRole(element) {
107
- const explicitRole = normalizeText(element.getAttribute('role'))
108
- if (explicitRole) {
109
- return explicitRole
110
- }
111
- const tagName = element.tagName.toLowerCase()
112
- if (tagName === 'button') {
113
- return 'button'
114
- }
115
- if (tagName === 'a' && element.hasAttribute('href')) {
116
- return 'link'
117
- }
118
- if (tagName === 'textarea') {
119
- return 'textbox'
120
- }
121
- if (tagName === 'select') {
122
- return 'combobox'
123
- }
124
- if (tagName === 'img') {
125
- return 'img'
126
- }
127
- if (tagName === 'input') {
128
- const type = (element.getAttribute('type') || 'text').toLowerCase()
129
- if (['button', 'submit', 'reset'].includes(type)) {
130
- return 'button'
131
- }
132
- if (type === 'checkbox') {
133
- return 'checkbox'
134
- }
135
- if (type === 'radio') {
136
- return 'radio'
137
- }
138
- return 'textbox'
139
- }
140
- return ''
141
- }
142
- function countRoleNameMatches(role, accessibleName) {
143
- let count = 0
144
- for (const candidate of Array.from(document.querySelectorAll('*'))) {
145
- if (getRole(candidate) !== role) {
146
- continue
147
- }
148
- if (getAccessibleName(candidate) !== accessibleName) {
149
- continue
150
- }
151
- count += 1
152
- if (count > 1) {
153
- break
154
- }
155
- }
156
- return count
157
- }
158
- function buildCssSelector(element) {
159
- const tagName = element.tagName.toLowerCase()
160
- const name = element.getAttribute('name')
161
- const type = element.getAttribute('type')
162
- const ariaLabel = element.getAttribute('aria-label')
163
- const parts = [tagName]
164
- if (isLikelyStableIdentifier(name)) {
165
- parts.push(`[name="${escapeForSelectorText(name)}"]`)
166
- }
167
- if (isLikelyStableIdentifier(type)) {
168
- parts.push(`[type="${escapeForSelectorText(type)}"]`)
169
- }
170
- if (isLikelyStableIdentifier(ariaLabel)) {
171
- parts.push(`[aria-label="${escapeForSelectorText(ariaLabel)}"]`)
172
- }
173
- if (parts.length === 1) {
174
- const stableClasses = Array.from(element.classList || [])
175
- .filter(isLikelyStableIdentifier)
176
- .slice(0, 2)
177
- if (stableClasses.length > 0) {
178
- parts.push(...stableClasses.map(className => `.${escapeForCss(className)}`))
179
- }
180
- }
181
- return parts.length > 1 ? `css=${parts.join('')}` : ''
182
- }
183
- function buildXPathSelector(element, text) {
184
- const tagName = element.tagName.toLowerCase()
185
- const id = element.getAttribute('id')
186
- if (id) {
187
- return `xpath=//*[@id="${id.replace(/"/g, '\\"')}"]`
188
- }
189
- if (text) {
190
- return `xpath=//${tagName}[normalize-space()="${text.replace(/"/g, '\\"')}"]`
191
- }
192
- return `xpath=//${tagName}`
193
- }
194
- function buildPrimarySelector(element) {
195
- for (const attributeName of ['data-testid', 'data-test', 'data-qa']) {
196
- const value = element.getAttribute(attributeName)
197
- if (isLikelyStableIdentifier(value)) {
198
- return {
199
- selector: `css=[${attributeName}="${escapeForSelectorText(value)}"]`,
200
- strategy: 'test-id',
201
- }
202
- }
203
- }
204
- const accessibleName = getAccessibleName(element)
205
- const role = getRole(element)
206
- if (role && accessibleName && countRoleNameMatches(role, accessibleName) === 1) {
207
- return {
208
- selector: `role=${role}[name="${escapeForSelectorText(accessibleName)}"]`,
209
- strategy: 'role',
210
- }
211
- }
212
- const labelText = getLabelText(element)
213
- if (labelText) {
214
- return {
215
- selector: `label="${escapeForSelectorText(labelText)}"`,
216
- strategy: 'label',
217
- }
218
- }
219
- const placeholder = normalizeText(element.getAttribute('placeholder'))
220
- if (placeholder) {
221
- return {
222
- selector: `placeholder="${escapeForSelectorText(placeholder)}"`,
223
- strategy: 'placeholder',
224
- }
225
- }
226
- const id = element.getAttribute('id')
227
- if (isLikelyStableIdentifier(id)) {
228
- return {
229
- selector: `css=#${escapeForCss(id)}`,
230
- strategy: 'id',
231
- }
232
- }
233
- const cssSelector = buildCssSelector(element)
234
- if (cssSelector) {
235
- return {
236
- selector: cssSelector,
237
- strategy: 'css',
238
- }
239
- }
240
- return {
241
- selector: buildXPathSelector(element, normalizeText(element.textContent).slice(0, 120)),
242
- strategy: 'xpath',
243
- }
244
- }
245
- function buildPreviewPayload(element) {
246
- const selection = buildPrimarySelector(element)
247
- return {
248
- selector: selection.selector,
249
- strategy: selection.strategy,
250
- currentUrl: window.location.href,
251
- pathname: normalizeRoute(window.location.href),
252
- pageTitle: document.title || '',
253
- tagName: element.tagName.toLowerCase(),
254
- text: normalizeText(element.textContent).slice(0, 240) || undefined,
255
- accessibleName: getAccessibleName(element) || undefined,
256
- }
257
- }
258
- function clearHover() {
259
- if (state.hoveredElement instanceof Element) {
260
- state.hoveredElement.classList.remove(HOVER_CLASS)
261
- }
262
- state.hoveredElement = null
263
- }
264
- function setPicking(enabled) {
265
- state.picking = enabled
266
- document.documentElement.classList.toggle(ACTIVE_CLASS, enabled)
267
- if (!enabled) {
268
- clearHover()
269
- }
270
- render()
271
- }
272
- function resolveElement(target) {
273
- if (target instanceof Element) {
274
- return target
275
- }
276
- if (target instanceof Node) {
277
- return target.parentElement
278
- }
279
- return null
280
- }
281
- function getMountTarget() {
282
- var _a, _b
283
- return (_b = (_a = document.body) !== null && _a !== void 0 ? _a : document.documentElement) !== null &&
284
- _b !== void 0
285
- ? _b
286
- : null
287
- }
288
- function ensureStyle() {
289
- if (!document.documentElement) {
290
- return
291
- }
292
- if (document.getElementById(STYLE_ID)) {
293
- return
294
- }
295
- const style = document.createElement('style')
296
- style.id = STYLE_ID
297
- style.textContent = `
298
- .${HOVER_CLASS} {
299
- outline: 2px solid #0f766e !important;
300
- outline-offset: 2px !important;
301
- background-color: rgba(15, 118, 110, 0.12) !important;
302
- cursor: crosshair !important;
303
- }
304
-
305
- html.${ACTIVE_CLASS},
306
- html.${ACTIVE_CLASS} * {
307
- cursor: crosshair !important;
308
- }
309
-
310
- #${ROOT_ID} {
311
- position: fixed;
312
- right: 20px;
313
- bottom: 20px;
314
- z-index: 2147483647;
315
- width: min(360px, calc(100vw - 32px));
316
- padding: 16px;
317
- border-radius: 18px;
318
- border: 1px solid rgba(15, 23, 42, 0.14);
319
- background: rgba(255, 255, 255, 0.96);
320
- box-shadow: 0 18px 40px rgba(15, 23, 42, 0.18);
321
- backdrop-filter: blur(12px);
322
- color: #0f172a;
323
- font-family: "Segoe UI", "Helvetica Neue", sans-serif;
324
- }
325
-
326
- #${ROOT_ID} * {
327
- box-sizing: border-box;
328
- font-family: inherit;
329
- }
330
-
331
- #${ROOT_ID} .appraise-picker-heading {
332
- margin: 0 0 6px;
333
- font-size: 15px;
334
- font-weight: 700;
335
- }
336
-
337
- #${ROOT_ID} .appraise-picker-copy {
338
- margin: 0;
339
- color: #475569;
340
- font-size: 12px;
341
- line-height: 1.45;
342
- }
343
-
344
- #${ROOT_ID} .appraise-picker-status {
345
- margin: 10px 0 0;
346
- color: #0f766e;
347
- font-size: 12px;
348
- font-weight: 600;
349
- }
350
-
351
- #${ROOT_ID} .appraise-picker-card {
352
- margin-top: 14px;
353
- padding: 12px;
354
- border-radius: 14px;
355
- background: #f8fafc;
356
- border: 1px solid rgba(148, 163, 184, 0.25);
357
- }
358
-
359
- #${ROOT_ID} .appraise-picker-label {
360
- display: block;
361
- margin-bottom: 6px;
362
- color: #334155;
363
- font-size: 11px;
364
- font-weight: 700;
365
- letter-spacing: 0.04em;
366
- text-transform: uppercase;
367
- }
368
-
369
- #${ROOT_ID} .appraise-picker-value {
370
- margin: 0;
371
- color: #0f172a;
372
- font-size: 12px;
373
- line-height: 1.5;
374
- white-space: pre-wrap;
375
- word-break: break-word;
376
- }
377
-
378
- #${ROOT_ID} .appraise-picker-actions {
379
- display: flex;
380
- flex-wrap: wrap;
381
- gap: 8px;
382
- margin-top: 14px;
383
- }
384
-
385
- #${ROOT_ID} button {
386
- border: none;
387
- border-radius: 999px;
388
- padding: 10px 14px;
389
- font-size: 12px;
390
- font-weight: 700;
391
- cursor: pointer;
392
- }
393
-
394
- #${ROOT_ID} button:disabled {
395
- cursor: not-allowed;
396
- opacity: 0.6;
397
- }
398
-
399
- #${ROOT_ID} .appraise-picker-primary {
400
- background: #0f766e;
401
- color: #ffffff;
402
- }
403
-
404
- #${ROOT_ID} .appraise-picker-secondary {
405
- background: #e2e8f0;
406
- color: #0f172a;
407
- }
408
-
409
- #${ROOT_ID} .appraise-picker-error {
410
- margin: 10px 0 0;
411
- color: #b91c1c;
412
- font-size: 12px;
413
- line-height: 1.4;
414
- }
415
- `
416
- document.documentElement.appendChild(style)
417
- }
418
- function ensureRoot() {
419
- var _a
420
- const mountTarget = getMountTarget()
421
- if (!mountTarget) {
422
- return
423
- }
424
- if ((_a = state.elements.root) === null || _a === void 0 ? void 0 : _a.isConnected) {
425
- return
426
- }
427
- const root = document.createElement('div')
428
- root.id = ROOT_ID
429
- root.setAttribute('role', 'dialog')
430
- root.setAttribute('aria-label', 'Appraise locator picker')
431
- const heading = document.createElement('p')
432
- heading.className = 'appraise-picker-heading'
433
- heading.textContent = 'Appraise Locator Picker'
434
- const helperText = document.createElement('p')
435
- helperText.className = 'appraise-picker-copy'
436
- const statusText = document.createElement('p')
437
- statusText.className = 'appraise-picker-status'
438
- const previewCard = document.createElement('div')
439
- previewCard.className = 'appraise-picker-card'
440
- const selectorLabel = document.createElement('span')
441
- selectorLabel.className = 'appraise-picker-label'
442
- selectorLabel.textContent = 'Selector'
443
- const selectorValue = document.createElement('pre')
444
- selectorValue.className = 'appraise-picker-value'
445
- const metadataLabel = document.createElement('span')
446
- metadataLabel.className = 'appraise-picker-label'
447
- metadataLabel.textContent = 'Page'
448
- const metadataValue = document.createElement('p')
449
- metadataValue.className = 'appraise-picker-value'
450
- previewCard.appendChild(selectorLabel)
451
- previewCard.appendChild(selectorValue)
452
- previewCard.appendChild(metadataLabel)
453
- previewCard.appendChild(metadataValue)
454
- const errorValue = document.createElement('p')
455
- errorValue.className = 'appraise-picker-error'
456
- const actions = document.createElement('div')
457
- actions.className = 'appraise-picker-actions'
458
- const startButton = document.createElement('button')
459
- startButton.className = 'appraise-picker-primary'
460
- startButton.type = 'button'
461
- startButton.textContent = 'Start picking'
462
- startButton.addEventListener('click', event => {
463
- stopOverlayEvent(event)
464
- state.submitting = false
465
- state.preview = null
466
- state.error = ''
467
- setPicking(true)
468
- })
469
- const useButton = document.createElement('button')
470
- useButton.className = 'appraise-picker-primary'
471
- useButton.type = 'button'
472
- useButton.textContent = 'Use selector'
473
- useButton.addEventListener('click', event => {
474
- stopOverlayEvent(event)
475
- if (!state.preview || state.submitting || !globalState.__appraiseLocatorPickerConfirm) {
476
- return
477
- }
478
- state.submitting = true
479
- state.error = ''
480
- render()
481
- void globalState
482
- .__appraiseLocatorPickerConfirm(state.preview)
483
- .catch(error => {
484
- state.error = error instanceof Error ? error.message : 'Unable to use selector.'
485
- })
486
- .finally(() => {
487
- state.submitting = false
488
- render()
489
- })
490
- })
491
- const pickAgainButton = document.createElement('button')
492
- pickAgainButton.className = 'appraise-picker-secondary'
493
- pickAgainButton.type = 'button'
494
- pickAgainButton.textContent = 'Pick again'
495
- pickAgainButton.addEventListener('click', event => {
496
- stopOverlayEvent(event)
497
- state.submitting = false
498
- state.preview = null
499
- state.error = ''
500
- setPicking(true)
501
- })
502
- const cancelButton = document.createElement('button')
503
- cancelButton.className = 'appraise-picker-secondary'
504
- cancelButton.type = 'button'
505
- cancelButton.textContent = 'Cancel'
506
- cancelButton.addEventListener('click', event => {
507
- stopOverlayEvent(event)
508
- if (state.submitting || !globalState.__appraiseLocatorPickerCancel) {
509
- return
510
- }
511
- state.submitting = true
512
- render()
513
- void globalState.__appraiseLocatorPickerCancel().catch(() => undefined)
514
- })
515
- actions.append(startButton, useButton, pickAgainButton, cancelButton)
516
- root.append(heading, helperText, statusText, previewCard, errorValue, actions)
517
- root.addEventListener('pointerdown', event => event.stopPropagation())
518
- root.addEventListener('click', event => event.stopPropagation())
519
- mountTarget.appendChild(root)
520
- state.elements = {
521
- root,
522
- startButton,
523
- useButton,
524
- pickAgainButton,
525
- cancelButton,
526
- helperText,
527
- statusText,
528
- selectorValue,
529
- metadataValue,
530
- errorValue,
531
- }
532
- }
533
- function render() {
534
- var _a, _b
535
- ensureStyle()
536
- ensureRoot()
537
- document.documentElement.classList.toggle(ACTIVE_CLASS, state.picking)
538
- if (state.hoveredElement && !state.hoveredElement.isConnected) {
539
- state.hoveredElement = null
540
- }
541
- const {
542
- helperText,
543
- statusText,
544
- selectorValue,
545
- metadataValue,
546
- errorValue,
547
- startButton,
548
- useButton,
549
- pickAgainButton,
550
- cancelButton,
551
- } = state.elements
552
- if (
553
- !helperText ||
554
- !statusText ||
555
- !selectorValue ||
556
- !metadataValue ||
557
- !errorValue ||
558
- !startButton ||
559
- !useButton ||
560
- !pickAgainButton ||
561
- !cancelButton
562
- ) {
563
- return
564
- }
565
- helperText.textContent = state.preview
566
- ? 'Review the generated selector, then confirm it or pick a different element.'
567
- : 'Start picking, hover to highlight, then click one element to preview a single generated selector.'
568
- if (state.picking) {
569
- statusText.textContent = 'Picking mode is on'
570
- } else if (state.preview) {
571
- statusText.textContent = 'Selection ready'
572
- } else {
573
- statusText.textContent = 'Waiting to start'
574
- }
575
- selectorValue.textContent =
576
- (_b = (_a = state.preview) === null || _a === void 0 ? void 0 : _a.selector) !== null && _b !== void 0
577
- ? _b
578
- : 'No selector picked yet.'
579
- metadataValue.textContent = state.preview
580
- ? [state.preview.pageTitle || '(untitled page)', state.preview.currentUrl].filter(Boolean).join('\n')
581
- : 'The selected page metadata will appear here.'
582
- errorValue.textContent = state.error
583
- startButton.style.display = state.preview ? 'none' : 'inline-flex'
584
- useButton.style.display = state.preview ? 'inline-flex' : 'none'
585
- pickAgainButton.style.display = state.preview ? 'inline-flex' : 'none'
586
- useButton.disabled = !state.preview || state.submitting
587
- pickAgainButton.disabled = state.submitting
588
- cancelButton.disabled = state.submitting
589
- }
590
- function installOrRender() {
591
- render()
592
- }
593
- if (!globalState.__appraiseLocatorPickerDomListenersBound) {
594
- globalState.__appraiseLocatorPickerDomListenersBound = true
595
- document.addEventListener('DOMContentLoaded', installOrRender)
596
- window.addEventListener('load', installOrRender)
597
- }
598
- if (globalState.__appraiseLocatorPickerInstalled) {
599
- installOrRender()
600
- return
601
- }
602
- globalState.__appraiseLocatorPickerInstalled = true
603
- document.addEventListener(
604
- 'mouseover',
605
- event => {
606
- if (!state.picking) {
607
- return
608
- }
609
- const target = resolveElement(event.target)
610
- if (!target || target.closest(`#${ROOT_ID}`)) {
611
- return
612
- }
613
- clearHover()
614
- target.classList.add(HOVER_CLASS)
615
- state.hoveredElement = target
616
- },
617
- true,
618
- )
619
- document.addEventListener(
620
- 'mouseout',
621
- event => {
622
- if (!state.picking) {
623
- return
624
- }
625
- const target = resolveElement(event.target)
626
- if (target instanceof Element) {
627
- target.classList.remove(HOVER_CLASS)
628
- }
629
- },
630
- true,
631
- )
632
- document.addEventListener(
633
- 'click',
634
- event => {
635
- if (!state.picking) {
636
- return
637
- }
638
- const target = resolveElement(event.target)
639
- if (!target || target.closest(`#${ROOT_ID}`)) {
640
- return
641
- }
642
- event.preventDefault()
643
- event.stopPropagation()
644
- event.stopImmediatePropagation()
645
- void Promise.resolve()
646
- .then(() => {
647
- const preview = buildPreviewPayload(target)
648
- state.preview = preview
649
- state.error = ''
650
- setPicking(false)
651
- })
652
- .catch(error => {
653
- state.error = error instanceof Error ? error.message : 'Unable to inspect that element.'
654
- setPicking(false)
655
- })
656
- },
657
- true,
658
- )
659
- installOrRender()
660
- }
@@ -1,14 +0,0 @@
1
- export declare function getLocatorPickerCompanionPaths(repoRoot?: string): {
2
- packageRoot: string
3
- sourceRoot: string
4
- distCliPath: string
5
- tsconfigPath: string
6
- tscCliPath: string
7
- }
8
- export declare function resolveLocatorPickerCompanionInvocation(
9
- cliArgs: string[],
10
- repoRoot?: string,
11
- ): Promise<{
12
- command: string
13
- args: string[]
14
- }>