Class: BiDiGenerate::Schema Private
| Relationships & Source Files | |
| Inherits: | Object |
| Defined in: | rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb |
Constant Summary
-
CHECKABLE_PRIMITIVES =
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 775
The scalar primitives that carry an inbound type-check. A field with no primitive (a ref, const, or opaque value) gets no descriptor and is left unchecked — lenient, so a missed check fails open rather than a wrong strict default rejecting valid data.
%w[string number integer boolean].freeze
-
OPAQUE =
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 536
Resolution for anything not modeled as a value type (scalar, enum, empty record). Frozen because it is shared across callers.
{ref: nil, list: false, rbs: 'untyped'}.freeze -
PRIMITIVE_RBS =
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 768
Every primitive the projector can emit maps to an RBS type.
unknownis intentionally absent — the projector rejects it (an unhandled CDDL construct fails the build), so it never reaches here; any other unlisted primitive fails generation at scalar_rbs rather than slipping through as untyped.{ 'string' => 'String', 'number' => 'Numeric', 'integer' => 'Integer', 'boolean' => 'bool', 'null' => 'nil' }.freeze
Class Method Summary
- .new(schema) ⇒ Schema constructor Internal use only
Instance Method Summary
- #commands_for(domain) Internal use only
-
#domain_href(domain)
Internal use only
The domain's
#module-spec link, or nil when the schema has none. -
#domains
Internal use only
Domains that carry a command or event each become one generated module.
-
#enums_for(domain)
Internal use only
Enumtypes declared under "." become nested constant modules. -
#envelope_synthetic?(type) ⇒ Boolean
Internal use only
A synthetic record lifted out as an envelope's params (its owner is an envelope).
- #events_for(domain) Internal use only
-
#message_envelope?(type) ⇒ Boolean
Internal use only
A protocol message envelope is a record with a baked
methoddiscriminator ({method: <const>, params: …}) — the wire shape of a command/event message. -
#params_for(params_ref)
Internal use only
Flat params for a command: the record's fields, or — for a union of records — the merged superset of variant fields.
-
#promote_command_params_records!
Internal use only
A command written in CDDL map form carries its params as an inline object (rather than the usual group form referencing a named params type).
-
#promote_to_domain_type!(name)
Internal use only
Strip the synthetic/owner/label tags so a lifted-out type emits as a top-level domain record instead of nesting under its (suppressed) envelope.
-
#structured_ref(name)
Internal use only
The Protocol-relative class path a command result parses into, or nil when it is non-structured (or a bare list, returned raw).
-
#suppressed_record?(type) ⇒ Boolean
Internal use only
Records the generator deliberately does not emit: a message envelope, or a synthetic params record lifted out of one.
- #type_kind(ref) Internal use only
-
#types_for(domain)
Internal use only
Structured value classes (records + discriminated unions) declared under "
." Empty records are projector artifacts with nothing to carry, so they stay opaque hashes; only non-empty records and unions become classes. -
#annotate_discriminator_enum!(params, selector)
private
Internal use only
A discriminated union's
byfield is validated against the whole allowed set: the const values that tag each variant plus the default variant's own enum values (e.g. continueWithAuth.action =provideCredentials+cancel). -
#baked_discriminator?(field) ⇒ Boolean
private
Internal use only
A const field is a baked discriminator tag, unless it is also nullable: the spec's
literal | null(browsingContext.setBypassCSP, emulation.setScriptingEnabled) is a settable value (the literal to set, null to clear), so it stays a normal field that can serialize null rather than a fixed tag that can only ever emit the literal. - #default_variant_enum_values(selector, by) private Internal use only
- #discriminated_variants(selector) private Internal use only
- #domain_path(name) private Internal use only
-
#enum_const(field_type)
private
Internal use only
The allowed-values constant path when a field (or a list's element) is an enum type, else nil.
- #field_ir(field) private Internal use only
-
#guard_union_dispatch_keys_simple!(selector, ref)
private
Internal use only
Union.buildmatches the command's kwargs to the selector's dispatch keys by symbol, which holds only while each dispatch wire key equals its ruby kwarg. -
#leaf_primitive(node, seen = {})
private
Internal use only
The runtime-checkable scalar primitive of a field, following alias chains so a scalar hidden behind a named alias (js-uint -> integer, browsingContext.BrowsingContext -> string) is typed rather than opaque.
-
#merged_params(variant_fields)
private
Internal use only
Merge variant field lists into one flat param superset.
-
#named_type(name)
private
Internal use only
A named structured type's serialization ref (nil for a dotless/global type, never emitted as a class) and its absolute RBS class path, derived independently so each output keeps its own treatment of dotless names.
- #nilable(type, flag) private Internal use only
- #ordered_variants(selector) private Internal use only
- #rbs_abs(path) private Internal use only
- #rbs_const(value) private Internal use only
- #rbs_type(node) private Internal use only
- #record_class(name, type) private Internal use only
- #record_params(fields) private Internal use only
-
#resolve(node)
private
Internal use only
Projects a schema type node to
list:, nullable:, rbs:. -
#resolve_named(name, seen = {})
private
Internal use only
Resolves a named ref to the same
list:, rbs:facts, transparently following aliases — including alias-to-list — so an element type behind an alias (e.g. script.ListLocalValue -> [script.LocalValue]) is preserved. - #resolve_named_alias(name, inner, seen) private Internal use only
-
#resolve_union(node, nullable)
private
Internal use only
An inline union of one union-typed arm plus scalars (e.g. a MappingRemoteValue entry, RemoteValue / string) is carried as that union ref so nested entries are typed.
-
#ruby_path(name)
private
Internal use only
Class path, nesting a synthetic type under its owner as
Owner::Labelso a ref resolves to the same nested constant the type is emitted as. -
#scalar_rbs(node)
private
Internal use only
The leaf of #resolve: the bare scalar type, before any nullable wrap.
- #union_class(name) private Internal use only
-
#union_from_alias(name)
private
Internal use only
The sole alias-union is input.Origin ("viewport" | "pointer" | ElementOrigin): a scalar-or-object union the object-payload selector model doesn't cover, so the projector leaves it an alias with no selector.
-
#union_from_selector(name, selector)
private
Internal use only
Map a union
selectorto dispatch variants the template renders: -
#union_params(type, ref = nil)
private
Internal use only
Merge a union's record variants into one flat param list for the command signature.
-
#union_ref?(name) ⇒ Boolean
private
Internal use only
True when a ref (following aliases) is a union — the only arm whose from_json tolerates a scalar sibling.
Constructor Details
.new(schema) ⇒ Schema
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 387
def initialize(schema) @types = schema['types'] @commands = schema['commands'] @events = schema['events'] @domains = schema['domains'] || {} promote_command_params_records! end
Instance Method Details
#annotate_discriminator_enum!(params, selector) (private)
A discriminated union's by field is validated against the whole allowed set:
the const values that tag each variant plus the default variant's own enum
values (e.g. continueWithAuth.action = provideCredentials + cancel).
That spans variants, so no single enum constant fits — emit an inline symbol=>wire
hash so the check accepts the idiomatic symbol like every other enum.
Boolean discriminators (handleRequestDevicePrompt.accept) need no membership check.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 831
def annotate_discriminator_enum!(params, selector) by = selector['by'] tagged = by ? selector['variants'].map { |v| v['value'] } : [] return unless !tagged.empty? && tagged.all?(String) allowed = (tagged + default_variant_enum_values(selector, by)).uniq pairs = allowed.map { |v| "#{BiDiGenerate.enum_key(v)}: '#{v}'" } param = params.find { |p| p.wire_name == by } return unless param param.enum = "{#{pairs.join(', ')}}" param.rbs = 'Symbol' end
#baked_discriminator?(field) ⇒ Boolean (private)
A const field is a baked discriminator tag, unless it is also nullable: the spec's
literal | null (browsingContext.setBypassCSP, emulation.setScriptingEnabled) is a
settable value (the literal to set, null to clear), so it stays a normal field that
can serialize null rather than a fixed tag that can only ever emit the literal.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 647
def baked_discriminator?(field) field['type'].key?('const') && !field['type']['nullable'] end
#commands_for(domain)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 432
def commands_for(domain) @commands.select { |c| c['domain'] == domain } end
#default_variant_enum_values(selector, by) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 845
def default_variant_enum_values(selector, by) default = selector['default'] field = default && @types[default]['fields'].find { |f| f['wire'] == by } ref = field && field['type']['ref'] ref && @types[ref] && @types[ref]['kind'] == 'enum' ? @types[ref]['values'] : [] end
#discriminated_variants(selector) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 712
def discriminated_variants(selector) variants = selector['variants'].map do |variant| VariantIR.new(mode: :value, value: variant['value'], ref: ruby_path(variant['ref']), requires: nil) end return variants unless selector['default'] variants << VariantIR.new(mode: :fallback, value: nil, ref: ruby_path(selector['default']), requires: nil) end
#domain_href(domain)
The domain's #module- spec link, or nil when the schema has none.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 396
def domain_href(domain) @domains.dig(domain, 'specHref') end
#domain_path(name) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 521
def domain_path(name) name.include?('.') ? ruby_path(name) : nil end
#domains
Domains that carry a command or event each become one generated module.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 428
def domains (@commands + @events).map { |entry| entry['domain'] }.uniq end
#enum_const(field_type) (private)
The allowed-values constant path when a field (or a list's element) is an enum type, else nil. Union command-params skip this (their merged superset can blur a discriminator's const vs enum); only flat record params get the outbound check.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 802
def enum_const(field_type) ref = field_type['ref'] || field_type.dig('list', 'ref') return unless ref && @types[ref] && @types[ref]['kind'] == 'enum' BiDiGenerate.enum_const_path(ref) end
#enums_for(domain)
Enum types declared under "
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 461
def enums_for(domain) @types.filter_map do |name, type| next unless type['kind'] == 'enum' next unless name.start_with?("#{domain}.") pairs = type['values'].map { |v| [BiDiGenerate.enum_key(v), v.to_s] } Enum.new(constant_name: BiDiGenerate.screaming_snake(name.sub("#{domain}.", '')), pairs: pairs, spec_href: type['specHref']) end end
#envelope_synthetic?(type) ⇒ Boolean
A synthetic record lifted out as an envelope's params (its owner is an envelope).
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 505
def envelope_synthetic?(type) return false unless type['synthetic'] owner = @types[type['owner']] owner && owner['kind'] == 'record' && (owner) end
#events_for(domain)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 440
def events_for(domain) @events.select { |e| e['domain'] == domain } end
#field_ir(field) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 651
def field_ir(field) resolved = resolve(field['type']) ruby_name = BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])) FieldIR.new(ruby_name: ruby_name, wire_key: field['wire'], required: field['required'], nullable: resolved[:nullable], ref: resolved[:ref], list: resolved[:list], enum: enum_const(field['type']), primitive: leaf_primitive(field['type']), scalar: resolved[:scalar], rbs: resolved[:rbs]) end
#guard_union_dispatch_keys_simple!(selector, ref) (private)
Union.build matches the command's kwargs to the selector's dispatch keys by
symbol, which holds only while each dispatch wire key equals its ruby kwarg.
Every current key is a single lowercase word; fail generation if a new one is
camelCase so the outbound dispatch gets an explicit wire<->ruby mapping then.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 868
def guard_union_dispatch_keys_simple!(selector, ref) keys = selector['by'] ? [selector['by']] : (selector['ordered'] || []).flat_map { |arm| arm['requires'] } camel = keys.reject { |k| BiDiGenerate.camel_to_snake(k) == k } return if camel.empty? raise "union command param #{ref} dispatches on non-snake wire key(s) #{camel.inspect}; " \ 'Union.build matches kwargs to dispatch keys by symbol, so give the outbound ' \ 'dispatch an explicit wire<->ruby mapping before shipping this.' end
#leaf_primitive(node, seen = {}) (private)
The runtime-checkable scalar primitive of a field, following alias chains so a scalar hidden behind a named alias (js-uint -> integer, browsingContext.BrowsingContext -> string) is typed rather than opaque. The projector carries the primitive on the alias node; this surfaces it onto the field. Nil for a list (its elements are not scalar-checked), a record/union ref, an enum, a const, or an opaque value.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 666
def leaf_primitive(node, seen = {}) return node['primitive'] if node.key?('primitive') && CHECKABLE_PRIMITIVES.include?(node['primitive']) return nil unless node.key?('ref') name = node['ref'] type = @types[name] return nil if seen[name] || type.nil? || type['kind'] != 'alias' seen[name] = true leaf_primitive(type['type'], seen) end
#merged_params(variant_fields) (private)
Merge variant field lists into one flat param superset. A field is required only when every variant declares it required; variant-specific fields become optional.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 854
def merged_params(variant_fields) all_fields = variant_fields.flatten all_fields.map { |f| f['wire'] }.uniq.map do |wire| field = all_fields.find { |f| f['wire'] == wire } required = variant_fields.all? { |fields| fields.any? { |f| f['wire'] == wire && f['required'] } } Param.new(ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])), wire_name: wire, required: required, rbs: rbs_type(field['type'])) end end
#message_envelope?(type) ⇒ Boolean
A protocol message envelope is a record with a baked method discriminator
({method: <const>, params: …}) — the wire shape of a command/event message.
No value type carries a const method field, so this is unambiguous.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 500
def (type) type['fields'].any? { |f| f['wire'] == 'method' && f['type'].key?('const') } end
#named_type(name) (private)
A named structured type's serialization ref (nil for a dotless/global type, never emitted as a class) and its absolute RBS class path, derived independently so each output keeps its own treatment of dotless names.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 608
def named_type(name) {ref: domain_path(name), list: false, rbs: rbs_abs(ruby_path(name))} end
#nilable(type, flag) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 624
def nilable(type, flag) flag ? BiDiGenerate.rbs_nilable(type) : type end
#ordered_variants(selector) (private)
[ GitHub ]#params_for(params_ref)
Flat params for a command: the record's fields, or — for a union of records — the merged superset of variant fields. Returns [] for commands with no params, or nil when params can't be flattened (alias, or a union whose variants aren't all records) so the caller forwards verbatim.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 448
def params_for(params_ref) return [] unless params_ref type = @types[params_ref['ref']] return nil unless type case type['kind'] when 'record' then record_params(type['fields']) when 'union' then union_params(type, params_ref['ref']) end end
#promote_command_params_records!
A command written in CDDL map form carries its params as an inline object (rather
than the usual group form referencing a named params type). The projector links the
command to those params, but hoists them into a synthetic record owned by the
command's message envelope. That envelope is suppressed (Transport forms it), so the
synthetic params record would never be emitted even though the command's params ref
points straight at it. Promote it to a top-level domain record so the generator emits
and references it like any other params type. Today this is exactly
userAgentClientHints.setClientHintsOverride.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 408
def promote_command_params_records! @commands.each do |cmd| ref = cmd.dig('params', 'ref') next unless ref type = @types[ref] promote_to_domain_type!(ref) if type && envelope_synthetic?(type) end end
#promote_to_domain_type!(name)
Strip the synthetic/owner/label tags so a lifted-out type emits as a top-level domain record instead of nesting under its (suppressed) envelope.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 420
def promote_to_domain_type!(name) type = @types[name] type&.delete('synthetic') type&.delete('owner') type&.delete('label') end
#rbs_abs(path) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 795
def rbs_abs(path) "::Selenium::WebDriver::BiDi::Protocol::#{path}" end
#rbs_const(value) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 786
def rbs_const(value) case value when true, false then 'bool' when ::String then 'String' when ::Numeric then 'Numeric' else 'untyped' end end
#rbs_type(node) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 760
def rbs_type(node) resolve(node)[:rbs] end
#record_class(name, type) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 628
def record_class(name, type) const = type['fields'].find { |f| baked_discriminator?(f) } discriminator = const && {ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(const['name'])), wire: const['wire'], value: const['type']['const'], rbs: rbs_const(const['type']['const'])} fields = type['fields'].reject { |f| baked_discriminator?(f) }.map { |f| field_ir(f) } # Gate the extensions store on `preserveExtras` (extensible AND re-sendable), not raw # `extensible`: only a type you receive and can hand back keeps unknown wire keys. A # received-only extensible type gets no store, so its unknown keys are silently ignored. TypeClass.new(ruby_name: BiDiGenerate.type_class_name(name), fields: fields, discriminator: discriminator, extensible: type['preserveExtras'] ? true : false, schema_name: name, synthetic: type['synthetic'] ? true : false, owner: type['owner'], label: type['label'], spec_href: type['specHref']) end
#record_params(fields) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 748
def record_params(fields) fields.map do |field| Param.new( ruby_name: BiDiGenerate.safe_field_name(BiDiGenerate.camel_to_snake(field['name'])), wire_name: field['wire'], required: field['required'], enum: enum_const(field['type']), rbs: rbs_type(field['type']) ) end end
#resolve(node) (private)
Projects a schema type node to list:, nullable:, rbs:. Deriving the
serialization facts and the RBS signature from one walk keeps them from drifting
apart when the schema shape changes.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 541
def resolve(node) nullable = node['nullable'] ? true : false if node.key?('list') element = resolve(node['list']) return {ref: element[:ref], list: true, nullable: nullable, scalar: element[:scalar], rbs: nilable("Array[#{element[:rbs]}]", nullable)} end if node.key?('ref') named = resolve_named(node['ref']) return {ref: named[:ref], list: named[:list], nullable: nullable, scalar: named[:scalar], rbs: nilable(named[:rbs], nullable)} end return resolve_union(node, nullable) if node.key?('union') {ref: nil, list: false, nullable: nullable, rbs: nilable(scalar_rbs(node), nullable)} end
#resolve_named(name, seen = {}) (private)
Resolves a named ref to the same list:, rbs: facts, transparently
following aliases — including alias-to-list — so an element type behind an alias
(e.g. script.ListLocalValue -> [script.LocalValue]) is preserved. Nullability is a
property of the referencing node (applied by #resolve), so it is not threaded
here. seen guards against cyclic ref-aliases.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 589
def resolve_named(name, seen = {}) return OPAQUE if name.nil? || seen[name] seen[name] = true type = @types[name] return OPAQUE unless type case type['kind'] when 'record' then type['fields'].empty? ? OPAQUE : named_type(name) when 'union' then named_type(name) when 'enum' then {ref: nil, list: false, rbs: 'Symbol'} when 'alias' then resolve_named_alias(name, type['type'], seen) else OPAQUE end end
#resolve_named_alias(name, inner, seen) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 612
def resolve_named_alias(name, inner, seen) return named_type(name) if inner.key?('union') return resolve_named(inner['ref'], seen) if inner.key?('ref') if inner.key?('list') element = resolve(inner['list']) return {ref: element[:ref], list: true, scalar: element[:scalar], rbs: "Array[#{element[:rbs]}]"} end {ref: nil, list: false, rbs: scalar_rbs(inner)} end
#resolve_union(node, nullable) (private)
An inline union of one union-typed arm plus scalars (e.g. a MappingRemoteValue entry,
RemoteValue / string) is carried as that union ref so nested entries are typed. Because
the union is object_only, a bare-scalar sibling would raise there — so the projector's
scalar signal (a bare-scalar arm is present) is forwarded, and the runtime passes a
non-object leaf through instead (the map's string keys). Any other shape (a record arm,
multiple structured arms, all scalars) stays opaque.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 564
def resolve_union(node, nullable) refs = node['union'].select { |arm| arm.key?('ref') } opaque = {ref: nil, list: false, nullable: nullable, rbs: nilable('untyped', nullable)} return opaque unless refs.one? && union_ref?(refs.first['ref']) named = resolve_named(refs.first['ref']) {ref: named[:ref], list: named[:list], nullable: nullable, scalar: node['scalar'], rbs: nilable('untyped', nullable)} end
#ruby_path(name) (private)
Class path, nesting a synthetic type under its owner as Owner::Label so a ref
resolves to the same nested constant the type is emitted as.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 527
def ruby_path(name) type = @types[name] return BiDiGenerate.type_ruby_path(name) unless type && type['synthetic'] "#{ruby_path(type['owner'])}::#{type['label']}" end
#scalar_rbs(node) (private)
The leaf of #resolve: the bare scalar type, before any nullable wrap. An alias's own nullable is intentionally left off — only the referencing node's is applied.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 779
def scalar_rbs(node) return PRIMITIVE_RBS.fetch(node['primitive']) if node.key?('primitive') return rbs_const(node['const']) if node.key?('const') 'untyped' end
#structured_ref(name)
The Protocol-relative class path a command result parses into, or nil when it is non-structured (or a bare list, returned raw).
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 514
def structured_ref(name) resolved = resolve_named(name) resolved[:list] ? nil : resolved[:ref] end
#suppressed_record?(type) ⇒ Boolean
Records the generator deliberately does not emit: a message envelope, or a synthetic params record lifted out of one. Both are reachable only through the envelope, which Transport replaces — so nothing else references them.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 493
def suppressed_record?(type) (type) || envelope_synthetic?(type) end
#type_kind(ref)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 436
def type_kind(ref) @types[ref]&.fetch('kind', nil) end
#types_for(domain)
Structured value classes (records + discriminated unions) declared under
"{method, params} wire wrapper) are
skipped — Transport forms that envelope, so nothing references them.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 477
def types_for(domain) prefix = "#{domain}." @types.filter_map do |name, type| next unless name.start_with?(prefix) case type['kind'] when 'record' then record_class(name, type) unless type['fields'].empty? || suppressed_record?(type) when 'union' then union_class(name) when 'alias' then union_class(name) if type['type'].key?('union') end end end
#union_class(name) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 678
def union_class(name) type = @types[name] # A first-class union carries the schema's authoritative dispatch `selector` # (derived spec-faithfully, including null discriminators and the spec's choice # order); consume it rather than re-deriving and silently depending on emit # order. An alias-to-union (only input.Origin) has no selector — its const-string # arms aren't first-class types — so it keeps the structural re-derivation. type['kind'] == 'union' ? union_from_selector(name, type['selector']) : union_from_alias(name) end
#union_from_alias(name) (private)
The sole alias-union is input.Origin ("viewport" | "pointer" | ElementOrigin): a scalar-or-object union the object-payload selector model doesn't cover, so the projector leaves it an alias with no selector. Its object arm(s) carry a const discriminator; the bare-string arms need no dispatch (Union.from_json returns a non-Hash payload unchanged). So dispatch the ref arms by their const tag.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 732
def union_from_alias(name) consts = @types[name]['type']['union'].filter_map { |arm| arm['ref'] }.to_h do |ref| const = @types[ref]['fields'].find { |f| f['type'].key?('const') } const || raise("alias-union #{name} arm #{ref} has no const discriminator to dispatch on") [ref, const] end variants = consts.map do |ref, const| VariantIR.new(mode: :value, value: const['type']['const'], ref: ruby_path(ref), requires: nil) end # An alias-union carries bare-scalar arms (input.Origin's "viewport"/"pointer"), so it # is never object_only — those arms must still pass a non-Hash payload through. UnionClass.new(ruby_name: BiDiGenerate.type_class_name(name), discriminator_wire: consts.values.first['wire'], variants: variants, schema_name: name, spec_href: @types[name]['specHref'], object_only: @types[name]['objectOnly'] ? true : false) end
#union_from_selector(name, selector) (private)
Map a union selector to dispatch variants the template renders:
{ by, variants, default? } -> a discriminator table (value => ref), {default}
as the fallback (it may itself be a union, which finishes the dispatch).
{ ordered: [{ ref, requires }] } -> presence rules in the spec's choice order.
{ correlated: true } -> resolved by request id, not the payload, so no payload
dispatch. Unreachable here: every correlated union is a top-level result
grouping, never domain-scoped, so it is never emitted as a class.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 695
def union_from_selector(name, selector) # A correlated union is resolved by request id, never the payload, so it carries # no dispatch — it must never be emitted (every one is a top-level result # grouping). Fail loudly if a future schema makes one domain-scoped rather than # emit a Union whose every parse would raise. if selector['correlated'] raise "correlated union #{name} must not be emitted (resolved by request id, not payload)" end variants = selector['by'] ? discriminated_variants(selector) : ordered_variants(selector) raise "union #{name} selector yielded no dispatch variants" if variants.empty? UnionClass.new(ruby_name: BiDiGenerate.type_class_name(name), discriminator_wire: selector['by'], variants: variants, schema_name: name, spec_href: @types[name]['specHref'], object_only: @types[name]['objectOnly'] ? true : false) end
#union_params(type, ref = nil) (private)
Merge a union's record variants into one flat param list for the command
signature. A field is only required when every variant declares it required;
variant-specific fields become optional. The command body dispatches these
kwargs to the matching variant via Union.build, whose typed as_json handles
null-vs-absent — so no nullable allowlist is needed.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 814
def union_params(type, ref = nil) variants = type['variants'].map { |variant_ref| @types[variant_ref] } return nil unless variants.all? { |v| v && v['kind'] == 'record' } selector = type['selector'] guard_union_dispatch_keys_simple!(selector, ref) params = merged_params(variants.map { |v| v['fields'] }) annotate_discriminator_enum!(params, selector) params end
#union_ref?(name) ⇒ Boolean (private)
True when a ref (following aliases) is a union — the only arm whose from_json tolerates a scalar sibling. A record arm would raise on one, so it is not carried.
# File 'rb/lib/selenium/webdriver/bidi/support/bidi_generate.rb', line 576
def union_ref?(name) type = @types[name] return false unless type return union_ref?(type['type']['ref']) if type['kind'] == 'alias' && type['type'].key?('ref') type['kind'] == 'union' end