webdriver-bidi-protocol 0.2.11 → 0.3.1

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.
package/src/index.ts CHANGED
@@ -12,12 +12,21 @@ export * from './gen/main.js';
12
12
  export * from './gen/permissions.js';
13
13
  export * from './gen/web-bluetooth.js';
14
14
 
15
+ export type {CommandMapping} from './gen/mapping.d.ts';
16
+
15
17
  type ExternalSpecCommand<T> = {
16
18
  // id is defined by the main WebDriver BiDi spec and extension specs do
17
19
  // not re-define it. Therefore, it's not part of generated types.
18
20
  id: Bidi.JsUint;
19
21
  } & T;
20
22
 
23
+ export type Result = Bidi.ResultData;
24
+
25
+ export type Command =
26
+ | Bidi.Command
27
+ | ExternalSpecCommand<BidiPermissions.PermissionsCommand>
28
+ | ExternalSpecCommand<BidiBluetooth.BluetoothCommand>;
29
+
21
30
  type ExternalSpecEvent<T> = {
22
31
  // type is defined by the main WebDriver BiDi spec and extension specs do
23
32
  // not re-define it. Therefore, it's not part of generated types.
@@ -25,279 +34,6 @@ type ExternalSpecEvent<T> = {
25
34
  } & T &
26
35
  Bidi.Extensible;
27
36
 
28
- export type Command =
29
- | Bidi.Command
30
- | ExternalSpecCommand<BidiPermissions.PermissionsCommand>
31
- | ExternalSpecCommand<BidiBluetooth.BluetoothCommand>;
32
-
33
37
  export type Event =
34
38
  | Bidi.Event
35
39
  | ExternalSpecEvent<BidiBluetooth.BluetoothEvent>;
36
-
37
- // TODO: is there a way to generate this mapping?
38
- export interface Commands {
39
- 'bluetooth.handleRequestDevicePrompt': {
40
- params: BidiBluetooth.Bluetooth.HandleRequestDevicePromptParameters;
41
- returnType: Bidi.EmptyResult;
42
- };
43
- 'bluetooth.disableSimulation': {
44
- params: BidiBluetooth.Bluetooth.DisableSimulationParameters;
45
- returnType: Bidi.EmptyResult;
46
- };
47
- 'bluetooth.simulateAdapter': {
48
- params: BidiBluetooth.Bluetooth.SimulateAdapterParameters;
49
- returnType: Bidi.EmptyResult;
50
- };
51
- 'bluetooth.simulateAdvertisement': {
52
- params: BidiBluetooth.Bluetooth.SimulateAdvertisementParameters;
53
- returnType: Bidi.EmptyResult;
54
- };
55
- 'bluetooth.simulatePreconnectedPeripheral': {
56
- params: BidiBluetooth.Bluetooth.SimulatePreconnectedPeripheralParameters;
57
- returnType: Bidi.EmptyResult;
58
- };
59
- 'bluetooth.simulateGattDisconnection': {
60
- params: BidiBluetooth.Bluetooth.SimulateGattDisconnectionParameters;
61
- returnType: Bidi.EmptyResult;
62
- };
63
- 'bluetooth.simulateDescriptor': {
64
- params: BidiBluetooth.Bluetooth.SimulateDescriptorParameters;
65
- returnType: Bidi.EmptyResult;
66
- };
67
- 'bluetooth.simulateDescriptorResponse': {
68
- params: BidiBluetooth.Bluetooth.SimulateDescriptorResponseParameters;
69
- returnType: Bidi.EmptyResult;
70
- };
71
-
72
- 'browser.close': {
73
- params: Bidi.EmptyParams;
74
- returnType: Bidi.EmptyResult;
75
- };
76
- 'browser.getgetClientWindows': {
77
- params: Bidi.EmptyParams;
78
- returnType: Bidi.Browser.GetClientWindowsResult;
79
- };
80
- 'browser.createUserContext': {
81
- params: Bidi.EmptyParams;
82
- returnType: Bidi.Browser.CreateUserContextResult;
83
- };
84
- 'browser.getUserContexts': {
85
- params: Bidi.EmptyParams;
86
- returnType: Bidi.Browser.GetUserContextsResult;
87
- };
88
- 'browser.removeUserContext': {
89
- params: {
90
- userContext: Bidi.Browser.UserContext;
91
- };
92
- returnType: Bidi.Browser.RemoveUserContext;
93
- };
94
- 'browser.setClientWindowState': {
95
- params: Bidi.Browser.SetClientWindowStateParameters;
96
- returnType: Bidi.Browser.ClientWindowInfo;
97
- };
98
-
99
- 'browsingContext.activate': {
100
- params: Bidi.BrowsingContext.ActivateParameters;
101
- returnType: Bidi.EmptyResult;
102
- };
103
- 'browsingContext.create': {
104
- params: Bidi.BrowsingContext.CreateParameters;
105
- returnType: Bidi.BrowsingContext.CreateResult;
106
- };
107
- 'browsingContext.close': {
108
- params: Bidi.BrowsingContext.CloseParameters;
109
- returnType: Bidi.EmptyResult;
110
- };
111
- 'browsingContext.getTree': {
112
- params: Bidi.BrowsingContext.GetTreeParameters;
113
- returnType: Bidi.BrowsingContext.GetTreeResult;
114
- };
115
- 'browsingContext.locateNodes': {
116
- params: Bidi.BrowsingContext.LocateNodesParameters;
117
- returnType: Bidi.BrowsingContext.LocateNodesResult;
118
- };
119
- 'browsingContext.navigate': {
120
- params: Bidi.BrowsingContext.NavigateParameters;
121
- returnType: Bidi.BrowsingContext.NavigateResult;
122
- };
123
- 'browsingContext.reload': {
124
- params: Bidi.BrowsingContext.ReloadParameters;
125
- returnType: Bidi.BrowsingContext.NavigateResult;
126
- };
127
- 'browsingContext.print': {
128
- params: Bidi.BrowsingContext.PrintParameters;
129
- returnType: Bidi.BrowsingContext.PrintResult;
130
- };
131
- 'browsingContext.captureScreenshot': {
132
- params: Bidi.BrowsingContext.CaptureScreenshotParameters;
133
- returnType: Bidi.BrowsingContext.CaptureScreenshotResult;
134
- };
135
- 'browsingContext.handleUserPrompt': {
136
- params: Bidi.BrowsingContext.HandleUserPromptParameters;
137
- returnType: Bidi.EmptyResult;
138
- };
139
- 'browsingContext.setViewport': {
140
- params: Bidi.BrowsingContext.SetViewportParameters;
141
- returnType: Bidi.EmptyResult;
142
- };
143
- 'browsingContext.traverseHistory': {
144
- params: Bidi.BrowsingContext.TraverseHistoryParameters;
145
- returnType: Bidi.EmptyResult;
146
- };
147
-
148
- 'emulation.setForcedColorsModeThemeOverride': {
149
- params: Bidi.Emulation.SetForcedColorsModeThemeOverrideParameters;
150
- returnType: Bidi.EmptyResult;
151
- };
152
- 'emulation.setGeolocationOverride': {
153
- params: Bidi.Emulation.SetGeolocationOverrideParameters;
154
- returnType: Bidi.EmptyResult;
155
- };
156
- 'emulation.setLocaleOverride': {
157
- params: Bidi.Emulation.SetLocaleOverrideParameters;
158
- returnType: Bidi.EmptyResult;
159
- };
160
- 'emulation.setScreenOrientationOverride': {
161
- params: Bidi.Emulation.SetScreenOrientationOverrideParameters;
162
- returnType: Bidi.EmptyResult;
163
- };
164
- 'emulation.setTimezoneOverride': {
165
- params: Bidi.Emulation.SetTimezoneOverrideParameters;
166
- returnType: Bidi.EmptyResult;
167
- };
168
- 'emulation.setScriptingEnabled': {
169
- params: Bidi.Emulation.SetScriptingEnabledParameters;
170
- returnType: Bidi.EmptyResult;
171
- };
172
- 'emulation.setUserAgentOverride': {
173
- params: Bidi.Emulation.SetUserAgentOverrideParameters;
174
- returnType: Bidi.EmptyResult;
175
- };
176
-
177
- 'input.performActions': {
178
- params: Bidi.Input.PerformActionsParameters;
179
- returnType: Bidi.EmptyResult;
180
- };
181
- 'input.releaseActions': {
182
- params: Bidi.Input.ReleaseActionsParameters;
183
- returnType: Bidi.EmptyResult;
184
- };
185
- 'input.setFiles': {
186
- params: Bidi.Input.SetFilesParameters;
187
- returnType: Bidi.EmptyResult;
188
- };
189
-
190
- 'permissions.setPermission': {
191
- params: BidiPermissions.Permissions.SetPermissionParameters;
192
- returnType: Bidi.EmptyResult;
193
- };
194
-
195
- 'script.evaluate': {
196
- params: Bidi.Script.EvaluateParameters;
197
- returnType: Bidi.Script.EvaluateResult;
198
- };
199
- 'script.callFunction': {
200
- params: Bidi.Script.CallFunctionParameters;
201
- returnType: Bidi.Script.EvaluateResult;
202
- };
203
- 'script.disown': {
204
- params: Bidi.Script.DisownParameters;
205
- returnType: Bidi.EmptyResult;
206
- };
207
- 'script.addPreloadScript': {
208
- params: Bidi.Script.AddPreloadScriptParameters;
209
- returnType: Bidi.Script.AddPreloadScriptResult;
210
- };
211
- 'script.removePreloadScript': {
212
- params: Bidi.Script.RemovePreloadScriptParameters;
213
- returnType: Bidi.EmptyResult;
214
- };
215
-
216
- 'session.end': {
217
- params: Bidi.EmptyParams;
218
- returnType: Bidi.EmptyResult;
219
- };
220
- 'session.new': {
221
- params: Bidi.Session.NewParameters;
222
- returnType: Bidi.Session.NewResult;
223
- };
224
- 'session.status': {
225
- params: object;
226
- returnType: Bidi.Session.StatusResult;
227
- };
228
- 'session.subscribe': {
229
- params: Bidi.Session.SubscriptionRequest;
230
- returnType: Bidi.EmptyResult;
231
- };
232
- 'session.unsubscribe': {
233
- params: Bidi.Session.SubscriptionRequest;
234
- returnType: Bidi.EmptyResult;
235
- };
236
-
237
- 'storage.deleteCookies': {
238
- params: Bidi.Storage.DeleteCookiesParameters;
239
- returnType: Bidi.Storage.DeleteCookiesResult;
240
- };
241
- 'storage.getCookies': {
242
- params: Bidi.Storage.GetCookiesParameters;
243
- returnType: Bidi.Storage.GetCookiesResult;
244
- };
245
- 'storage.setCookie': {
246
- params: Bidi.Storage.SetCookieParameters;
247
- returnType: Bidi.Storage.SetCookieParameters;
248
- };
249
-
250
- 'network.addDataCollector': {
251
- params: Bidi.Network.AddDataCollectorParameters;
252
- returnType: Bidi.Network.AddDataCollectorResult;
253
- };
254
- 'network.addIntercept': {
255
- params: Bidi.Network.AddInterceptParameters;
256
- returnType: Bidi.Network.AddInterceptResult;
257
- };
258
- 'network.removeIntercept': {
259
- params: Bidi.Network.RemoveInterceptParameters;
260
- returnType: Bidi.EmptyResult;
261
- };
262
- 'network.continueRequest': {
263
- params: Bidi.Network.ContinueRequestParameters;
264
- returnType: Bidi.EmptyResult;
265
- };
266
- 'network.continueWithAuth': {
267
- params: Bidi.Network.ContinueWithAuthParameters;
268
- returnType: Bidi.EmptyResult;
269
- };
270
- 'network.failRequest': {
271
- params: Bidi.Network.FailRequestParameters;
272
- returnType: Bidi.EmptyResult;
273
- };
274
- 'network.provideResponse': {
275
- params: Bidi.Network.ProvideResponseParameters;
276
- returnType: Bidi.EmptyResult;
277
- };
278
- 'network.disownData': {
279
- params: Bidi.Network.DisownDataParameters;
280
- returnType: Bidi.EmptyResult;
281
- };
282
- 'network.getData': {
283
- params: Bidi.Network.GetDataParameters;
284
- returnType: Bidi.Network.GetDataResult;
285
- };
286
- 'network.setCacheBehavior': {
287
- params: Bidi.Network.SetCacheBehaviorParameters;
288
- returnType: Bidi.EmptyResult;
289
- };
290
- 'network.setExtraHeaders': {
291
- params: Bidi.Network.SetExtraHeadersParameters;
292
- returnType: Bidi.EmptyResult;
293
- };
294
-
295
- 'webExtension.install': {
296
- params: Bidi.WebExtension.InstallParameters;
297
- returnType: Bidi.WebExtension.InstallResult;
298
- };
299
- 'webExtension.uninstall': {
300
- params: Bidi.WebExtension.UninstallParameters;
301
- returnType: Bidi.EmptyResult;
302
- };
303
- }
@@ -4,14 +4,14 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {Event, Command, Commands} from '..';
7
+ import {Event, Command, CommandMapping} from '..';
8
8
 
9
9
  function sendCommand(command: Command) {}
10
10
  function handleEvent(event: Event) {}
11
- function sendCommandMultipleArgs<T extends keyof Commands>(
11
+ function sendCommandMultipleArgs<T extends keyof CommandMapping>(
12
12
  method: T,
13
- params: Commands[T]['params'],
14
- ): {result: Commands[T]['returnType']} {
13
+ params: CommandMapping[T]['params'],
14
+ ): {result: CommandMapping[T]['returnType']} {
15
15
  throw new Error('Not implemented');
16
16
  }
17
17
 
package/tools/build.sh CHANGED
@@ -4,6 +4,8 @@
4
4
  # Copyright 2024 Google Inc.
5
5
  # SPDX-License-Identifier: Apache-2.0
6
6
 
7
+ set -e
8
+
7
9
  rm -rf src/gen && mkdir src/gen
8
10
  rm -rf out
9
11
 
@@ -23,6 +25,7 @@ cddlconv specs/web-bluetooth/all.cddl > src/gen/web-bluetooth.ts
23
25
 
24
26
  git submodule deinit --all
25
27
 
28
+ node ./tools/generateCommandMap.ts
26
29
  npx tsc -p tsconfig.json
27
30
  npx tsd
28
- npm run format
31
+ npm run format
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google Inc.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {Project, Type, TypeFormatFlags} from 'ts-morph';
8
+ import * as path from 'path';
9
+ import {
10
+ getResultNameFromMethod,
11
+ getTypeInNamespaceOrThrow,
12
+ type MappingInterface,
13
+ type SpecType,
14
+ } from './utils.ts';
15
+
16
+ const rootDir = path.resolve(import.meta.dirname, '..');
17
+
18
+ const MAIN_SPEC_PREFIX = 'Bidi';
19
+
20
+ const specs: SpecType[] = [
21
+ {
22
+ inputFile: './main.ts',
23
+ commandType: 'CommandData',
24
+ modulePrefix: MAIN_SPEC_PREFIX,
25
+ },
26
+ {
27
+ inputFile: './permissions.ts',
28
+ commandType: 'PermissionsCommand',
29
+ modulePrefix: 'BidiPermissions',
30
+ },
31
+ {
32
+ inputFile: './web-bluetooth.ts',
33
+ commandType: 'BluetoothCommand',
34
+ modulePrefix: 'BidiBluetooth',
35
+ },
36
+ ];
37
+
38
+ const project = new Project({
39
+ tsConfigFilePath: path.resolve(rootDir, 'tsconfig.json'),
40
+ });
41
+ const commandMappingEntries: MappingInterface[] = [];
42
+ for (const spec of specs) {
43
+ const apiIndexFile = project.addSourceFileAtPath(
44
+ path.resolve(rootDir, 'src/gen', spec.inputFile),
45
+ );
46
+
47
+ // Allow other name
48
+ const commandType = apiIndexFile.getTypeAliasOrThrow(spec.commandType);
49
+ const unionType = commandType.getType();
50
+ let types: Type[];
51
+ if (unionType.isUnion()) {
52
+ types = unionType.getUnionTypes();
53
+ } else {
54
+ types = [commandType.getTypeNodeOrThrow().getType()];
55
+ }
56
+
57
+ for (const unionMember of types) {
58
+ const methodProp = unionMember.getProperty('method');
59
+ if (!methodProp) {
60
+ // If not method is found continue.
61
+ // For some reason the Bluetooth spec has Record<string,never>
62
+ // TODO: fix it upstream
63
+ continue;
64
+ }
65
+
66
+ const methodType = methodProp.getTypeAtLocation(commandType);
67
+
68
+ if (!methodType.isStringLiteral()) {
69
+ throw new Error(`Non string found ${methodProp.getName()}`);
70
+ }
71
+
72
+ const methodString = `${methodType.getLiteralValue()}`;
73
+
74
+ const paramsProp = unionMember.getPropertyOrThrow('params');
75
+ const paramsType = paramsProp.getTypeAtLocation(commandType);
76
+
77
+ const paramsTypeString = paramsType.getText(
78
+ commandType,
79
+ TypeFormatFlags.None,
80
+ );
81
+
82
+ let prefix = spec.modulePrefix;
83
+ let expectedResultTypeName = paramsTypeString.replace(
84
+ 'Parameters',
85
+ 'Result',
86
+ );
87
+
88
+ // We need to infer from methods
89
+ // TODO: See if this is needed as a fallback always
90
+ if (paramsTypeString.includes('Extensible')) {
91
+ expectedResultTypeName = getResultNameFromMethod(methodString);
92
+ }
93
+
94
+ try {
95
+ // Usually we get something like `BrowsingContext.GetTreeResult`
96
+ getTypeInNamespaceOrThrow(apiIndexFile, expectedResultTypeName);
97
+ } catch {
98
+ try {
99
+ // Maybe it was not inside an Namespace try on the module scope
100
+ apiIndexFile.getTypeAliasOrThrow(expectedResultTypeName);
101
+ } catch {
102
+ // The EmptyResult is only available on the main spec
103
+ prefix = MAIN_SPEC_PREFIX;
104
+ // Default to EmptyResult
105
+ expectedResultTypeName = `EmptyResult`;
106
+ }
107
+ }
108
+
109
+ commandMappingEntries.push({
110
+ method: methodString,
111
+ params: `${spec.modulePrefix}.${paramsTypeString}`,
112
+ resultType: `${prefix}.${expectedResultTypeName}`,
113
+ });
114
+ }
115
+ }
116
+
117
+ // Start generating the mapping types
118
+ const outputPath = path.resolve(rootDir, 'src/gen/mapping.ts');
119
+ const generatedFile = project.createSourceFile(outputPath, '', {
120
+ overwrite: true,
121
+ });
122
+
123
+ for (const spec of specs) {
124
+ generatedFile.addImportDeclaration({
125
+ moduleSpecifier: spec.inputFile,
126
+ isTypeOnly: true,
127
+ namespaceImport: spec.modulePrefix,
128
+ });
129
+ }
130
+
131
+ const mapInterface = generatedFile.addInterface({
132
+ name: 'CommandMapping',
133
+ isExported: true,
134
+ });
135
+
136
+ const sortedCommandMappingEntries = commandMappingEntries.sort((a, b) => {
137
+ if (a.method > b.method) {
138
+ return 1;
139
+ } else if (a.method < b.method) {
140
+ return -1;
141
+ }
142
+
143
+ return 0;
144
+ });
145
+
146
+ for (const entry of sortedCommandMappingEntries) {
147
+ mapInterface.addProperty({
148
+ // Wrap in quotes as we use <module>.<command-name>
149
+ // syntax
150
+ name: `"${entry.method}"`,
151
+ type: writer => {
152
+ writer.write(`
153
+ {
154
+ params: ${entry.params};
155
+ returnType: ${entry.resultType};
156
+ }
157
+ `);
158
+ },
159
+ });
160
+ }
161
+
162
+ await generatedFile.save();
package/tools/utils.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google Inc.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import type {
8
+ ModuleDeclaration,
9
+ SourceFile,
10
+ TypeAliasDeclaration,
11
+ } from 'ts-morph';
12
+
13
+ export function getNamespaces(file: SourceFile, s: String) {
14
+ const result: ModuleDeclaration[] = [];
15
+ for (const n of file.getModules()) {
16
+ if (n.getDeclarationKind() === 'namespace') {
17
+ if (s === n.getName()) {
18
+ result.push(n);
19
+ }
20
+ }
21
+ }
22
+ return result;
23
+ }
24
+
25
+ export interface SpecType {
26
+ inputFile: string;
27
+ commandType: string;
28
+ modulePrefix: string;
29
+ }
30
+ export interface MappingInterface {
31
+ method: string;
32
+ params: string;
33
+ resultType: string;
34
+ }
35
+
36
+ export function getTypeInNamespaceOrThrow(
37
+ file: SourceFile,
38
+ typeWithNamespace: String,
39
+ ): TypeAliasDeclaration {
40
+ const [namespaceName, typeName] = typeWithNamespace.split('.') as [
41
+ string,
42
+ string,
43
+ ];
44
+
45
+ for (const namespace of getNamespaces(file, namespaceName)) {
46
+ const type = namespace.getTypeAlias(typeName);
47
+
48
+ if (type) {
49
+ return type;
50
+ }
51
+ }
52
+
53
+ throw new Error('Not found');
54
+ }
55
+
56
+ export function getResultNameFromMethod(method: string) {
57
+ const type = method
58
+ .split('.')
59
+ .map(s => s.charAt(0).toUpperCase() + s.slice(1))
60
+ .join('.');
61
+ return `${type}Result`;
62
+ }