selenium-webdriver 4.49.0 → 4.50.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 (217) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +13 -0
  3. data/Gemfile +0 -0
  4. data/LICENSE +0 -0
  5. data/NOTICE +0 -0
  6. data/README.md +0 -0
  7. data/bin/linux-arm64/selenium-manager +0 -0
  8. data/bin/linux-x86_64/selenium-manager +0 -0
  9. data/bin/macos/selenium-manager +0 -0
  10. data/bin/selenium-manager-THIRD-PARTY-NOTICES.txt +74 -43
  11. data/bin/selenium-manager.cdx.json +421 -421
  12. data/bin/windows/selenium-manager.exe +0 -0
  13. data/lib/selenium/server.rb +0 -0
  14. data/lib/selenium/webdriver/atoms/findElements.js +14 -2
  15. data/lib/selenium/webdriver/atoms.rb +0 -0
  16. data/lib/selenium/webdriver/bidi/browser.rb +0 -0
  17. data/lib/selenium/webdriver/bidi/browsing_context.rb +0 -0
  18. data/lib/selenium/webdriver/bidi/error.rb +0 -0
  19. data/lib/selenium/webdriver/bidi/log_handler.rb +0 -0
  20. data/lib/selenium/webdriver/bidi/network/cookies.rb +0 -0
  21. data/lib/selenium/webdriver/bidi/network/credentials.rb +0 -0
  22. data/lib/selenium/webdriver/bidi/network/headers.rb +0 -0
  23. data/lib/selenium/webdriver/bidi/network/intercepted_auth.rb +0 -0
  24. data/lib/selenium/webdriver/bidi/network/intercepted_item.rb +0 -0
  25. data/lib/selenium/webdriver/bidi/network/intercepted_request.rb +0 -0
  26. data/lib/selenium/webdriver/bidi/network/intercepted_response.rb +0 -0
  27. data/lib/selenium/webdriver/bidi/network/url_pattern.rb +0 -0
  28. data/lib/selenium/webdriver/bidi/network.rb +0 -0
  29. data/lib/selenium/webdriver/bidi/protocol/bluetooth.rb +27 -23
  30. data/lib/selenium/webdriver/bidi/protocol/browser.rb +0 -0
  31. data/lib/selenium/webdriver/bidi/protocol/browsing_context.rb +58 -4
  32. data/lib/selenium/webdriver/bidi/protocol/digital_credentials.rb +69 -0
  33. data/lib/selenium/webdriver/bidi/protocol/domain.rb +0 -0
  34. data/lib/selenium/webdriver/bidi/protocol/emulation.rb +31 -0
  35. data/lib/selenium/webdriver/bidi/protocol/error_code.rb +0 -0
  36. data/lib/selenium/webdriver/bidi/protocol/input.rb +0 -0
  37. data/lib/selenium/webdriver/bidi/protocol/log.rb +0 -0
  38. data/lib/selenium/webdriver/bidi/protocol/moz_debugging.rb +334 -0
  39. data/lib/selenium/webdriver/bidi/protocol/moz_profiler.rb +108 -0
  40. data/lib/selenium/webdriver/bidi/protocol/network.rb +0 -0
  41. data/lib/selenium/webdriver/bidi/protocol/permissions.rb +0 -0
  42. data/lib/selenium/webdriver/bidi/protocol/script.rb +0 -0
  43. data/lib/selenium/webdriver/bidi/protocol/session.rb +0 -0
  44. data/lib/selenium/webdriver/bidi/protocol/speculation.rb +0 -0
  45. data/lib/selenium/webdriver/bidi/protocol/storage.rb +0 -0
  46. data/lib/selenium/webdriver/bidi/protocol/user_agent_client_hints.rb +0 -0
  47. data/lib/selenium/webdriver/bidi/protocol/web_extension.rb +41 -5
  48. data/lib/selenium/webdriver/bidi/protocol.rb +3 -0
  49. data/lib/selenium/webdriver/bidi/serialization/record.rb +0 -0
  50. data/lib/selenium/webdriver/bidi/serialization/union.rb +0 -0
  51. data/lib/selenium/webdriver/bidi/serialization.rb +0 -0
  52. data/lib/selenium/webdriver/bidi/session.rb +0 -0
  53. data/lib/selenium/webdriver/bidi/struct.rb +0 -0
  54. data/lib/selenium/webdriver/bidi/support/bidi_generate.rb +154 -38
  55. data/lib/selenium/webdriver/bidi/support/check_generated.rb +0 -0
  56. data/lib/selenium/webdriver/bidi/transport.rb +0 -0
  57. data/lib/selenium/webdriver/bidi.rb +0 -0
  58. data/lib/selenium/webdriver/chrome/driver.rb +0 -0
  59. data/lib/selenium/webdriver/chrome/features.rb +0 -0
  60. data/lib/selenium/webdriver/chrome/options.rb +0 -0
  61. data/lib/selenium/webdriver/chrome/profile.rb +0 -0
  62. data/lib/selenium/webdriver/chrome/service.rb +0 -0
  63. data/lib/selenium/webdriver/chrome.rb +0 -0
  64. data/lib/selenium/webdriver/chromium/driver.rb +0 -0
  65. data/lib/selenium/webdriver/chromium/features.rb +0 -0
  66. data/lib/selenium/webdriver/chromium/options.rb +0 -0
  67. data/lib/selenium/webdriver/chromium/profile.rb +0 -0
  68. data/lib/selenium/webdriver/chromium.rb +0 -0
  69. data/lib/selenium/webdriver/common/action_builder.rb +0 -0
  70. data/lib/selenium/webdriver/common/alert.rb +0 -0
  71. data/lib/selenium/webdriver/common/child_process.rb +0 -0
  72. data/lib/selenium/webdriver/common/client_config.rb +0 -0
  73. data/lib/selenium/webdriver/common/driver.rb +24 -0
  74. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -0
  75. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -0
  76. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +2 -0
  77. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -0
  78. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -0
  79. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +0 -0
  80. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -0
  81. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +0 -0
  82. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -0
  83. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -0
  84. data/lib/selenium/webdriver/common/driver_extensions/has_fedcm_dialog.rb +0 -0
  85. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +0 -0
  86. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -0
  87. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +0 -0
  88. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +0 -0
  89. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -0
  90. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +0 -0
  91. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -0
  92. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +0 -0
  93. data/lib/selenium/webdriver/common/driver_extensions/has_session_events.rb +0 -0
  94. data/lib/selenium/webdriver/common/driver_extensions/has_session_id.rb +0 -0
  95. data/lib/selenium/webdriver/common/driver_extensions/prints_page.rb +0 -0
  96. data/lib/selenium/webdriver/common/driver_extensions/uploads_files.rb +0 -0
  97. data/lib/selenium/webdriver/common/driver_finder.rb +0 -0
  98. data/lib/selenium/webdriver/common/element.rb +0 -0
  99. data/lib/selenium/webdriver/common/error.rb +0 -0
  100. data/lib/selenium/webdriver/common/fedcm/account.rb +0 -0
  101. data/lib/selenium/webdriver/common/fedcm/dialog.rb +0 -0
  102. data/lib/selenium/webdriver/common/fedcm.rb +0 -0
  103. data/lib/selenium/webdriver/common/file_reaper.rb +0 -0
  104. data/lib/selenium/webdriver/common/interactions/input_device.rb +0 -0
  105. data/lib/selenium/webdriver/common/interactions/interaction.rb +0 -0
  106. data/lib/selenium/webdriver/common/interactions/interactions.rb +0 -0
  107. data/lib/selenium/webdriver/common/interactions/key_actions.rb +0 -0
  108. data/lib/selenium/webdriver/common/interactions/key_input.rb +0 -0
  109. data/lib/selenium/webdriver/common/interactions/none_input.rb +0 -0
  110. data/lib/selenium/webdriver/common/interactions/pause.rb +0 -0
  111. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +0 -0
  112. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +0 -0
  113. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +0 -0
  114. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +0 -0
  115. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +0 -0
  116. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +0 -0
  117. data/lib/selenium/webdriver/common/interactions/scroll.rb +0 -0
  118. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +0 -0
  119. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +0 -0
  120. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +0 -0
  121. data/lib/selenium/webdriver/common/interactions/wheel_input.rb +0 -0
  122. data/lib/selenium/webdriver/common/keys.rb +0 -0
  123. data/lib/selenium/webdriver/common/local_driver.rb +0 -0
  124. data/lib/selenium/webdriver/common/log_entry.rb +0 -0
  125. data/lib/selenium/webdriver/common/logger.rb +0 -0
  126. data/lib/selenium/webdriver/common/logs.rb +0 -0
  127. data/lib/selenium/webdriver/common/manager.rb +0 -0
  128. data/lib/selenium/webdriver/common/navigation.rb +0 -0
  129. data/lib/selenium/webdriver/common/network.rb +0 -0
  130. data/lib/selenium/webdriver/common/options.rb +0 -0
  131. data/lib/selenium/webdriver/common/platform.rb +0 -0
  132. data/lib/selenium/webdriver/common/port_prober.rb +0 -0
  133. data/lib/selenium/webdriver/common/print_options.rb +0 -0
  134. data/lib/selenium/webdriver/common/profile_helper.rb +0 -0
  135. data/lib/selenium/webdriver/common/proxy.rb +0 -0
  136. data/lib/selenium/webdriver/common/script.rb +0 -0
  137. data/lib/selenium/webdriver/common/search_context.rb +0 -0
  138. data/lib/selenium/webdriver/common/selenium_manager.rb +0 -0
  139. data/lib/selenium/webdriver/common/service.rb +0 -0
  140. data/lib/selenium/webdriver/common/service_manager.rb +0 -0
  141. data/lib/selenium/webdriver/common/shadow_root.rb +0 -0
  142. data/lib/selenium/webdriver/common/socket_lock.rb +0 -0
  143. data/lib/selenium/webdriver/common/socket_poller.rb +0 -0
  144. data/lib/selenium/webdriver/common/takes_screenshot.rb +0 -0
  145. data/lib/selenium/webdriver/common/target_locator.rb +0 -0
  146. data/lib/selenium/webdriver/common/timeouts.rb +0 -0
  147. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +0 -0
  148. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +0 -0
  149. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +0 -0
  150. data/lib/selenium/webdriver/common/wait.rb +0 -0
  151. data/lib/selenium/webdriver/common/web_extension.rb +42 -0
  152. data/lib/selenium/webdriver/common/websocket_connection.rb +2 -2
  153. data/lib/selenium/webdriver/common/window.rb +0 -0
  154. data/lib/selenium/webdriver/common/zipper.rb +15 -11
  155. data/lib/selenium/webdriver/common.rb +1 -0
  156. data/lib/selenium/webdriver/devtools/console_event.rb +0 -0
  157. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -0
  158. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -0
  159. data/lib/selenium/webdriver/devtools/network_interceptor.rb +0 -0
  160. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -0
  161. data/lib/selenium/webdriver/devtools/request.rb +0 -0
  162. data/lib/selenium/webdriver/devtools/response.rb +0 -0
  163. data/lib/selenium/webdriver/devtools.rb +0 -0
  164. data/lib/selenium/webdriver/edge/driver.rb +0 -0
  165. data/lib/selenium/webdriver/edge/features.rb +0 -0
  166. data/lib/selenium/webdriver/edge/options.rb +0 -0
  167. data/lib/selenium/webdriver/edge/profile.rb +0 -0
  168. data/lib/selenium/webdriver/edge/service.rb +0 -0
  169. data/lib/selenium/webdriver/edge.rb +0 -0
  170. data/lib/selenium/webdriver/firefox/driver.rb +0 -0
  171. data/lib/selenium/webdriver/firefox/features.rb +18 -7
  172. data/lib/selenium/webdriver/firefox/options.rb +0 -0
  173. data/lib/selenium/webdriver/firefox/profile.rb +0 -37
  174. data/lib/selenium/webdriver/firefox/profiles_ini.rb +0 -0
  175. data/lib/selenium/webdriver/firefox/service.rb +0 -0
  176. data/lib/selenium/webdriver/firefox/util.rb +0 -0
  177. data/lib/selenium/webdriver/firefox.rb +0 -2
  178. data/lib/selenium/webdriver/ie/driver.rb +0 -0
  179. data/lib/selenium/webdriver/ie/features.rb +0 -0
  180. data/lib/selenium/webdriver/ie/options.rb +0 -0
  181. data/lib/selenium/webdriver/ie/service.rb +0 -0
  182. data/lib/selenium/webdriver/ie.rb +0 -0
  183. data/lib/selenium/webdriver/remote/bidi_bridge.rb +23 -0
  184. data/lib/selenium/webdriver/remote/bridge/commands.rb +0 -0
  185. data/lib/selenium/webdriver/remote/bridge/locator_converter.rb +0 -0
  186. data/lib/selenium/webdriver/remote/bridge.rb +20 -6
  187. data/lib/selenium/webdriver/remote/capabilities.rb +0 -0
  188. data/lib/selenium/webdriver/remote/driver.rb +0 -0
  189. data/lib/selenium/webdriver/remote/features.rb +9 -8
  190. data/lib/selenium/webdriver/remote/http/common.rb +0 -0
  191. data/lib/selenium/webdriver/remote/http/curb.rb +0 -0
  192. data/lib/selenium/webdriver/remote/http/default.rb +0 -0
  193. data/lib/selenium/webdriver/remote/response.rb +0 -0
  194. data/lib/selenium/webdriver/remote/server_error.rb +0 -0
  195. data/lib/selenium/webdriver/remote.rb +0 -0
  196. data/lib/selenium/webdriver/safari/driver.rb +0 -0
  197. data/lib/selenium/webdriver/safari/features.rb +0 -0
  198. data/lib/selenium/webdriver/safari/options.rb +0 -0
  199. data/lib/selenium/webdriver/safari/service.rb +0 -0
  200. data/lib/selenium/webdriver/safari.rb +0 -0
  201. data/lib/selenium/webdriver/support/abstract_event_listener.rb +0 -0
  202. data/lib/selenium/webdriver/support/block_event_listener.rb +0 -0
  203. data/lib/selenium/webdriver/support/color.rb +0 -0
  204. data/lib/selenium/webdriver/support/escaper.rb +0 -0
  205. data/lib/selenium/webdriver/support/event_firing_bridge.rb +0 -0
  206. data/lib/selenium/webdriver/support/guards/guard.rb +0 -0
  207. data/lib/selenium/webdriver/support/guards/guard_condition.rb +0 -0
  208. data/lib/selenium/webdriver/support/guards.rb +0 -0
  209. data/lib/selenium/webdriver/support/relative_locator.rb +0 -0
  210. data/lib/selenium/webdriver/support/select.rb +0 -0
  211. data/lib/selenium/webdriver/support.rb +0 -0
  212. data/lib/selenium/webdriver/version.rb +1 -1
  213. data/lib/selenium/webdriver.rb +0 -0
  214. data/lib/selenium-webdriver.rb +0 -0
  215. data/selenium-webdriver.gemspec +0 -1
  216. metadata +7 -27
  217. data/lib/selenium/webdriver/firefox/extension.rb +0 -103
@@ -48,8 +48,10 @@ module BiDiGenerate
48
48
  RUBY_RESERVED = %w[begin end rescue ensure raise return yield if unless while until for do
49
49
  case when then class module def].freeze
50
50
 
51
+ # A vendor namespace separator (`moz:debugging`) reads as a word boundary.
51
52
  def self.camel_to_snake(str)
52
53
  str
54
+ .tr(':', '_')
53
55
  .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
54
56
  .gsub(/([a-z\d])([A-Z])/, '\1_\2')
55
57
  .downcase
@@ -72,6 +74,11 @@ module BiDiGenerate
72
74
  "#{snake_to_class_name(camel_to_snake(domain))}::#{type_class_name(type_name)}"
73
75
  end
74
76
 
77
+ # Source literal for a list of wire keys, in the form RuboCop expects at each size.
78
+ def self.word_array(words)
79
+ words.size > 1 ? "%w[#{words.join(' ')}]" : "[#{words.map { |w| "'#{w}'" }.join(', ')}]"
80
+ end
81
+
75
82
  # Source literal for a discriminator/const value (string, boolean, or number).
76
83
  def self.ruby_literal(value)
77
84
  return 'nil' if value.nil?
@@ -100,15 +107,17 @@ module BiDiGenerate
100
107
  RESERVED_FIELD_NAMES = (RUBY_RESERVED + %w[method hash class send dup clone freeze inspect
101
108
  to_h to_s members with deconstruct deconstruct_keys
102
109
  object_id tap itself then display
103
- extensible extensions]).freeze
110
+ extensible]).freeze
104
111
 
105
112
  # Append underscore to a field name that would shadow a core method; the wire
106
113
  # name is unaffected, only the Ruby reader is renamed.
107
- def self.safe_field_name(name)
114
+ def self.safe_field_name(name, extensible: true)
108
115
  # A vendor-prefixed wire name carries a colon (moz:allowPrivateBrowsing); swap it
109
116
  # for an underscore so the Ruby reader is a legal identifier. The wire key is kept.
110
117
  name = name.tr(':', '_')
111
- RESERVED_FIELD_NAMES.include?(name) ? "#{name}_" : name
118
+ # Only an extensible record holds its undeclared fields in an `extensions` member.
119
+ reserved = RESERVED_FIELD_NAMES.include?(name) || (extensible && name == 'extensions')
120
+ reserved ? "#{name}_" : name
112
121
  end
113
122
 
114
123
  # SCREAMING_SNAKE constant name for an enum, matching the EVENTS map style
@@ -226,6 +235,20 @@ module BiDiGenerate
226
235
  args << "result: #{result_ref}" if result_ref
227
236
  BiDiGenerate.wrap_call('execute', args, indent)
228
237
  end
238
+
239
+ # The full `def … end` block, shared by the module template and a vendor variant that adds
240
+ # the command (VendorModule#render), so both render a command identically.
241
+ def render_lines(indent)
242
+ pad = ' ' * indent
243
+ body = ' ' * (indent + 2)
244
+ lines = ["#{pad}# @api private", "#{pad}# @see #{BiDiGenerate::BIDI_DOC_URL}"]
245
+ lines << "#{pad}# @see #{spec_href}" if spec_href
246
+ lines << "#{pad}#{def_header(indent)}"
247
+ lines.concat(enum_checks(indent + 2).map { |check| "#{body}#{check}" })
248
+ assignment = params_assignment(indent + 2)
249
+ lines << "#{body}#{assignment}" if assignment
250
+ lines + ["#{body}#{execute_call(indent + 2)}", "#{pad}end"]
251
+ end
229
252
  end
230
253
 
231
254
  # A browser-specific extension to a command, kept out of the shared class so a
@@ -280,8 +303,9 @@ module BiDiGenerate
280
303
  end
281
304
  end
282
305
 
283
- # A namespaced group of browser-specific command extensions (e.g. Firefox's `moz:`
284
- # fields), emitted as a subclass of the domain that overrides the extended commands.
306
+ # A namespaced group of browser-specific commands (e.g. Firefox's), emitted as a subclass of
307
+ # the domain: it overrides the commands a vendor extends with `moz:` fields and adds the
308
+ # commands a vendor defines in the domain (`webExtension.moz:listExtensions`).
285
309
  # A subclass (rather than a runtime-mixed module) keeps the vendor signatures statically
286
310
  # visible to type checkers, and is constructed directly (`<Name>.new(source)`) for a
287
311
  # matching session — no factory or runtime mix-in.
@@ -290,7 +314,7 @@ module BiDiGenerate
290
314
  pad = ' ' * indent
291
315
  lines = [
292
316
  "#{pad}# @api private",
293
- "#{pad}# #{namespace}: vendor variant of #{parent}, overriding commands with browser-specific params.",
317
+ "#{pad}# #{namespace}: vendor variant of #{parent}, with browser-specific commands and params.",
294
318
  "#{pad}# Construct #{name}.new(source) for a matching session; other sessions use #{parent}.",
295
319
  "#{pad}class #{name} < #{parent}"
296
320
  ]
@@ -543,15 +567,44 @@ module BiDiGenerate
543
567
  :vendor_modules, :spec_href, keyword_init: true)
544
568
 
545
569
  class Schema
570
+ # Vendor content (schema `vendor.<namespace>`) is folded in beside the spec's: a vendor
571
+ # module's commands and events become a domain of their own, and its types resolve like
572
+ # spec types and are emitted in that module (see owned_types).
546
573
  def initialize(schema)
547
- @types = schema['types']
548
- @commands = schema['commands']
549
- @events = schema['events']
550
- @domains = schema['domains'] || {}
551
574
  @vendor = schema['vendor'] || {}
575
+ @vendor_types = @vendor.values.map { |section| section['types'] || {} }.reduce({}, :merge)
576
+ @types = schema['types'].merge(@vendor_types)
577
+ @commands = schema['commands'] + vendor_messages('commands').select { |c| vendor_domain?(c['domain']) }
578
+ @events = schema['events'] + vendor_events
579
+ @domains = schema['domains'] || {}
552
580
  promote_command_params_records!
553
581
  end
554
582
 
583
+ # A vendor module's domain keeps its wire prefix (`moz:debugging`); a spec domain has none.
584
+ def vendor_domain?(domain) = domain.include?(':')
585
+
586
+ def vendor_messages(kind)
587
+ @vendor.values.flat_map { |section| section[kind] || [] }
588
+ end
589
+
590
+ # A vendor event in a spec domain would need the same vendor-variant routing as a command;
591
+ # none exists yet, so fail generation rather than leak it into the shared class.
592
+ def vendor_events
593
+ events = vendor_messages('events')
594
+ stray = events.reject { |e| vendor_domain?(e['domain']) }
595
+ raise "vendor event #{stray.first['method']} in spec domain #{stray.first['domain']} is unsupported" if stray.any?
596
+
597
+ events
598
+ end
599
+
600
+ # The commands a vendor defines in a spec domain (`webExtension.moz:listExtensions`). They are
601
+ # emitted on that domain's vendor variant, never on the shared class (see vendor_modules_for).
602
+ def vendor_added_commands(domain, namespace)
603
+ return [] if vendor_domain?(domain)
604
+
605
+ (@vendor.dig(namespace, 'commands') || []).select { |c| c['domain'] == domain }
606
+ end
607
+
555
608
  # The domain's `#module-<domain>` spec link, or nil when the schema has none.
556
609
  def domain_href(domain)
557
610
  @domains.dig(domain, 'specHref')
@@ -627,23 +680,36 @@ module BiDiGenerate
627
680
  # any domain (or schema) with no vendor extensions, so non-vendor output is unaffected.
628
681
  def vendor_modules_for(domain)
629
682
  parent = BiDiGenerate.snake_to_class_name(BiDiGenerate.camel_to_snake(domain))
630
- groups = Hash.new { |h, k| h[k] = [] }
631
- @vendor.each do |namespace, spec|
632
- (spec['extends'] || {}).each do |type_name, entry|
683
+ @vendor.filter_map do |namespace, spec|
684
+ overrides = (spec['extends'] || {}).filter_map do |type_name, entry|
633
685
  cmd = @commands.find { |c| c.dig('params', 'ref') == type_name }
634
- next unless cmd && cmd['domain'] == domain
635
-
636
- groups[namespace] << build_vendor_command(cmd, type_name, entry, namespace)
686
+ build_vendor_command(cmd, type_name, entry, namespace) if cmd && cmd['domain'] == domain
637
687
  end
638
- end
639
- groups.map do |namespace, commands|
688
+ added = vendor_added_commands(domain, namespace).map { |cmd| build_added_command(cmd, namespace, domain) }
689
+ commands = overrides + added
690
+ next if commands.empty?
691
+
640
692
  VendorModule.new(name: BiDiGenerate.snake_to_class_name(namespace), namespace: namespace, parent: parent,
641
693
  commands: commands)
642
694
  end
643
695
  end
644
696
 
697
+ # The vendor variant already scopes the command, so its name drops the namespace (`moz:listExtensions`
698
+ # → list_extensions); a name that would silently override a spec command fails generation instead.
699
+ def build_added_command(cmd, namespace, domain)
700
+ command = BiDiGenerate.build_command(self, cmd.merge('name' => cmd['name'].delete_prefix("#{namespace}:")))
701
+ spec_names = commands_for(domain).map do |c|
702
+ BiDiGenerate.safe_method_name(BiDiGenerate.camel_to_snake(c['name']))
703
+ end
704
+ if spec_names.include?(command.method_name)
705
+ raise "vendor command #{cmd['method']} would override spec command #{domain}.#{command.method_name}"
706
+ end
707
+
708
+ command
709
+ end
710
+
645
711
  def build_vendor_command(cmd, type_name, entry, namespace)
646
- shared = record_params(@types[type_name]['fields'])
712
+ shared = record_params(@types[type_name]['fields'], extensible_record?(type_name))
647
713
  taken = shared.map(&:ruby_name)
648
714
  VendorCommand.new(
649
715
  method_name: BiDiGenerate.safe_method_name(BiDiGenerate.camel_to_snake(cmd['name'])),
@@ -692,23 +758,61 @@ module BiDiGenerate
692
758
  return nil unless type
693
759
 
694
760
  case type['kind']
695
- when 'record' then record_params(type['fields'])
761
+ when 'record' then record_params(type['fields'], extensible_record?(params_ref['ref']))
696
762
  when 'union' then union_params(type, params_ref['ref'])
697
763
  end
698
764
  end
699
765
 
700
766
  # Enum types declared under "<domain>." become nested constant modules.
701
767
  def enums_for(domain)
702
- @types.filter_map do |name, type|
768
+ owned_types(domain).filter_map do |name, type|
703
769
  next unless type['kind'] == 'enum'
704
- next unless name.start_with?("#{domain}.")
705
770
 
706
771
  pairs = type['values'].map { |v| [BiDiGenerate.enum_key(v), v] }
707
- Enum.new(constant_name: BiDiGenerate.screaming_snake(name.sub("#{domain}.", '')), pairs: pairs,
772
+ Enum.new(constant_name: BiDiGenerate.screaming_snake(name.split('.', 2).last), pairs: pairs,
708
773
  primitive: type['primitive'], spec_href: type['specHref'])
709
774
  end
710
775
  end
711
776
 
777
+ # The types a domain's module declares. A spec domain's are the "<domain>." types the spec
778
+ # defines; a vendor's helper types under that prefix are not emitted until a generated
779
+ # command needs them. A vendor module (`moz:debugging`) owns the vendor types its commands
780
+ # and events name (Mozilla prefixes them `mozDebugging.`), read off their params and result refs.
781
+ def owned_types(domain)
782
+ vendor = vendor_domain?(domain)
783
+ prefixes = type_prefixes(domain).map { |prefix| "#{prefix}." }
784
+ added = vendor ? Set.new : vendor_types_reached(domain)
785
+ @types.select do |name, _|
786
+ next false unless prefixes.any? { |p| name.start_with?(p) }
787
+
788
+ @vendor_types.key?(name) ? vendor || added.include?(name) : !vendor
789
+ end
790
+ end
791
+
792
+ # The vendor types a vendor-added command in this spec domain reaches through its params and
793
+ # result, so they are emitted in the domain's module beside the command that returns them.
794
+ def vendor_types_reached(domain)
795
+ commands = @vendor.keys.flat_map { |namespace| vendor_added_commands(domain, namespace) }
796
+ pending = commands.flat_map { |c| [c.dig('params', 'ref'), c.dig('result', 'ref')] }.compact
797
+ reached = Set.new
798
+ until pending.empty?
799
+ name = pending.pop
800
+ next if reached.include?(name) || !@vendor_types.key?(name)
801
+
802
+ reached << name
803
+ pending.concat(plain_refs(@types[name]) + (@types[name]['variants'] || []))
804
+ end
805
+ reached
806
+ end
807
+
808
+ def type_prefixes(domain)
809
+ return [domain] unless vendor_domain?(domain)
810
+
811
+ messages = commands_for(domain) + events_for(domain)
812
+ refs = messages.flat_map { |m| [m.dig('params', 'ref'), m.dig('result', 'ref')] }
813
+ refs.compact.select { |ref| ref.include?('.') }.map { |ref| ref.split('.', 2).first }.uniq
814
+ end
815
+
712
816
  # The protocol-root ErrorCode enum's wire values (e.g. "no such frame"), in schema order.
713
817
  # Used to generate the BiDi-specific Error subclasses. [] when the schema has no ErrorCode.
714
818
  def error_codes
@@ -721,10 +825,7 @@ module BiDiGenerate
721
825
  # Command/event message envelopes (the `{method, params}` wire wrapper) are
722
826
  # skipped — Transport forms that envelope, so nothing references them.
723
827
  def types_for(domain)
724
- prefix = "#{domain}."
725
- @types.filter_map do |name, type|
726
- next unless name.start_with?(prefix)
727
-
828
+ owned_types(domain).filter_map do |name, type|
728
829
  case type['kind']
729
830
  when 'record' then record_class(name, type) unless type['fields'].empty? || suppressed_record?(type)
730
831
  when 'union' then union_class(name)
@@ -926,21 +1027,36 @@ module BiDiGenerate
926
1027
  end
927
1028
 
928
1029
  def record_class(name, type)
1030
+ extensible = extensible_record?(name)
929
1031
  const = type['fields'].find { |f| baked_discriminator?(f) }
930
- discriminator = const && {ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(const['name'])),
1032
+ discriminator = const && {ruby_name: field_name(const, extensible),
931
1033
  wire: const['wire'], value: const['type']['const'],
932
1034
  rbs: rbs_const(const['type']['const'])}
933
- fields = type['fields'].reject { |f| baked_discriminator?(f) }.map { |f| field_ir(f) }
1035
+ fields = type['fields'].reject { |f| baked_discriminator?(f) }.map { |f| field_ir(f, extensible) }
934
1036
  # Every extensible type gets the extensions store: an undeclared wire key is preserved
935
1037
  # and echoed back on any type the spec marks extensible, whether or not it is re-sendable.
936
- # Extensibility alone is the signal; send-reachability does not enter into it.
1038
+ # Extensibility alone is the signal; send-reachability does not enter into it. A type a
1039
+ # vendor extends is open too: its vendor variant composes the vendor fields through that
1040
+ # store (see VendorCommand), which a closed record would reject.
937
1041
  TypeClass.new(ruby_name: BiDiGenerate.type_class_name(name), fields: fields,
938
- discriminator: discriminator, extensible: type['extensible'] ? true : false,
1042
+ discriminator: discriminator, extensible: extensible,
939
1043
  schema_name: name, synthetic: type['synthetic'] ? true : false,
940
1044
  owner: type['owner'], label: type['label'], spec_href: type['specHref'],
941
1045
  **directionality(name))
942
1046
  end
943
1047
 
1048
+ def vendor_extended?(name)
1049
+ @vendor.values.any? { |spec| (spec['extends'] || {}).key?(name) }
1050
+ end
1051
+
1052
+ def extensible_record?(name)
1053
+ @types.dig(name, 'extensible') || vendor_extended?(name) ? true : false
1054
+ end
1055
+
1056
+ def field_name(field, extensible)
1057
+ BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name']), extensible: extensible)
1058
+ end
1059
+
944
1060
  # A const field is a baked discriminator tag, unless it is also nullable: the spec's
945
1061
  # `literal | null` (browsingContext.setBypassCSP, emulation.setScriptingEnabled) is a
946
1062
  # settable value (the literal to set, null to clear), so it stays a normal field that
@@ -949,9 +1065,9 @@ module BiDiGenerate
949
1065
  field['type'].key?('const') && !field['type']['nullable']
950
1066
  end
951
1067
 
952
- def field_ir(field)
1068
+ def field_ir(field, extensible)
953
1069
  resolved = resolve(field['type'])
954
- ruby_name = BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name']))
1070
+ ruby_name = field_name(field, extensible)
955
1071
  FieldIR.new(ruby_name: ruby_name, wire_key: field['wire'],
956
1072
  required: field['required'], nullable: resolved[:nullable],
957
1073
  ref: resolved[:ref], list: resolved[:list], enum: enum_const(field['type']),
@@ -1074,10 +1190,10 @@ module BiDiGenerate
1074
1190
  scalar_values: spec['type']['scalarValues'], **directionality(name))
1075
1191
  end
1076
1192
 
1077
- def record_params(fields)
1193
+ def record_params(fields, extensible)
1078
1194
  fields.map do |field|
1079
1195
  Param.new(
1080
- ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])),
1196
+ ruby_name: field_name(field, extensible),
1081
1197
  wire_name: field['wire'],
1082
1198
  required: field['required'],
1083
1199
  enum: enum_const(field['type']),
@@ -1146,7 +1262,7 @@ module BiDiGenerate
1146
1262
 
1147
1263
  selector = type['selector']
1148
1264
  guard_union_dispatch_keys_simple!(selector, ref)
1149
- params = merged_params(variants.map { |v| v['fields'] })
1265
+ params = merged_params(variants.map { |v| v['fields'] }, type['variants'].any? { |v| extensible_record?(v) })
1150
1266
  annotate_discriminator_enum!(params, selector)
1151
1267
  params
1152
1268
  end
@@ -1180,12 +1296,12 @@ module BiDiGenerate
1180
1296
 
1181
1297
  # Merge variant field lists into one flat param superset. A field is required only
1182
1298
  # when every variant declares it required; variant-specific fields become optional.
1183
- def merged_params(variant_fields)
1299
+ def merged_params(variant_fields, extensible)
1184
1300
  all_fields = variant_fields.flatten
1185
1301
  all_fields.map { |f| f['wire'] }.uniq.map do |wire|
1186
1302
  field = all_fields.find { |f| f['wire'] == wire }
1187
1303
  required = variant_fields.all? { |fields| fields.any? { |f| f['wire'] == wire && f['required'] } }
1188
- Param.new(ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])),
1304
+ Param.new(ruby_name: field_name(field, extensible),
1189
1305
  wire_name: wire, required: required, rbs: rbs_type(field['type']))
1190
1306
  end
1191
1307
  end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -277,6 +277,30 @@ module Selenium
277
277
  @network ||= WebDriver::Network.new(bridge)
278
278
  end
279
279
 
280
+ #
281
+ # Installs a browser extension from an unpacked directory, a packed extension (.xpi/.crx/.zip),
282
+ # or base64-encoded bytes; works with remote (Grid) sessions.
283
+ #
284
+ # @note Chromium requires a BiDi session and installs only unpacked directories
285
+ # (SeleniumHQ/selenium#16541); Firefox falls back to the classic endpoint without BiDi.
286
+ # @param [String] path directory, packed extension, or base64-encoded bytes
287
+ # @return [WebExtension] the installed extension
288
+ #
289
+
290
+ def install_web_extension(...)
291
+ bridge.install_web_extension(...)
292
+ end
293
+
294
+ #
295
+ # Uninstalls a browser extension installed with {#install_web_extension}.
296
+ #
297
+ # @param [WebExtension] extension the extension returned by {#install_web_extension}
298
+ #
299
+
300
+ def uninstall_web_extension(extension)
301
+ bridge.uninstall_web_extension(extension.id)
302
+ end
303
+
280
304
  #-------------------------------- sugar --------------------------------
281
305
 
282
306
  #
@@ -30,6 +30,7 @@ module Selenium
30
30
  #
31
31
 
32
32
  def install_addon(path, temporary = nil)
33
+ WebDriver.logger.deprecate('#install_addon', '#install_web_extension', id: :install_addon)
33
34
  @bridge.install_addon(path, temporary)
34
35
  end
35
36
 
@@ -40,6 +41,7 @@ module Selenium
40
41
  #
41
42
 
42
43
  def uninstall_addon(id)
44
+ WebDriver.logger.deprecate('#uninstall_addon', '#uninstall_web_extension', id: :uninstall_addon)
43
45
  @bridge.uninstall_addon(id)
44
46
  end
45
47
  end # HasAddons
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes