appium-remote-debugger 15.2.12 → 15.2.14

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 (58) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/lib/atoms.d.ts +16 -10
  3. package/build/lib/atoms.d.ts.map +1 -1
  4. package/build/lib/atoms.js +27 -16
  5. package/build/lib/atoms.js.map +1 -1
  6. package/build/lib/logger.d.ts +1 -2
  7. package/build/lib/logger.d.ts.map +1 -1
  8. package/build/lib/logger.js +2 -2
  9. package/build/lib/logger.js.map +1 -1
  10. package/build/lib/protocol/index.d.ts +13 -8
  11. package/build/lib/protocol/index.d.ts.map +1 -1
  12. package/build/lib/protocol/index.js +17 -12
  13. package/build/lib/protocol/index.js.map +1 -1
  14. package/build/lib/remote-debugger.js +2 -2
  15. package/build/lib/remote-debugger.js.map +1 -1
  16. package/build/lib/rpc/index.d.ts +2 -3
  17. package/build/lib/rpc/index.d.ts.map +1 -1
  18. package/build/lib/rpc/index.js +2 -2
  19. package/build/lib/rpc/index.js.map +1 -1
  20. package/build/lib/rpc/remote-messages.d.ts +62 -41
  21. package/build/lib/rpc/remote-messages.d.ts.map +1 -1
  22. package/build/lib/rpc/remote-messages.js +53 -38
  23. package/build/lib/rpc/remote-messages.js.map +1 -1
  24. package/build/lib/rpc/rpc-client-real-device.js +2 -5
  25. package/build/lib/rpc/rpc-client-real-device.js.map +1 -1
  26. package/build/lib/rpc/rpc-client-simulator.js +10 -10
  27. package/build/lib/rpc/rpc-client-simulator.js.map +1 -1
  28. package/build/lib/rpc/rpc-client.js +50 -50
  29. package/build/lib/rpc/rpc-client.js.map +1 -1
  30. package/build/lib/rpc/rpc-message-handler.d.ts +32 -39
  31. package/build/lib/rpc/rpc-message-handler.d.ts.map +1 -1
  32. package/build/lib/rpc/rpc-message-handler.js +45 -59
  33. package/build/lib/rpc/rpc-message-handler.js.map +1 -1
  34. package/build/lib/types.d.ts +3 -0
  35. package/build/lib/types.d.ts.map +1 -1
  36. package/build/lib/utils.d.ts +54 -34
  37. package/build/lib/utils.d.ts.map +1 -1
  38. package/build/lib/utils.js +58 -39
  39. package/build/lib/utils.js.map +1 -1
  40. package/build/test/functional/safari-e2e-specs.js +5 -1
  41. package/build/test/functional/safari-e2e-specs.js.map +1 -1
  42. package/build/tsconfig.tsbuildinfo +1 -1
  43. package/lib/atoms.ts +98 -0
  44. package/lib/logger.ts +3 -0
  45. package/lib/protocol/{index.js → index.ts} +29 -17
  46. package/lib/remote-debugger.ts +1 -1
  47. package/lib/rpc/index.ts +2 -0
  48. package/lib/rpc/{remote-messages.js → remote-messages.ts} +70 -56
  49. package/lib/rpc/rpc-client-real-device.js +1 -1
  50. package/lib/rpc/rpc-client-simulator.js +1 -1
  51. package/lib/rpc/rpc-client.js +1 -1
  52. package/lib/rpc/{rpc-message-handler.js → rpc-message-handler.ts} +74 -65
  53. package/lib/types.ts +4 -0
  54. package/lib/{utils.js → utils.ts} +72 -51
  55. package/package.json +1 -1
  56. package/lib/atoms.js +0 -84
  57. package/lib/logger.js +0 -6
  58. package/lib/rpc/index.js +0 -4
@@ -1,21 +1,42 @@
1
- import log from '../logger';
1
+ import { EventEmitter } from 'node:events';
2
+ import { log } from '../logger';
2
3
  import _ from 'lodash';
3
4
  import { util } from '@appium/support';
4
- import EventEmitters from 'events';
5
+ import type { StringRecord } from '@appium/types';
5
6
 
7
+ /**
8
+ * Represents a data message from the Web Inspector.
9
+ */
10
+ interface DataMessage {
11
+ id?: string;
12
+ method: string;
13
+ params: StringRecord;
14
+ result: any;
15
+ error?: string | DataErrorMessage;
16
+ }
6
17
 
7
- export default class RpcMessageHandler extends EventEmitters {
8
- constructor () {
9
- super();
10
- }
18
+ /**
19
+ * Represents an error message structure in a data message.
20
+ */
21
+ interface DataErrorMessage {
22
+ message: string;
23
+ code: number;
24
+ data: any;
25
+ }
11
26
 
27
+ /**
28
+ * Handles messages from the Web Inspector and dispatches them as events.
29
+ * Extends EventEmitter to provide event-based message handling.
30
+ */
31
+ export default class RpcMessageHandler extends EventEmitter {
12
32
  /**
13
- * Handle a message from the Web Inspector.
33
+ * Handles a message from the Web Inspector by parsing the selector
34
+ * and emitting appropriate events.
14
35
  *
15
- * @param {import('@appium/types').StringRecord} plist
16
- * @returns {Promise<void>}
36
+ * @param plist - The plist message from the Web Inspector containing
37
+ * __selector and __argument properties.
17
38
  */
18
- async handleMessage (plist) {
39
+ async handleMessage(plist: StringRecord): Promise<void> {
19
40
  const selector = plist.__selector;
20
41
  if (!selector) {
21
42
  log.debug('Got an invalid plist');
@@ -70,35 +91,41 @@ export default class RpcMessageHandler extends EventEmitters {
70
91
  }
71
92
 
72
93
  /**
73
- * Parse the data key from the plist.
94
+ * Parses the data key from a plist message.
95
+ * The data key is a JSON string that needs to be parsed.
74
96
  *
75
- * @param {import('@appium/types').StringRecord} plist
76
- * @returns {DataMessage}
77
- * @throws {Error} if the data key cannot be parsed
97
+ * @param plist - The plist message containing the data key.
98
+ * @returns The parsed DataMessage object.
99
+ * @throws Error if the data key cannot be parsed.
78
100
  */
79
- parseDataKey (plist) {
101
+ private parseDataKey(plist: StringRecord): DataMessage {
80
102
  try {
81
103
  return JSON.parse(plist.__argument.WIRMessageDataKey.toString('utf8'));
82
- } catch (err) {
104
+ } catch (err: any) {
83
105
  log.error(`Unparseable message data: ${_.truncate(JSON.stringify(plist), {length: 100})}`);
84
106
  throw new Error(`Unable to parse message data: ${err.message}`);
85
107
  }
86
108
  }
87
109
 
88
110
  /**
89
- * Dispatch a data message.
111
+ * Dispatches a data message by emitting events.
112
+ * If msgId is provided, emits a message-specific event.
113
+ * Otherwise, emits method-based events with appropriate argument mapping.
90
114
  *
91
- * @param {string} msgId If not empty then the following event is going to be emitted:
92
- * - <msgId, error, result>
93
- * If empty then the following event is going to be emitted:
94
- * - <name, error, ..args>
95
- * @param {string | undefined} method
96
- * @param {import('@appium/types').StringRecord | undefined} params
97
- * @param {any} result
98
- * @param {Error | undefined} error
99
- * @returns {Promise<void>}
115
+ * @param msgId - If not empty, emits an event with this ID: <msgId, error, result>.
116
+ * If empty, emits method-based events: <name, error, ...args>.
117
+ * @param method - The method name from the data message.
118
+ * @param params - The parameters from the data message.
119
+ * @param result - The result from the data message.
120
+ * @param error - Any error that occurred during message processing.
100
121
  */
101
- async dispatchDataMessage (msgId, method, params, result, error) {
122
+ private async dispatchDataMessage(
123
+ msgId: string,
124
+ method: string | undefined,
125
+ params: StringRecord | undefined,
126
+ result: any,
127
+ error: Error | undefined
128
+ ): Promise<void> {
102
129
  if (msgId) {
103
130
  if (this.listenerCount(msgId)) {
104
131
  if (_.has(result?.result, 'value')) {
@@ -114,22 +141,20 @@ export default class RpcMessageHandler extends EventEmitters {
114
141
  return;
115
142
  }
116
143
 
117
- /** @type {any[]} */
118
- const eventNames = [method];
119
- /** @type {any[]} */
120
- let args = [params];
144
+ const eventNames: string[] = method ? [method] : [];
145
+ let args: any[] = [params];
121
146
 
122
147
  // some events have different names, or the arguments are mapped from the
123
148
  // parameters received
124
149
  switch (method) {
125
150
  case 'Page.frameStoppedLoading':
126
151
  eventNames.push('Page.frameNavigated');
127
- case 'Page.frameNavigated': // eslint-disable-line no-fallthrough
152
+ // eslint-disable-next-line no-fallthrough
153
+ case 'Page.frameNavigated':
128
154
  args = [`'${method}' event`];
129
155
  break;
130
156
  case 'Timeline.eventRecorded':
131
- // @ts-ignore This is fine for the given method
132
- args = [params || params.record];
157
+ args = [params || (params as any)?.record];
133
158
  break;
134
159
  case 'Console.messageAdded':
135
160
  args = [params?.message];
@@ -142,13 +167,13 @@ export default class RpcMessageHandler extends EventEmitters {
142
167
  break;
143
168
  }
144
169
 
145
- if (_.startsWith(method, 'Network.')) {
170
+ if (method && _.startsWith(method, 'Network.')) {
146
171
  // aggregate Network events, and add original method name to the arguments
147
172
  eventNames.push('NetworkEvent');
148
173
  args.push(method);
149
174
  }
150
- if (_.startsWith(method, 'Console.')) {
151
- // aggregate Network events, and add original method name to the arguments
175
+ if (method && _.startsWith(method, 'Console.')) {
176
+ // aggregate Console events, and add original method name to the arguments
152
177
  eventNames.push('ConsoleEvent');
153
178
  args.push(method);
154
179
  }
@@ -159,12 +184,12 @@ export default class RpcMessageHandler extends EventEmitters {
159
184
  }
160
185
 
161
186
  /**
162
- * Handle a data message from the Web Inspector.
187
+ * Handles a data message from the Web Inspector by parsing it and
188
+ * dispatching appropriate events based on the message type.
163
189
  *
164
- * @param {import('@appium/types').StringRecord} plist
165
- * @returns {Promise<void>}
190
+ * @param plist - The plist message from the Web Inspector.
166
191
  */
167
- async handleDataMessage (plist) {
192
+ private async handleDataMessage(plist: StringRecord): Promise<void> {
168
193
  const dataKey = this.parseDataKey(plist);
169
194
  let msgId = (dataKey.id || '').toString();
170
195
  let result = dataKey.result;
@@ -172,7 +197,7 @@ export default class RpcMessageHandler extends EventEmitters {
172
197
  let method = dataKey.method;
173
198
  let params = dataKey.params;
174
199
 
175
- const parseError = () => {
200
+ const parseError = (): Error | undefined => {
176
201
  const defaultMessage = 'Error occurred in handling data message';
177
202
  if (result?.wasThrown) {
178
203
  const message = (result?.result?.value || result?.result?.description)
@@ -182,10 +207,10 @@ export default class RpcMessageHandler extends EventEmitters {
182
207
  }
183
208
  if (dataKey.error) {
184
209
  if (_.isPlainObject(dataKey.error)) {
185
- const dataKeyError = /** @type {DataErrorMessage} */ (dataKey.error);
186
- let error = new Error(defaultMessage);
210
+ const dataKeyError = dataKey.error as DataErrorMessage;
211
+ const error = new Error(defaultMessage);
187
212
  for (const key of Object.keys(dataKeyError)) {
188
- error[key] = dataKeyError[key];
213
+ (error as any)[key] = dataKeyError[key as keyof DataErrorMessage];
189
214
  }
190
215
  return error;
191
216
  }
@@ -213,9 +238,9 @@ export default class RpcMessageHandler extends EventEmitters {
213
238
  method = message.method;
214
239
  result = message.result || message;
215
240
  params = result.params;
216
- } catch (err) {
241
+ } catch (err: any) {
217
242
  // if this happens then some aspect of the protocol is missing to us
218
- // so print the entire message to get visibiity into what is going on
243
+ // so print the entire message to get visibility into what is going on
219
244
  log.error(`Unexpected message format from Web Inspector: ${util.jsonStringify(plist, null)}`);
220
245
  throw err;
221
246
  }
@@ -227,22 +252,6 @@ export default class RpcMessageHandler extends EventEmitters {
227
252
  default: {
228
253
  await this.dispatchDataMessage(msgId, method, params, result, parseError());
229
254
  }
230
- } // switch
231
- } // function
255
+ }
256
+ }
232
257
  }
233
-
234
- /**
235
- * @typedef {Object} DataMessage
236
- * @property {string} [id]
237
- * @property {string} method
238
- * @property {import('@appium/types').StringRecord} params
239
- * @property {any} result
240
- * @property {string | DataErrorMessage} [error]
241
- */
242
-
243
- /**
244
- * @typedef {Object} DataErrorMessage
245
- * @property {string} message
246
- * @property {number} code
247
- * @property {any} data
248
- */
package/lib/types.ts CHANGED
@@ -83,6 +83,10 @@ export type AppIdKey = string | number;
83
83
  export type PageIdKey = string | number;
84
84
  export type TargetId = string;
85
85
 
86
+ export interface RemoteCommandId {
87
+ id: string;
88
+ }
89
+
86
90
  export interface RemoteCommandOpts {
87
91
  appIdKey?: AppIdKey;
88
92
  pageIdKey?: PageIdKey;
@@ -3,6 +3,8 @@ import { errorFromMJSONWPStatusCode } from '@appium/base-driver';
3
3
  import { util, node } from '@appium/support';
4
4
  import nodeFs from 'node:fs';
5
5
  import path from 'node:path';
6
+ import type { StringRecord } from '@appium/types';
7
+ import type { AppInfo, AppDict, Page } from './types';
6
8
 
7
9
  const MODULE_NAME = 'appium-remote-debugger';
8
10
  export const WEB_CONTENT_BUNDLE_ID = 'com.apple.WebKit.WebContent';
@@ -16,13 +18,13 @@ const ACCEPTED_PAGE_TYPES = [
16
18
  export const RESPONSE_LOG_LENGTH = 100;
17
19
 
18
20
  /**
19
- * Takes a dictionary from the remote debugger and makes a more manageable
20
- * dictionary whose keys are understandable
21
+ * Takes a dictionary from the remote debugger and converts it into a more
22
+ * manageable AppInfo object with understandable keys.
21
23
  *
22
- * @param {Record<string, any>} dict
23
- * @returns {[string, import('./types').AppInfo]}
24
+ * @param dict - Dictionary from the remote debugger containing application information.
25
+ * @returns A tuple containing the application ID and the AppInfo object.
24
26
  */
25
- export function appInfoFromDict (dict) {
27
+ export function appInfoFromDict(dict: Record<string, any>): [string, AppInfo] {
26
28
  const id = dict.WIRApplicationIdentifierKey;
27
29
  const isProxy = _.isString(dict.WIRIsApplicationProxyKey)
28
30
  ? dict.WIRIsApplicationProxyKey.toLowerCase() === 'true'
@@ -30,8 +32,7 @@ export function appInfoFromDict (dict) {
30
32
  // automation enabled can be either from the keys
31
33
  // - WIRRemoteAutomationEnabledKey (boolean)
32
34
  // - WIRAutomationAvailabilityKey (string or boolean)
33
- /** @type {boolean|string} */
34
- let isAutomationEnabled = !!dict.WIRRemoteAutomationEnabledKey;
35
+ let isAutomationEnabled: boolean | string = !!dict.WIRRemoteAutomationEnabledKey;
35
36
  if (_.has(dict, 'WIRAutomationAvailabilityKey')) {
36
37
  if (_.isString(dict.WIRAutomationAvailabilityKey)) {
37
38
  isAutomationEnabled = dict.WIRAutomationAvailabilityKey === 'WIRAutomationAvailabilityUnknown'
@@ -41,8 +42,7 @@ export function appInfoFromDict (dict) {
41
42
  isAutomationEnabled = !!dict.WIRAutomationAvailabilityKey;
42
43
  }
43
44
  }
44
- /** @type {import('./types').AppInfo} */
45
- const entry = {
45
+ const entry: AppInfo = {
46
46
  id,
47
47
  isProxy,
48
48
  name: dict.WIRApplicationNameKey,
@@ -56,13 +56,13 @@ export function appInfoFromDict (dict) {
56
56
  }
57
57
 
58
58
  /**
59
- * Take a dictionary from the remote debugger and makes a more manageable
60
- * dictionary of pages available.
59
+ * Takes a dictionary from the remote debugger and converts it into an array
60
+ * of Page objects with understandable keys. Filters out non-web pages.
61
61
  *
62
- * @param {import('@appium/types').StringRecord} pageDict
63
- * @returns {import('./types').Page[]}
62
+ * @param pageDict - Dictionary from the remote debugger containing page information.
63
+ * @returns An array of Page objects representing the available pages.
64
64
  */
65
- export function pageArrayFromDict (pageDict) {
65
+ export function pageArrayFromDict(pageDict: StringRecord): Page[] {
66
66
  return _.values(pageDict)
67
67
  // count only WIRTypeWeb pages and ignore all others (WIRTypeJavaScript etc)
68
68
  .filter((dict) => _.isUndefined(dict.WIRTypeKey) || ACCEPTED_PAGE_TYPES.includes(dict.WIRTypeKey))
@@ -75,14 +75,16 @@ export function pageArrayFromDict (pageDict) {
75
75
  }
76
76
 
77
77
  /**
78
+ * Finds all application identifier keys that match the given bundle ID.
79
+ * If no matches are found and the bundle ID is not WEB_CONTENT_BUNDLE_ID,
80
+ * falls back to searching for WEB_CONTENT_BUNDLE_ID.
78
81
  *
79
- * @param {string} bundleId
80
- * @param {import('./types').AppDict} appDict
81
- * @returns {string[]}
82
+ * @param bundleId - The bundle identifier to search for.
83
+ * @param appDict - The application dictionary to search in.
84
+ * @returns An array of unique application identifier keys matching the bundle ID.
82
85
  */
83
- export function appIdsForBundle (bundleId, appDict) {
84
- /** @type {string[]} */
85
- const appIds = _.toPairs(appDict)
86
+ export function appIdsForBundle(bundleId: string, appDict: AppDict): string[] {
87
+ const appIds: string[] = _.toPairs(appDict)
86
88
  .filter(([, data]) => data.bundleId === bundleId)
87
89
  .map(([key]) => key);
88
90
 
@@ -95,11 +97,15 @@ export function appIdsForBundle (bundleId, appDict) {
95
97
  }
96
98
 
97
99
  /**
98
- * @template {import('@appium/types').StringRecord} T
99
- * @param {T} params
100
- * @returns {T}
100
+ * Validates that all parameters in the provided object have non-nil values.
101
+ * Throws an error if any parameters are missing (null or undefined).
102
+ *
103
+ * @template T - The type of the parameters object.
104
+ * @param params - An object containing parameters to validate.
105
+ * @returns The same parameters object if all values are valid.
106
+ * @throws Error if any parameters are missing, listing all missing parameter names.
101
107
  */
102
- export function checkParams (params) {
108
+ export function checkParams<T extends StringRecord>(params: T): T {
103
109
  // check if all parameters have a value
104
110
  const errors = _.toPairs(params)
105
111
  .filter(([, value]) => _.isNil(value))
@@ -111,30 +117,33 @@ export function checkParams (params) {
111
117
  }
112
118
 
113
119
  /**
114
- * @param {any} value
115
- * @param {boolean} [multiline=false]
116
- * @returns {string}
120
+ * Converts a value to a JSON string, removing noisy function properties
121
+ * that can muddy the logs.
122
+ *
123
+ * @param value - The value to stringify.
124
+ * @param multiline - If true, formats the JSON with indentation. Defaults to false.
125
+ * @returns A JSON string representation of the value with noisy properties removed.
117
126
  */
118
- export function simpleStringify (value, multiline = false) {
127
+ export function simpleStringify(value: any, multiline: boolean = false): string {
119
128
  if (!value) {
120
129
  return JSON.stringify(value);
121
130
  }
122
131
 
123
- // we get back objects sometimes with string versions of functions
124
- // which muddy the logs
125
- let cleanValue = _.clone(value);
126
- for (const property of ['ceil', 'clone', 'floor', 'round', 'scale', 'toString']) {
127
- delete cleanValue[property];
128
- }
132
+ const cleanValue = removeNoisyProperties(_.clone(value));
129
133
  return multiline ? JSON.stringify(cleanValue, null, 2) : JSON.stringify(cleanValue);
130
134
  }
131
135
 
132
136
  /**
137
+ * Converts the result from a JavaScript evaluation in the remote debugger
138
+ * into a usable format. Handles errors, serialization, and cleans up noisy
139
+ * function properties.
133
140
  *
134
- * @param {any} res
135
- * @returns {any}
141
+ * @param res - The raw result from the remote debugger's JavaScript evaluation.
142
+ * @returns The cleaned and converted result value.
143
+ * @throws Error if the result is undefined, has an unexpected type, or contains
144
+ * an error status code.
136
145
  */
137
- export function convertJavascriptEvaluationResult (res) {
146
+ export function convertJavascriptEvaluationResult(res: any): any {
138
147
  if (_.isUndefined(res)) {
139
148
  throw new Error(`Did not get OK result from remote debugger. Result was: ${_.truncate(simpleStringify(res), {length: RESPONSE_LOG_LENGTH})}`);
140
149
  } else if (_.isString(res)) {
@@ -156,23 +165,17 @@ export function convertJavascriptEvaluationResult (res) {
156
165
  // with either have an object with a `value` property (even if `null`),
157
166
  // or a plain object
158
167
  const value = _.has(res, 'value') ? res.value : res;
159
-
160
- // get rid of noisy functions on objects
161
- if (_.isObject(value)) {
162
- for (const property of ['ceil', 'clone', 'floor', 'round', 'scale', 'toString']) {
163
- delete value[property];
164
- }
165
- }
166
- return value;
168
+ return removeNoisyProperties(value);
167
169
  }
168
170
 
169
171
  /**
170
- * Calculates the path to the current module's root folder
172
+ * Calculates the path to the current module's root folder.
173
+ * The result is memoized for performance.
171
174
  *
172
- * @returns {string} The full path to module root
173
- * @throws {Error} If the current module root folder cannot be determined
175
+ * @returns The full path to the module root directory.
176
+ * @throws Error if the module root folder cannot be determined.
174
177
  */
175
- export const getModuleRoot = _.memoize(function getModuleRoot () {
178
+ export const getModuleRoot = _.memoize(function getModuleRoot(): string {
176
179
  const root = node.getModuleRootSync(MODULE_NAME, __filename);
177
180
  if (!root) {
178
181
  throw new Error(`Cannot find the root folder of the ${MODULE_NAME} Node.js module`);
@@ -181,9 +184,27 @@ export const getModuleRoot = _.memoize(function getModuleRoot () {
181
184
  });
182
185
 
183
186
  /**
184
- * @returns {import('@appium/types').StringRecord}
187
+ * Reads and parses the package.json file from the module root.
188
+ *
189
+ * @returns The parsed package.json contents as a StringRecord.
185
190
  */
186
- export function getModuleProperties() {
191
+ export function getModuleProperties(): StringRecord {
187
192
  const fullPath = path.resolve(getModuleRoot(), 'package.json');
188
193
  return JSON.parse(nodeFs.readFileSync(fullPath, 'utf8'));
189
194
  }
195
+
196
+ /**
197
+ * Removes noisy function properties from an object that can muddy the logs.
198
+ * These properties are often added by JavaScript number objects and similar.
199
+ *
200
+ * @param obj - The object to clean.
201
+ * @returns The cleaned object.
202
+ */
203
+ function removeNoisyProperties<T>(obj: T): T {
204
+ if (_.isObject(obj)) {
205
+ for (const property of ['ceil', 'clone', 'floor', 'round', 'scale', 'toString']) {
206
+ delete obj[property];
207
+ }
208
+ }
209
+ return obj;
210
+ }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "keywords": [
5
5
  "appium"
6
6
  ],
7
- "version": "15.2.12",
7
+ "version": "15.2.14",
8
8
  "author": "Appium Contributors",
9
9
  "license": "Apache-2.0",
10
10
  "repository": {
package/lib/atoms.js DELETED
@@ -1,84 +0,0 @@
1
- import { fs } from '@appium/support';
2
- import path from 'path';
3
- import _ from 'lodash';
4
- import log from './logger';
5
- import { getModuleRoot } from './utils';
6
-
7
- const ATOMS_CACHE = {};
8
-
9
- /**
10
- * @param {any} obj
11
- * @returns {string}
12
- */
13
- function atomsStringify(obj) {
14
- if (typeof obj === 'undefined') {
15
- return 'undefined';
16
- }
17
- return JSON.stringify(obj);
18
- }
19
-
20
- /**
21
- *
22
- * @param {string} atomName
23
- * @returns {Promise<Buffer>}
24
- */
25
- async function getAtom (atomName) {
26
- // check if we have already loaded and cached this atom
27
- if (!_.has(ATOMS_CACHE, atomName)) {
28
- const atomFileName = path.resolve(getModuleRoot(), 'atoms', `${atomName}.js`);
29
- try {
30
- ATOMS_CACHE[atomName] = await fs.readFile(atomFileName);
31
- } catch {
32
- throw new Error(`Unable to load Atom '${atomName}' from file '${atomFileName}'`);
33
- }
34
- }
35
-
36
- return ATOMS_CACHE[atomName];
37
- }
38
-
39
- /**
40
- * @param {string} script
41
- * @param {string} frame
42
- * @returns {Promise<string>}
43
- */
44
- async function wrapScriptForFrame (script, frame) {
45
- log.debug(`Wrapping script for frame '${frame}'`);
46
- const elFromCache = await getAtom('get_element_from_cache');
47
- return `(function (window) { var document = window.document; ` +
48
- `return (${script}); })((${elFromCache.toString('utf8')})(${atomsStringify(frame)}))`;
49
- }
50
-
51
- /**
52
- *
53
- * @param {string} atom
54
- * @param {any[]} [args]
55
- * @param {string[]} [frames]
56
- * @param {string?} [asyncCallBack]
57
- * @returns {Promise<string>}
58
- */
59
- async function getScriptForAtom (atom, args = [], frames = [], asyncCallBack = null) {
60
- const atomSrc = (await getAtom(atom)).toString('utf8');
61
- let script;
62
- if (frames.length > 0) {
63
- script = atomSrc;
64
- for (const frame of frames) {
65
- script = await wrapScriptForFrame(script, frame);
66
- }
67
- } else {
68
- log.debug(`Executing '${atom}' atom in default context`);
69
- script = `(${atomSrc})`;
70
- }
71
-
72
- // add the arguments, as strings
73
- args = args.map(atomsStringify);
74
- if (asyncCallBack) {
75
- script += `(${args.join(',')}, ${asyncCallBack}, true)`;
76
- } else {
77
- script += `(${args.join(',')})`;
78
- }
79
-
80
- return script;
81
- }
82
-
83
- export { getAtom, getScriptForAtom };
84
- export default getAtom;
package/lib/logger.js DELETED
@@ -1,6 +0,0 @@
1
- import { logger } from '@appium/support';
2
-
3
-
4
- const log = logger.getLogger('RemoteDebugger');
5
-
6
- export default log;
package/lib/rpc/index.js DELETED
@@ -1,4 +0,0 @@
1
- import { RpcClientSimulator } from './rpc-client-simulator';
2
- import { RpcClientRealDevice } from './rpc-client-real-device';
3
-
4
- export { RpcClientSimulator, RpcClientRealDevice };