Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions javascript/selenium-webdriver/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ js_library(
"common/*.js",
"bidi/*.js",
"bidi/external/*.js",
"bidi/serialization/*.js",
]),
deps = [
":node_modules/@bazel/runfiles",
Expand Down Expand Up @@ -197,7 +198,11 @@ pkg_tar(
)

SMALL_TESTS = [
"test/bidi/domain_test.js",
"test/bidi/index_test.js",
"test/bidi/serialization/record_test.js",
"test/bidi/serialization/union_test.js",
"test/bidi/serialization/wire_contract_test.js",
"test/io/io_test.js",
"test/io/zip_test.js",
"test/lib/bidi_connection_test.js",
Expand Down
37 changes: 37 additions & 0 deletions javascript/selenium-webdriver/bidi/domain.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

export interface EventDescriptor<T> {
readonly method: string
readonly type?: { fromWire(payload: unknown): T }
}

export function event<T>(method: string, type?: { fromWire(payload: unknown): T }): EventDescriptor<T>

/** Internal construction guard — only a generated `Class.create(driver)` passes this. Never use directly. */
export const DOMAIN_TOKEN: unique symbol

export declare class Domain {
protected constructor(bidi: unknown, token: typeof DOMAIN_TOKEN)
protected static connect(driver: unknown): Promise<unknown>
protected send(method: string, params: Record<string, unknown>): Promise<unknown>
addCallback<T>(
descriptor: EventDescriptor<T>,
handler: (params: T) => void,
): Promise<{ id: string; unsubscribe(): Promise<void> }>
removeCallback(subscriptionId: string): Promise<void>
}
76 changes: 76 additions & 0 deletions javascript/selenium-webdriver/bidi/domain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

const { getBidiConnection } = require('../lib/bidi_connection')

// Gates Domain's constructor so `new Network(someRandomThing)` fails loudly
// instead of silently producing a broken instance. A Symbol can't be forged
// or guessed, so this is real runtime enforcement, not just a TS annotation —
// only a generated `Class.create(driver)` (and this package's own tests) may
// pass it. It's exported deliberately, not hidden: the point is to stop
// accidental misuse of the normal `new Network(x)` shape, not to defend
// against someone who deliberately imports and passes this.
const DOMAIN_TOKEN = Symbol('Domain internal construction token — obtained only via Class.create(driver)')

/**
* @param {string} method
* @param {{fromWire(payload: unknown): unknown}} [type] Runtime record/union
* class for the event's params, if the schema declares one. When present,
* addCallback() parses each delivered payload through it before the
* caller's handler runs — inbound wire payloads are validated against
* their resolved type; an event's params is such a payload just as much
* as a command's result is.
* @returns {{method: string, type: ({fromWire(payload: unknown): unknown}|undefined)}}
*/
function event(method, type) {
Comment on lines +37 to +39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. event jsdoc lacks description 📘 Rule violation ✧ Quality

The exported event function's JSDoc contains no free-text summary, and its @returns tag has no
description. This leaves the public API documentation incomplete.
Agent Prompt
## Issue description
Complete the JSDoc for the exported `event` function with a summary and a descriptive `@returns` tag.

## Issue Context
PR Compliance 389257 requires every exported function to have a complete JSDoc block immediately before its declaration.

## Fix Focus Areas
- javascript/selenium-webdriver/bidi/domain.js[29-39]
- javascript/selenium-webdriver/bidi/domain.d.ts[23-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

return { method, type }
}

/** Shared base for every generated BiDi domain class. See domain.d.ts for the typed surface. */
class Domain {
#bidi

constructor(bidi, token) {
if (token !== DOMAIN_TOKEN) {
throw new TypeError(`${new.target.name} must be constructed via ${new.target.name}.create(driver), not \`new\``)
}
this.#bidi = bidi
}

static async connect(driver) {
return getBidiConnection(driver)
}

async send(method, params) {
const response = await this.#bidi.send({ method, params })
if (response?.error !== undefined) {
throw new Error(`${response.error}: ${response.message}`)
}
return response?.result
}

async addCallback(descriptor, handler) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. domain callbacks lack jsdoc 📘 Rule violation ✧ Quality

The exported Domain class adds public addCallback and removeCallback methods without
immediately preceding JSDoc blocks. Their parameters and non-void promise return values are
therefore undocumented.
Agent Prompt
## Issue description
Add complete JSDoc blocks for `Domain.addCallback` and `Domain.removeCallback`, including summaries, typed parameters, and described return values.

## Issue Context
`Domain` is exported through `module.exports`, and both methods are public in its TypeScript declaration.

## Fix Focus Areas
- javascript/selenium-webdriver/bidi/domain.js[66-73]
- javascript/selenium-webdriver/bidi/domain.d.ts[32-36]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

const dispatch = descriptor.type === undefined ? handler : (params) => handler(descriptor.type.fromWire(params))
return this.#bidi.addCallback(descriptor.method, dispatch)
}

async removeCallback(subscriptionId) {
return this.#bidi.removeCallback(subscriptionId)
Comment on lines +66 to +72

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Callback transport methods missing 🐞 Bug ≡ Correctness

Domain.addCallback() and removeCallback() invoke methods that the real BiDi connection does not
implement, so every generated event registration or removal fails with a TypeError. The connection
is an EventEmitter exposing protocol events through on/off, while its subscription methods are
named subscribe and unsubscribe.
Agent Prompt
## Issue description
`Domain.addCallback()` and `removeCallback()` delegate to nonexistent methods on the real BiDi connection, causing event APIs to fail at runtime.

## Issue Context
`getBidiConnection()` returns `bidi/index.js`, which emits events by protocol method name and implements `subscribe()`/`unsubscribe()`, but not `addCallback()`/`removeCallback()`.

## Fix Focus Areas
- javascript/selenium-webdriver/bidi/domain.js[66-72]
- javascript/selenium-webdriver/bidi/index.js[82-105]
- javascript/selenium-webdriver/bidi/index.js[231-312]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}
}

module.exports = { Domain, event, DOMAIN_TOKEN }
23 changes: 23 additions & 0 deletions javascript/selenium-webdriver/bidi/serialization/enum.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

export interface EnumEntry<T extends string> {
readonly values: readonly T[]
includes(value: unknown): value is T
}

export function defineEnum<T extends string>(name: string, values: readonly T[]): EnumEntry<T>
31 changes: 31 additions & 0 deletions javascript/selenium-webdriver/bidi/serialization/enum.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

const { register } = require('./registry')

/**
* @param {string} name Schema type name, e.g. 'network.InterceptPhase'.
* @param {string[]} values
*/
function defineEnum(name, values) {
Comment on lines +20 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. defineenum jsdoc incomplete 📘 Rule violation ✧ Quality

The exported defineEnum function's JSDoc has no free-text description and omits documentation for
its non-void return value. Consumers are not told that the function returns the registered enum
entry.
Agent Prompt
## Issue description
Add a summary and a descriptive typed `@returns` tag to the `defineEnum` JSDoc block.

## Issue Context
The function is exported from the module and returns `entry`, so complete return documentation is required.

## Fix Focus Areas
- javascript/selenium-webdriver/bidi/serialization/enum.js[20-24]
- javascript/selenium-webdriver/bidi/serialization/enum.d.ts[23-23]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

const allowed = new Set(values)
const entry = { kind: 'enum', values, includes: (value) => allowed.has(value) }
register(name, entry)
return entry
}

module.exports = { defineEnum }
58 changes: 58 additions & 0 deletions javascript/selenium-webdriver/bidi/serialization/record.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

// Mirrors bidi_schema.json's type-ref vocabulary (see project_bidi_schema.mjs).
export interface TypeNode {
primitive?: string
const?: unknown
ref?: string
enum?: string[]
list?: TypeNode
map?: TypeNode
union?: TypeNode[]
nullable?: boolean
// Present on an inline union with a bare-scalar arm — the primitive(s) that
// arm accepts (see unionNode() in project_bidi_schema.mjs). Not consumed by
// validateValue yet; declared so embedding a real schema node type-checks.
scalar?: string | string[]
// The exact `const` literals a bare-scalar union arm admits (e.g.
// input.Origin's "viewport"/"pointer") — see unionNode(). Same status as
// `scalar`: not yet consumed by validateValue, declared for the embed.
scalarValues?: unknown[]
}

export interface FieldSpec {
name: string
wire: string
required: boolean
type: TypeNode
}

export interface RecordOptions {
extensible?: boolean
}

export declare class ValidationError extends Error {}

export interface RecordClass<T> {
new (data: T): Readonly<T>
fromWire(payload: unknown): Readonly<T>
}

export function defineRecord<T>(name: string, fields: FieldSpec[], options?: RecordOptions): RecordClass<T>

export function defineAlias(name: string, type: TypeNode): void
Loading
Loading