selenium-webdriver 4.48.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 +21 -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 → linux-x86_64}/selenium-manager +0 -0
  9. data/bin/macos/selenium-manager +0 -0
  10. data/bin/selenium-manager-THIRD-PARTY-NOTICES.txt +327 -51
  11. data/bin/selenium-manager.cdx.json +491 -491
  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 +78 -7
  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 +303 -6
  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 +175 -50
  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 +6 -2
  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 +9 -28
  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
@@ -137,14 +146,16 @@ module BiDiGenerate
137
146
  # snake_case hash key for an enum value (only a label for the wire value it maps to).
138
147
  # Preserves camelCase word boundaries (beforeRequestSent → before_request_sent), maps a
139
148
  # leading minus to "neg" (-0 → neg0, -Infinity → neg_infinity; no underscore before a
140
- # digit, so the key stays normalcase), and collapses other punctuation
141
- # (dedicated-worker → dedicated_worker).
149
+ # digit, so the key stays normalcase), collapses other punctuation
150
+ # (dedicated-worker → dedicated_worker), and prefixes a numeric value so the key
151
+ # is still a valid symbol (0 → _0).
142
152
  def self.enum_key(value)
143
- camel_to_snake(value.to_s)
144
- .sub(/\A-(?=\d)/, 'neg')
145
- .sub(/\A-/, 'neg_')
146
- .gsub(/[^a-z0-9]+/, '_')
147
- .gsub(/\A_+|_+\z/, '')
153
+ token = camel_to_snake(value.to_s)
154
+ .sub(/\A-(?=\d)/, 'neg')
155
+ .sub(/\A-/, 'neg_')
156
+ .gsub(/[^a-z0-9]+/, '_')
157
+ .gsub(/\A_+|_+\z/, '')
158
+ token.empty? || token.match?(/\A\d/) ? "_#{token}" : token
148
159
  end
149
160
 
150
161
  # ruby_name is the snake_case keyword argument; wire_name is the exact key the
@@ -224,6 +235,20 @@ module BiDiGenerate
224
235
  args << "result: #{result_ref}" if result_ref
225
236
  BiDiGenerate.wrap_call('execute', args, indent)
226
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
227
252
  end
228
253
 
229
254
  # A browser-specific extension to a command, kept out of the shared class so a
@@ -278,8 +303,9 @@ module BiDiGenerate
278
303
  end
279
304
  end
280
305
 
281
- # A namespaced group of browser-specific command extensions (e.g. Firefox's `moz:`
282
- # 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`).
283
309
  # A subclass (rather than a runtime-mixed module) keeps the vendor signatures statically
284
310
  # visible to type checkers, and is constructed directly (`<Name>.new(source)`) for a
285
311
  # matching session — no factory or runtime mix-in.
@@ -288,7 +314,7 @@ module BiDiGenerate
288
314
  pad = ' ' * indent
289
315
  lines = [
290
316
  "#{pad}# @api private",
291
- "#{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.",
292
318
  "#{pad}# Construct #{name}.new(source) for a matching session; other sessions use #{parent}.",
293
319
  "#{pad}class #{name} < #{parent}"
294
320
  ]
@@ -308,9 +334,16 @@ module BiDiGenerate
308
334
  def type_entry = "'#{wire_name}' => #{payload_ref || 'nil'}"
309
335
  end
310
336
 
311
- # constant_name is the SCREAMING_SNAKE hash name; pairs are [symbol_key, wire_value] tuples.
312
- # spec_href links to the type's definition in the live spec (nil when the schema has none).
313
- Enum = Struct.new(:constant_name, :pairs, :spec_href, keyword_init: true)
337
+ # The RBS type a schema value primitive maps to; an unrecognized one is untyped.
338
+ RBS_VALUE_TYPES = {'string' => 'String', 'integer' => 'Integer', 'number' => 'Float',
339
+ 'boolean' => 'bool'}.freeze
340
+
341
+ # constant_name is the SCREAMING_SNAKE hash name; pairs are [symbol_key, wire_value] tuples;
342
+ # primitive is the schema's declared value type. spec_href links to the type's definition in
343
+ # the live spec (nil when the schema has none).
344
+ Enum = Struct.new(:constant_name, :pairs, :primitive, :spec_href, keyword_init: true) do
345
+ def rbs_value_type = RBS_VALUE_TYPES.fetch(primitive, 'untyped')
346
+ end
314
347
 
315
348
  # The generated Protocol::ErrorCode module (filename 'error_code'): `codes` is the [wire, class_name]
316
349
  # pairs in schema order (the full map); `new_classes` is the subset of class names the classic
@@ -534,15 +567,44 @@ module BiDiGenerate
534
567
  :vendor_modules, :spec_href, keyword_init: true)
535
568
 
536
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).
537
573
  def initialize(schema)
538
- @types = schema['types']
539
- @commands = schema['commands']
540
- @events = schema['events']
541
- @domains = schema['domains'] || {}
542
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'] || {}
543
580
  promote_command_params_records!
544
581
  end
545
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
+
546
608
  # The domain's `#module-<domain>` spec link, or nil when the schema has none.
547
609
  def domain_href(domain)
548
610
  @domains.dig(domain, 'specHref')
@@ -618,23 +680,36 @@ module BiDiGenerate
618
680
  # any domain (or schema) with no vendor extensions, so non-vendor output is unaffected.
619
681
  def vendor_modules_for(domain)
620
682
  parent = BiDiGenerate.snake_to_class_name(BiDiGenerate.camel_to_snake(domain))
621
- groups = Hash.new { |h, k| h[k] = [] }
622
- @vendor.each do |namespace, spec|
623
- (spec['extends'] || {}).each do |type_name, entry|
683
+ @vendor.filter_map do |namespace, spec|
684
+ overrides = (spec['extends'] || {}).filter_map do |type_name, entry|
624
685
  cmd = @commands.find { |c| c.dig('params', 'ref') == type_name }
625
- next unless cmd && cmd['domain'] == domain
626
-
627
- groups[namespace] << build_vendor_command(cmd, type_name, entry, namespace)
686
+ build_vendor_command(cmd, type_name, entry, namespace) if cmd && cmd['domain'] == domain
628
687
  end
629
- end
630
- 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
+
631
692
  VendorModule.new(name: BiDiGenerate.snake_to_class_name(namespace), namespace: namespace, parent: parent,
632
693
  commands: commands)
633
694
  end
634
695
  end
635
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
+
636
711
  def build_vendor_command(cmd, type_name, entry, namespace)
637
- shared = record_params(@types[type_name]['fields'])
712
+ shared = record_params(@types[type_name]['fields'], extensible_record?(type_name))
638
713
  taken = shared.map(&:ruby_name)
639
714
  VendorCommand.new(
640
715
  method_name: BiDiGenerate.safe_method_name(BiDiGenerate.camel_to_snake(cmd['name'])),
@@ -683,21 +758,59 @@ module BiDiGenerate
683
758
  return nil unless type
684
759
 
685
760
  case type['kind']
686
- when 'record' then record_params(type['fields'])
761
+ when 'record' then record_params(type['fields'], extensible_record?(params_ref['ref']))
687
762
  when 'union' then union_params(type, params_ref['ref'])
688
763
  end
689
764
  end
690
765
 
691
766
  # Enum types declared under "<domain>." become nested constant modules.
692
767
  def enums_for(domain)
693
- @types.filter_map do |name, type|
768
+ owned_types(domain).filter_map do |name, type|
694
769
  next unless type['kind'] == 'enum'
695
- next unless name.start_with?("#{domain}.")
696
770
 
697
- pairs = type['values'].map { |v| [BiDiGenerate.enum_key(v), v.to_s] }
698
- Enum.new(constant_name: BiDiGenerate.screaming_snake(name.sub("#{domain}.", '')), pairs: pairs,
699
- spec_href: type['specHref'])
771
+ pairs = type['values'].map { |v| [BiDiGenerate.enum_key(v), v] }
772
+ Enum.new(constant_name: BiDiGenerate.screaming_snake(name.split('.', 2).last), pairs: pairs,
773
+ primitive: type['primitive'], spec_href: type['specHref'])
774
+ end
775
+ end
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'] || []))
700
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
701
814
  end
702
815
 
703
816
  # The protocol-root ErrorCode enum's wire values (e.g. "no such frame"), in schema order.
@@ -712,10 +825,7 @@ module BiDiGenerate
712
825
  # Command/event message envelopes (the `{method, params}` wire wrapper) are
713
826
  # skipped — Transport forms that envelope, so nothing references them.
714
827
  def types_for(domain)
715
- prefix = "#{domain}."
716
- @types.filter_map do |name, type|
717
- next unless name.start_with?(prefix)
718
-
828
+ owned_types(domain).filter_map do |name, type|
719
829
  case type['kind']
720
830
  when 'record' then record_class(name, type) unless type['fields'].empty? || suppressed_record?(type)
721
831
  when 'union' then union_class(name)
@@ -917,21 +1027,36 @@ module BiDiGenerate
917
1027
  end
918
1028
 
919
1029
  def record_class(name, type)
1030
+ extensible = extensible_record?(name)
920
1031
  const = type['fields'].find { |f| baked_discriminator?(f) }
921
- discriminator = const && {ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(const['name'])),
1032
+ discriminator = const && {ruby_name: field_name(const, extensible),
922
1033
  wire: const['wire'], value: const['type']['const'],
923
1034
  rbs: rbs_const(const['type']['const'])}
924
- 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) }
925
1036
  # Every extensible type gets the extensions store: an undeclared wire key is preserved
926
1037
  # and echoed back on any type the spec marks extensible, whether or not it is re-sendable.
927
- # 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.
928
1041
  TypeClass.new(ruby_name: BiDiGenerate.type_class_name(name), fields: fields,
929
- discriminator: discriminator, extensible: type['extensible'] ? true : false,
1042
+ discriminator: discriminator, extensible: extensible,
930
1043
  schema_name: name, synthetic: type['synthetic'] ? true : false,
931
1044
  owner: type['owner'], label: type['label'], spec_href: type['specHref'],
932
1045
  **directionality(name))
933
1046
  end
934
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
+
935
1060
  # A const field is a baked discriminator tag, unless it is also nullable: the spec's
936
1061
  # `literal | null` (browsingContext.setBypassCSP, emulation.setScriptingEnabled) is a
937
1062
  # settable value (the literal to set, null to clear), so it stays a normal field that
@@ -940,9 +1065,9 @@ module BiDiGenerate
940
1065
  field['type'].key?('const') && !field['type']['nullable']
941
1066
  end
942
1067
 
943
- def field_ir(field)
1068
+ def field_ir(field, extensible)
944
1069
  resolved = resolve(field['type'])
945
- ruby_name = BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name']))
1070
+ ruby_name = field_name(field, extensible)
946
1071
  FieldIR.new(ruby_name: ruby_name, wire_key: field['wire'],
947
1072
  required: field['required'], nullable: resolved[:nullable],
948
1073
  ref: resolved[:ref], list: resolved[:list], enum: enum_const(field['type']),
@@ -1065,10 +1190,10 @@ module BiDiGenerate
1065
1190
  scalar_values: spec['type']['scalarValues'], **directionality(name))
1066
1191
  end
1067
1192
 
1068
- def record_params(fields)
1193
+ def record_params(fields, extensible)
1069
1194
  fields.map do |field|
1070
1195
  Param.new(
1071
- ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])),
1196
+ ruby_name: field_name(field, extensible),
1072
1197
  wire_name: field['wire'],
1073
1198
  required: field['required'],
1074
1199
  enum: enum_const(field['type']),
@@ -1137,7 +1262,7 @@ module BiDiGenerate
1137
1262
 
1138
1263
  selector = type['selector']
1139
1264
  guard_union_dispatch_keys_simple!(selector, ref)
1140
- params = merged_params(variants.map { |v| v['fields'] })
1265
+ params = merged_params(variants.map { |v| v['fields'] }, type['variants'].any? { |v| extensible_record?(v) })
1141
1266
  annotate_discriminator_enum!(params, selector)
1142
1267
  params
1143
1268
  end
@@ -1171,12 +1296,12 @@ module BiDiGenerate
1171
1296
 
1172
1297
  # Merge variant field lists into one flat param superset. A field is required only
1173
1298
  # when every variant declares it required; variant-specific fields become optional.
1174
- def merged_params(variant_fields)
1299
+ def merged_params(variant_fields, extensible)
1175
1300
  all_fields = variant_fields.flatten
1176
1301
  all_fields.map { |f| f['wire'] }.uniq.map do |wire|
1177
1302
  field = all_fields.find { |f| f['wire'] == wire }
1178
1303
  required = variant_fields.all? { |fields| fields.any? { |f| f['wire'] == wire && f['required'] } }
1179
- Param.new(ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])),
1304
+ Param.new(ruby_name: field_name(field, extensible),
1180
1305
  wire_name: wire, required: required, rbs: rbs_type(field['type']))
1181
1306
  end
1182
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