appium 3.2.2 → 3.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.
Files changed (250) hide show
  1. package/build/lib/appium.d.ts +147 -205
  2. package/build/lib/appium.d.ts.map +1 -1
  3. package/build/lib/appium.js +169 -282
  4. package/build/lib/appium.js.map +1 -1
  5. package/build/lib/bidi-commands.d.ts.map +1 -1
  6. package/build/lib/bidi-commands.js +11 -11
  7. package/build/lib/bidi-commands.js.map +1 -1
  8. package/build/lib/bootstrap/appium-initializer.d.ts +21 -0
  9. package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -0
  10. package/build/lib/bootstrap/appium-initializer.js +146 -0
  11. package/build/lib/bootstrap/appium-initializer.js.map +1 -0
  12. package/build/lib/bootstrap/appium-main-runner.d.ts +22 -0
  13. package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -0
  14. package/build/lib/bootstrap/appium-main-runner.js +109 -0
  15. package/build/lib/bootstrap/appium-main-runner.js.map +1 -0
  16. package/build/lib/bootstrap/config-file.d.ts +37 -0
  17. package/build/lib/bootstrap/config-file.d.ts.map +1 -0
  18. package/build/lib/{config-file.js → bootstrap/config-file.js} +62 -138
  19. package/build/lib/bootstrap/config-file.js.map +1 -0
  20. package/build/lib/bootstrap/grid-v3-register.d.ts +20 -0
  21. package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -0
  22. package/build/lib/bootstrap/grid-v3-register.js +185 -0
  23. package/build/lib/bootstrap/grid-v3-register.js.map +1 -0
  24. package/build/lib/bootstrap/init-types.d.ts +16 -0
  25. package/build/lib/bootstrap/init-types.d.ts.map +1 -0
  26. package/build/lib/bootstrap/init-types.js +3 -0
  27. package/build/lib/bootstrap/init-types.js.map +1 -0
  28. package/build/lib/bootstrap/main-helpers.d.ts +55 -0
  29. package/build/lib/bootstrap/main-helpers.d.ts.map +1 -0
  30. package/build/lib/bootstrap/main-helpers.js +187 -0
  31. package/build/lib/bootstrap/main-helpers.js.map +1 -0
  32. package/build/lib/bootstrap/node-helpers.d.ts +32 -0
  33. package/build/lib/bootstrap/node-helpers.d.ts.map +1 -0
  34. package/build/lib/bootstrap/node-helpers.js +201 -0
  35. package/build/lib/bootstrap/node-helpers.js.map +1 -0
  36. package/build/lib/bootstrap/startup-config.d.ts +22 -0
  37. package/build/lib/bootstrap/startup-config.d.ts.map +1 -0
  38. package/build/lib/bootstrap/startup-config.js +111 -0
  39. package/build/lib/bootstrap/startup-config.js.map +1 -0
  40. package/build/lib/cli/args.d.ts +16 -12
  41. package/build/lib/cli/args.d.ts.map +1 -1
  42. package/build/lib/cli/args.js +20 -40
  43. package/build/lib/cli/args.js.map +1 -1
  44. package/build/lib/cli/driver-command.d.ts +51 -93
  45. package/build/lib/cli/driver-command.d.ts.map +1 -1
  46. package/build/lib/cli/driver-command.js +11 -66
  47. package/build/lib/cli/driver-command.js.map +1 -1
  48. package/build/lib/cli/extension-command.d.ts +173 -377
  49. package/build/lib/cli/extension-command.d.ts.map +1 -1
  50. package/build/lib/cli/extension-command.js +387 -656
  51. package/build/lib/cli/extension-command.js.map +1 -1
  52. package/build/lib/cli/extension.d.ts +10 -15
  53. package/build/lib/cli/extension.d.ts.map +1 -1
  54. package/build/lib/cli/extension.js +15 -33
  55. package/build/lib/cli/extension.js.map +1 -1
  56. package/build/lib/cli/parser.d.ts +37 -66
  57. package/build/lib/cli/parser.d.ts.map +1 -1
  58. package/build/lib/cli/parser.js +69 -104
  59. package/build/lib/cli/parser.js.map +1 -1
  60. package/build/lib/cli/plugin-command.d.ts +50 -90
  61. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  62. package/build/lib/cli/plugin-command.js +11 -63
  63. package/build/lib/cli/plugin-command.js.map +1 -1
  64. package/build/lib/cli/setup-command.d.ts +21 -26
  65. package/build/lib/cli/setup-command.d.ts.map +1 -1
  66. package/build/lib/cli/setup-command.js +19 -61
  67. package/build/lib/cli/setup-command.js.map +1 -1
  68. package/build/lib/cli/utils.d.ts +33 -35
  69. package/build/lib/cli/utils.d.ts.map +1 -1
  70. package/build/lib/cli/utils.js +48 -50
  71. package/build/lib/cli/utils.js.map +1 -1
  72. package/build/lib/constants.d.ts +23 -23
  73. package/build/lib/constants.d.ts.map +1 -1
  74. package/build/lib/constants.js +10 -15
  75. package/build/lib/constants.js.map +1 -1
  76. package/build/lib/doctor/doctor.d.ts +40 -57
  77. package/build/lib/doctor/doctor.d.ts.map +1 -1
  78. package/build/lib/doctor/doctor.js +31 -62
  79. package/build/lib/doctor/doctor.js.map +1 -1
  80. package/build/lib/extension/driver-config.d.ts +18 -77
  81. package/build/lib/extension/driver-config.d.ts.map +1 -1
  82. package/build/lib/extension/driver-config.js +37 -125
  83. package/build/lib/extension/driver-config.js.map +1 -1
  84. package/build/lib/extension/extension-config.d.ts +103 -210
  85. package/build/lib/extension/extension-config.d.ts.map +1 -1
  86. package/build/lib/extension/extension-config.js +180 -342
  87. package/build/lib/extension/extension-config.js.map +1 -1
  88. package/build/lib/extension/index.d.ts +12 -29
  89. package/build/lib/extension/index.d.ts.map +1 -1
  90. package/build/lib/extension/index.js +33 -75
  91. package/build/lib/extension/index.js.map +1 -1
  92. package/build/lib/extension/manifest-migrations.d.ts +3 -20
  93. package/build/lib/extension/manifest-migrations.d.ts.map +1 -1
  94. package/build/lib/extension/manifest-migrations.js +20 -101
  95. package/build/lib/extension/manifest-migrations.js.map +1 -1
  96. package/build/lib/extension/manifest.d.ts +61 -107
  97. package/build/lib/extension/manifest.d.ts.map +1 -1
  98. package/build/lib/extension/manifest.js +181 -356
  99. package/build/lib/extension/manifest.js.map +1 -1
  100. package/build/lib/extension/package-changed.d.ts +1 -3
  101. package/build/lib/extension/package-changed.d.ts.map +1 -1
  102. package/build/lib/extension/package-changed.js +8 -15
  103. package/build/lib/extension/package-changed.js.map +1 -1
  104. package/build/lib/extension/plugin-config.d.ts +10 -52
  105. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  106. package/build/lib/extension/plugin-config.js +11 -63
  107. package/build/lib/extension/plugin-config.js.map +1 -1
  108. package/build/lib/helpers/build.d.ts +22 -0
  109. package/build/lib/helpers/build.d.ts.map +1 -0
  110. package/build/lib/helpers/build.js +109 -0
  111. package/build/lib/helpers/build.js.map +1 -0
  112. package/build/lib/helpers/capability.d.ts +38 -0
  113. package/build/lib/helpers/capability.d.ts.map +1 -0
  114. package/build/lib/helpers/capability.js +128 -0
  115. package/build/lib/helpers/capability.js.map +1 -0
  116. package/build/lib/helpers/network.d.ts +14 -0
  117. package/build/lib/helpers/network.d.ts.map +1 -0
  118. package/build/lib/helpers/network.js +35 -0
  119. package/build/lib/helpers/network.js.map +1 -0
  120. package/build/lib/insecure-features.js +6 -6
  121. package/build/lib/insecure-features.js.map +1 -1
  122. package/build/lib/inspector-commands.d.ts +6 -0
  123. package/build/lib/inspector-commands.d.ts.map +1 -1
  124. package/build/lib/inspector-commands.js +6 -0
  125. package/build/lib/inspector-commands.js.map +1 -1
  126. package/build/lib/logger.d.ts +2 -3
  127. package/build/lib/logger.d.ts.map +1 -1
  128. package/build/lib/logger.js +2 -3
  129. package/build/lib/logger.js.map +1 -1
  130. package/build/lib/logsink.d.ts +13 -22
  131. package/build/lib/logsink.d.ts.map +1 -1
  132. package/build/lib/logsink.js +48 -103
  133. package/build/lib/logsink.js.map +1 -1
  134. package/build/lib/main.d.ts +15 -58
  135. package/build/lib/main.d.ts.map +1 -1
  136. package/build/lib/main.js +25 -425
  137. package/build/lib/main.js.map +1 -1
  138. package/build/lib/schema/arg-spec.d.ts +32 -107
  139. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  140. package/build/lib/schema/arg-spec.js +11 -107
  141. package/build/lib/schema/arg-spec.js.map +1 -1
  142. package/build/lib/schema/cli-args-guards.d.ts +34 -0
  143. package/build/lib/schema/cli-args-guards.d.ts.map +1 -0
  144. package/build/lib/schema/cli-args-guards.js +49 -0
  145. package/build/lib/schema/cli-args-guards.js.map +1 -0
  146. package/build/lib/schema/cli-args.d.ts +3 -15
  147. package/build/lib/schema/cli-args.d.ts.map +1 -1
  148. package/build/lib/schema/cli-args.js +17 -107
  149. package/build/lib/schema/cli-args.js.map +1 -1
  150. package/build/lib/schema/cli-transformers.d.ts +15 -12
  151. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  152. package/build/lib/schema/cli-transformers.js +15 -45
  153. package/build/lib/schema/cli-transformers.js.map +1 -1
  154. package/build/lib/schema/format-errors.d.ts +28 -0
  155. package/build/lib/schema/format-errors.d.ts.map +1 -0
  156. package/build/lib/schema/format-errors.js +29 -0
  157. package/build/lib/schema/format-errors.js.map +1 -0
  158. package/build/lib/schema/index.d.ts +4 -2
  159. package/build/lib/schema/index.d.ts.map +1 -1
  160. package/build/lib/schema/index.js +2 -0
  161. package/build/lib/schema/index.js.map +1 -1
  162. package/build/lib/schema/keywords.d.ts +12 -20
  163. package/build/lib/schema/keywords.d.ts.map +1 -1
  164. package/build/lib/schema/keywords.js +6 -51
  165. package/build/lib/schema/keywords.js.map +1 -1
  166. package/build/lib/schema/schema.d.ts +106 -231
  167. package/build/lib/schema/schema.d.ts.map +1 -1
  168. package/build/lib/schema/schema.js +88 -358
  169. package/build/lib/schema/schema.js.map +1 -1
  170. package/build/lib/utils.d.ts +7 -267
  171. package/build/lib/utils.d.ts.map +1 -1
  172. package/build/lib/utils.js +10 -409
  173. package/build/lib/utils.js.map +1 -1
  174. package/lib/{appium.js → appium.ts} +297 -341
  175. package/lib/bidi-commands.ts +10 -14
  176. package/lib/bootstrap/appium-initializer.ts +212 -0
  177. package/lib/bootstrap/appium-main-runner.ts +172 -0
  178. package/lib/bootstrap/config-file.ts +178 -0
  179. package/lib/bootstrap/grid-v3-register.ts +250 -0
  180. package/lib/bootstrap/init-types.ts +31 -0
  181. package/lib/bootstrap/main-helpers.ts +223 -0
  182. package/lib/bootstrap/node-helpers.ts +180 -0
  183. package/lib/bootstrap/startup-config.ts +143 -0
  184. package/lib/cli/{args.js → args.ts} +45 -56
  185. package/lib/cli/driver-command.ts +122 -0
  186. package/lib/cli/{extension-command.js → extension-command.ts} +827 -906
  187. package/lib/cli/extension.ts +65 -0
  188. package/lib/cli/{parser.js → parser.ts} +93 -116
  189. package/lib/cli/plugin-command.ts +117 -0
  190. package/lib/cli/{setup-command.js → setup-command.ts} +59 -74
  191. package/lib/cli/utils.ts +97 -0
  192. package/lib/{constants.js → constants.ts} +30 -41
  193. package/lib/doctor/{doctor.js → doctor.ts} +82 -92
  194. package/lib/extension/driver-config.ts +165 -0
  195. package/lib/extension/{extension-config.js → extension-config.ts} +291 -405
  196. package/lib/extension/index.ts +143 -0
  197. package/lib/extension/manifest-migrations.ts +57 -0
  198. package/lib/extension/manifest.ts +369 -0
  199. package/lib/extension/{package-changed.js → package-changed.ts} +9 -18
  200. package/lib/extension/plugin-config.ts +62 -0
  201. package/lib/helpers/build.ts +111 -0
  202. package/lib/helpers/capability.ts +171 -0
  203. package/lib/helpers/network.ts +30 -0
  204. package/lib/insecure-features.ts +1 -1
  205. package/lib/inspector-commands.ts +6 -1
  206. package/lib/{logger.js → logger.ts} +1 -2
  207. package/lib/{logsink.js → logsink.ts} +91 -137
  208. package/lib/main.ts +60 -0
  209. package/lib/schema/arg-spec.ts +131 -0
  210. package/lib/schema/cli-args-guards.ts +67 -0
  211. package/lib/schema/cli-args.ts +171 -0
  212. package/lib/schema/cli-transformers.ts +83 -0
  213. package/lib/schema/format-errors.ts +43 -0
  214. package/lib/schema/index.ts +4 -0
  215. package/lib/schema/keywords.ts +96 -0
  216. package/lib/schema/schema.ts +448 -0
  217. package/lib/utils.ts +73 -0
  218. package/package.json +17 -18
  219. package/scripts/autoinstall-extensions.js +3 -0
  220. package/build/lib/config-file.d.ts +0 -100
  221. package/build/lib/config-file.d.ts.map +0 -1
  222. package/build/lib/config-file.js.map +0 -1
  223. package/build/lib/config.d.ts +0 -70
  224. package/build/lib/config.d.ts.map +0 -1
  225. package/build/lib/config.js +0 -390
  226. package/build/lib/config.js.map +0 -1
  227. package/build/lib/grid-register.d.ts +0 -10
  228. package/build/lib/grid-register.d.ts.map +0 -1
  229. package/build/lib/grid-register.js +0 -134
  230. package/build/lib/grid-register.js.map +0 -1
  231. package/lib/cli/driver-command.js +0 -174
  232. package/lib/cli/extension.js +0 -74
  233. package/lib/cli/plugin-command.js +0 -164
  234. package/lib/cli/utils.js +0 -91
  235. package/lib/config-file.js +0 -228
  236. package/lib/config.js +0 -389
  237. package/lib/extension/driver-config.js +0 -245
  238. package/lib/extension/index.js +0 -169
  239. package/lib/extension/manifest-migrations.js +0 -136
  240. package/lib/extension/manifest.js +0 -550
  241. package/lib/extension/plugin-config.js +0 -112
  242. package/lib/grid-register.js +0 -146
  243. package/lib/main.js +0 -545
  244. package/lib/schema/arg-spec.js +0 -229
  245. package/lib/schema/cli-args.js +0 -254
  246. package/lib/schema/cli-transformers.js +0 -113
  247. package/lib/schema/index.js +0 -2
  248. package/lib/schema/keywords.js +0 -136
  249. package/lib/schema/schema.js +0 -725
  250. package/lib/utils.js +0 -512
@@ -0,0 +1,448 @@
1
+ import Ajv, {type ErrorObject, type SchemaObject, type ValidateFunction} from 'ajv';
2
+ import addFormats from 'ajv-formats';
3
+ import _ from 'lodash';
4
+ import path from 'node:path';
5
+ import {AppiumConfigJsonSchema} from '@appium/schema';
6
+ import type {ExtensionType} from '@appium/types';
7
+ import {DRIVER_TYPE, PLUGIN_TYPE} from '../constants';
8
+ import {APPIUM_CONFIG_SCHEMA_ID, ArgSpec, SERVER_PROP_NAME} from './arg-spec';
9
+ import {keywords} from './keywords';
10
+
11
+ type StrictSchemaObject = SchemaObject & {additionalProperties: false};
12
+ type FlattenedSchema = {schema: SchemaObject; argSpec: ArgSpec}[];
13
+ type ArgSpecDefaultValue = ArgSpec['defaultValue'];
14
+ type NestedArgSpecDefaultValue = Record<string, Record<string, ArgSpecDefaultValue>>;
15
+ type DefaultValues<Flattened extends boolean | undefined> = Record<
16
+ string,
17
+ Flattened extends true ? ArgSpecDefaultValue : ArgSpecDefaultValue | NestedArgSpecDefaultValue
18
+ >;
19
+ type AllowedSchemaExtension = '.json' | '.js' | '.cjs';
20
+
21
+ /**
22
+ * Key/value pairs go in... but they don't come out.
23
+ */
24
+ export class RoachHotelMap<K, V> extends Map<K, V> {
25
+ override set(key: K, value: V): this {
26
+ if (this.has(key)) {
27
+ throw new Error(`${String(key)} is already set`);
28
+ }
29
+ return super.set(key, value);
30
+ }
31
+
32
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
+ override delete(_key: K): boolean {
34
+ return false;
35
+ }
36
+
37
+ override clear(): void {
38
+ throw new Error(`Cannot clear RoachHotelMap`);
39
+ }
40
+ }
41
+
42
+ export const ALLOWED_SCHEMA_EXTENSIONS = Object.freeze(
43
+ new Set<AllowedSchemaExtension>(['.json', '.js', '.cjs'])
44
+ );
45
+
46
+ const SCHEMA_KEY = '$schema';
47
+
48
+ class AppiumSchema {
49
+ static #instance: AppiumSchema;
50
+ #argSpecs = new RoachHotelMap<string, ArgSpec>();
51
+ #registeredSchemas: Record<ExtensionType, Map<string, SchemaObject>> = {
52
+ [DRIVER_TYPE]: new Map(),
53
+ [PLUGIN_TYPE]: new Map(),
54
+ };
55
+ #ajv: Ajv;
56
+ #finalizedSchemas: Record<string, StrictSchemaObject> | null = null;
57
+
58
+ private constructor() {
59
+ this.#ajv = AppiumSchema._instantiateAjv();
60
+ }
61
+
62
+ /**
63
+ * Returns a singleton instance.
64
+ */
65
+ static create(): AppiumSchema {
66
+ if (!AppiumSchema.#instance) {
67
+ const instance = new AppiumSchema();
68
+ AppiumSchema.#instance = instance;
69
+ _.bindAll(instance, [
70
+ 'finalize',
71
+ 'flatten',
72
+ 'getAllArgSpecs',
73
+ 'getArgSpec',
74
+ 'getDefaults',
75
+ 'getDefaultsForExtension',
76
+ 'getSchema',
77
+ 'hasArgSpec',
78
+ 'isFinalized',
79
+ 'registerSchema',
80
+ 'hasRegisteredSchema',
81
+ 'reset',
82
+ 'validate',
83
+ ]);
84
+ }
85
+ return AppiumSchema.#instance;
86
+ }
87
+
88
+ /**
89
+ * Returns `true` if filename extension is an allowed schema extension.
90
+ */
91
+ static isAllowedSchemaFileExtension(filename: string): boolean {
92
+ return ALLOWED_SCHEMA_EXTENSIONS.has(path.extname(filename) as AllowedSchemaExtension);
93
+ }
94
+
95
+ /**
96
+ * Returns `true` if schema is a plain object and not async.
97
+ */
98
+ static isSupportedSchemaType(schema: any): schema is SchemaObject {
99
+ return _.isPlainObject(schema) && (schema as any).$async !== true;
100
+ }
101
+
102
+ /**
103
+ * Configures and creates an Ajv instance.
104
+ */
105
+ private static _instantiateAjv(): Ajv {
106
+ const ajv = addFormats(
107
+ new Ajv({
108
+ // without this not much validation actually happens
109
+ allErrors: true,
110
+ })
111
+ );
112
+ _.forEach(keywords, (keyword) => {
113
+ ajv.addKeyword(keyword);
114
+ });
115
+ return ajv;
116
+ }
117
+
118
+ /**
119
+ * Returns `true` if a schema has been registered for extension type/name.
120
+ */
121
+ hasRegisteredSchema(extType: ExtensionType, extName: string): boolean {
122
+ return this.#registeredSchemas[extType].has(extName);
123
+ }
124
+
125
+ /**
126
+ * Returns `true` if this instance has been finalized.
127
+ */
128
+ isFinalized(): boolean {
129
+ return Boolean(this.#finalizedSchemas);
130
+ }
131
+
132
+ /**
133
+ * Returns map of known argument specs.
134
+ */
135
+ getAllArgSpecs(): ReadonlyMap<string, ArgSpec> {
136
+ return this.#argSpecs;
137
+ }
138
+
139
+ /**
140
+ * Finalizes all registered schemas into Ajv and generates arg-spec lookups.
141
+ */
142
+ async finalize(): Promise<Readonly<Record<string, StrictSchemaObject>>> {
143
+ if (this.isFinalized()) {
144
+ return this.#finalizedSchemas as Record<string, StrictSchemaObject>;
145
+ }
146
+
147
+ const ajv = this.#ajv;
148
+ const baseSchema = _.cloneDeep(AppiumConfigJsonSchema) as any;
149
+
150
+ const addArgSpecs = (
151
+ schema: Record<string, any>,
152
+ extType?: ExtensionType,
153
+ extName?: string
154
+ ): void => {
155
+ for (const [propName, propSchema] of Object.entries(schema)) {
156
+ const argSpec = ArgSpec.create(propName, {
157
+ dest: (propSchema as any).appiumCliDest,
158
+ defaultValue: (propSchema as any).default,
159
+ extType,
160
+ extName,
161
+ });
162
+ this.#argSpecs.set(argSpec.arg, argSpec);
163
+ }
164
+ };
165
+
166
+ addArgSpecs(_.omit(baseSchema.properties.server.properties, [DRIVER_TYPE, PLUGIN_TYPE]));
167
+
168
+ const finalizedSchemas: Record<string, StrictSchemaObject> = {};
169
+
170
+ for (const [extType, extensionSchemas] of Object.entries(this.#registeredSchemas) as Array<
171
+ [ExtensionType, Map<string, SchemaObject>]
172
+ >) {
173
+ for (const [extName, schema] of extensionSchemas.entries()) {
174
+ const $ref = ArgSpec.toSchemaBaseRef(extType, extName);
175
+ (schema as any).$id = $ref;
176
+ (schema as any).additionalProperties = false;
177
+ baseSchema.properties.server.properties[extType].properties[extName] = {$ref, $comment: extName};
178
+ await ajv.validateSchema(schema, true);
179
+ addArgSpecs((schema as any).properties, extType, extName);
180
+ ajv.addSchema(schema, $ref);
181
+ finalizedSchemas[$ref] = schema as StrictSchemaObject;
182
+ }
183
+ }
184
+
185
+ const finalSchema = baseSchema as StrictSchemaObject;
186
+
187
+ ajv.addSchema(finalSchema, APPIUM_CONFIG_SCHEMA_ID);
188
+ finalizedSchemas[APPIUM_CONFIG_SCHEMA_ID] = finalSchema;
189
+ await ajv.validateSchema(finalSchema, true);
190
+ this.#finalizedSchemas = finalizedSchemas;
191
+ return Object.freeze(finalizedSchemas);
192
+ }
193
+
194
+ /**
195
+ * Resets this instance to initial state.
196
+ */
197
+ reset(): void {
198
+ for (const schemaId of Object.keys(this.#finalizedSchemas ?? {})) {
199
+ this.#ajv.removeSchema(schemaId);
200
+ }
201
+ this.#argSpecs = new RoachHotelMap();
202
+ this.#registeredSchemas = {[DRIVER_TYPE]: new Map(), [PLUGIN_TYPE]: new Map()};
203
+ this.#finalizedSchemas = null;
204
+ this.#ajv = AppiumSchema._instantiateAjv();
205
+ }
206
+
207
+ /**
208
+ * Registers an extension schema.
209
+ */
210
+ async registerSchema(extType: ExtensionType, extName: string, schema: SchemaObject): Promise<void> {
211
+ if (!(extType && extName) || _.isUndefined(schema)) {
212
+ throw new TypeError('Expected extension type, extension name, and a defined schema');
213
+ }
214
+ if (!AppiumSchema.isSupportedSchemaType(schema)) {
215
+ throw new SchemaUnsupportedSchemaError(schema, extType, extName);
216
+ }
217
+ const normalizedExtName = _.kebabCase(extName);
218
+ if (this.hasRegisteredSchema(extType, normalizedExtName)) {
219
+ if (_.isEqual(this.#registeredSchemas[extType].get(normalizedExtName), schema)) {
220
+ return;
221
+ }
222
+ throw new SchemaNameConflictError(extType, extName);
223
+ }
224
+ await this.#ajv.validateSchema(schema, true);
225
+ this.#registeredSchemas[extType].set(normalizedExtName, schema);
226
+ }
227
+
228
+ /**
229
+ * Returns an `ArgSpec` for argument name/ext context, if present.
230
+ */
231
+ getArgSpec(name: string, extType?: ExtensionType, extName?: string): ArgSpec | undefined {
232
+ return this.#argSpecs.get(ArgSpec.toArg(name, extType, extName));
233
+ }
234
+
235
+ /**
236
+ * Returns `true` if an `ArgSpec` exists for argument name/ext context.
237
+ */
238
+ hasArgSpec(name: string, extType?: ExtensionType, extName?: string): boolean {
239
+ return this.#argSpecs.has(ArgSpec.toArg(name, extType, extName));
240
+ }
241
+
242
+ /**
243
+ * Returns default values for all args, flattened or nested.
244
+ */
245
+ getDefaults<Flattened extends boolean | undefined = true>(
246
+ flatten = true as Flattened
247
+ ): DefaultValues<Flattened> {
248
+ if (!this.isFinalized()) {
249
+ throw new SchemaFinalizationError();
250
+ }
251
+
252
+ const reducer = flatten
253
+ ? (defaults: any, {defaultValue, dest}: ArgSpec) => {
254
+ if (!_.isUndefined(defaultValue)) {
255
+ defaults[dest] = defaultValue;
256
+ }
257
+ return defaults;
258
+ }
259
+ : (defaults: any, {defaultValue, dest}: ArgSpec) => {
260
+ if (!_.isUndefined(defaultValue)) {
261
+ _.set(defaults, dest, defaultValue);
262
+ }
263
+ return defaults;
264
+ };
265
+
266
+ const retval = {} as DefaultValues<Flattened>;
267
+ return [...this.#argSpecs.values()].reduce(reducer, retval);
268
+ }
269
+
270
+ /**
271
+ * Returns flattened defaults for a specific extension.
272
+ */
273
+ getDefaultsForExtension(
274
+ extType: ExtensionType,
275
+ extName: string
276
+ ): Record<string, ArgSpecDefaultValue> {
277
+ if (!this.isFinalized()) {
278
+ throw new SchemaFinalizationError();
279
+ }
280
+ const specs = [...this.#argSpecs.values()].filter(
281
+ (spec) => spec.extType === extType && spec.extName === extName
282
+ );
283
+ return specs.reduce((defaults, {defaultValue, rawDest}) => {
284
+ if (!_.isUndefined(defaultValue)) {
285
+ defaults[rawDest] = defaultValue;
286
+ }
287
+ return defaults;
288
+ }, {} as Record<string, ArgSpecDefaultValue>);
289
+ }
290
+
291
+ /**
292
+ * Flattens finalized schemas into schema + argSpec tuples.
293
+ */
294
+ flatten(): FlattenedSchema {
295
+ const schema = this.getSchema() as any;
296
+ const stack: {properties: Record<string, any>; prefix: string[]}[] = [
297
+ {properties: schema.properties, prefix: []},
298
+ ];
299
+ const flattened: FlattenedSchema = [];
300
+
301
+ for (const {properties, prefix} of stack) {
302
+ const pairs = _.toPairs(properties);
303
+ for (const [key, value] of pairs) {
304
+ if (key === SCHEMA_KEY) {
305
+ continue;
306
+ }
307
+ const {properties, $ref} = value as any;
308
+ if (properties) {
309
+ stack.push({properties, prefix: key === SERVER_PROP_NAME ? [] : [...prefix, key]});
310
+ } else if ($ref) {
311
+ let refSchema: any;
312
+ try {
313
+ refSchema = this.getSchema($ref);
314
+ } catch {
315
+ throw new SchemaUnknownSchemaError($ref);
316
+ }
317
+ const {normalizedExtName} = ArgSpec.extensionInfoFromRootSchemaId($ref);
318
+ if (!normalizedExtName) {
319
+ throw new ReferenceError(
320
+ `Could not determine extension name from schema ID ${$ref}. This is a bug.`
321
+ );
322
+ }
323
+ stack.push({properties: refSchema.properties, prefix: [...prefix, key, normalizedExtName]});
324
+ } else if (key !== DRIVER_TYPE && key !== PLUGIN_TYPE) {
325
+ const [extType, extName] = prefix;
326
+ const argSpec = this.getArgSpec(key, extType as ExtensionType, extName);
327
+ if (!argSpec) {
328
+ throw new ReferenceError(
329
+ `Unknown argument with key ${key}, extType ${extType} and extName ${extName}. This is a bug.`
330
+ );
331
+ }
332
+ flattened.push({schema: _.cloneDeep(value as SchemaObject), argSpec});
333
+ }
334
+ }
335
+ }
336
+ return flattened;
337
+ }
338
+
339
+ /**
340
+ * Returns schema by ID (default: base Appium schema).
341
+ */
342
+ getSchema(ref = APPIUM_CONFIG_SCHEMA_ID): SchemaObject {
343
+ return this._getValidator(ref).schema as SchemaObject;
344
+ }
345
+
346
+ /**
347
+ * Validates a value against schema by ID/reference.
348
+ */
349
+ validate(value: any, ref = APPIUM_CONFIG_SCHEMA_ID): ErrorObject[] {
350
+ const validator = this._getValidator(ref);
351
+ return !validator(value) && _.isArray(validator.errors) ? [...validator.errors] : [];
352
+ }
353
+
354
+ /**
355
+ * Retrieves schema validator function from Ajv.
356
+ */
357
+ private _getValidator(id = APPIUM_CONFIG_SCHEMA_ID): ValidateFunction {
358
+ const validator = this.#ajv.getSchema(id);
359
+ if (!validator) {
360
+ if (id === APPIUM_CONFIG_SCHEMA_ID) {
361
+ throw new SchemaFinalizationError();
362
+ }
363
+ throw new SchemaUnknownSchemaError(id);
364
+ }
365
+ return validator;
366
+ }
367
+ }
368
+
369
+ export class SchemaFinalizationError extends Error {
370
+ readonly code = 'APPIUMERR_SCHEMA_FINALIZATION' as const;
371
+ constructor() {
372
+ super('Schema not yet finalized; `finalize()` must be called first.');
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Thrown when a unique extension schema name conflicts with an existing one.
378
+ */
379
+ export class SchemaNameConflictError extends Error {
380
+ readonly code = 'APPIUMERR_SCHEMA_NAME_CONFLICT' as const;
381
+ readonly data: Readonly<{extType: ExtensionType; extName: string}>;
382
+ constructor(extType: ExtensionType, extName: string) {
383
+ super(`Name for ${extType} schema "${extName}" conflicts with an existing schema`);
384
+ this.data = {extType, extName};
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Thrown when requested schema ID is unknown to Ajv.
390
+ */
391
+ export class SchemaUnknownSchemaError extends ReferenceError {
392
+ readonly code = 'APPIUMERR_SCHEMA_UNKNOWN_SCHEMA' as const;
393
+ readonly data: Readonly<{schemaId: string}>;
394
+ constructor(schemaId: string) {
395
+ super(`Unknown schema: "${schemaId}"`);
396
+ this.data = {schemaId};
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Thrown when provided schema type is unsupported (boolean/async/non-object).
402
+ */
403
+ export class SchemaUnsupportedSchemaError extends TypeError {
404
+ readonly code = 'APPIUMERR_SCHEMA_UNSUPPORTED_SCHEMA' as const;
405
+ readonly data: Readonly<{schema: any; extType: ExtensionType; extName: string}>;
406
+
407
+ constructor(schema: any, extType: ExtensionType, extName: string) {
408
+ super(
409
+ (() => {
410
+ const msg = `Unsupported schema from ${extType} "${extName}":`;
411
+ if (_.isBoolean(schema)) {
412
+ return `${msg} schema cannot be a boolean`;
413
+ }
414
+ if (_.isPlainObject(schema)) {
415
+ if ((schema as any).$async) {
416
+ return `${msg} schema cannot be an async schema`;
417
+ }
418
+ throw new TypeError(
419
+ `schema IS supported; this error should not be thrown (this is a bug). value of schema: ${JSON.stringify(
420
+ schema
421
+ )}`
422
+ );
423
+ }
424
+ return `${msg} schema must be a plain object without a true "$async" property`;
425
+ })()
426
+ );
427
+ this.data = {schema, extType, extName};
428
+ }
429
+ }
430
+
431
+ const appiumSchema = AppiumSchema.create();
432
+
433
+ export const {
434
+ registerSchema,
435
+ getAllArgSpecs,
436
+ getArgSpec,
437
+ hasArgSpec,
438
+ isFinalized,
439
+ finalize: finalizeSchema,
440
+ reset: resetSchema,
441
+ validate,
442
+ getSchema,
443
+ flatten: flattenSchema,
444
+ getDefaults: getDefaultsForSchema,
445
+ getDefaultsForExtension,
446
+ } = appiumSchema;
447
+
448
+ export const {isAllowedSchemaFileExtension} = AppiumSchema;
package/lib/utils.ts ADDED
@@ -0,0 +1,73 @@
1
+ import _ from 'lodash';
2
+ import {node, fs} from '@appium/support';
3
+
4
+ export const npmPackage = fs.readPackageJsonFrom(__dirname);
5
+
6
+ /**
7
+ * Returns the root directory of the Appium module (memoized).
8
+ *
9
+ * @throws {Error} If the appium module root cannot be determined.
10
+ */
11
+ export const getAppiumModuleRoot = _.memoize(function getAppiumModuleRoot(): string {
12
+ const selfRoot = node.getModuleRootSync('appium', __filename);
13
+ if (!selfRoot) {
14
+ throw new Error('Cannot find the appium module root. This is likely a bug in Appium.');
15
+ }
16
+ return selfRoot;
17
+ });
18
+
19
+ /**
20
+ * Adler-32 checksum (see https://github.com/SheetJS/js-adler32).
21
+ */
22
+ export function adler32(str: string, seed: number | null = null): number {
23
+ let a = 1,
24
+ b = 0,
25
+ M = 0,
26
+ c = 0,
27
+ d = 0;
28
+ const L = str.length;
29
+ if (typeof seed === 'number') {
30
+ a = seed & 0xffff;
31
+ b = seed >>> 16;
32
+ }
33
+ for (let i = 0; i < L;) {
34
+ M = Math.min(L - i, 2918);
35
+ while (M > 0) {
36
+ c = str.charCodeAt(i++);
37
+ if (c < 0x80) {
38
+ a += c;
39
+ } else if (c < 0x800) {
40
+ a += 192 | ((c >> 6) & 31);
41
+ b += a;
42
+ --M;
43
+ a += 128 | (c & 63);
44
+ } else if (c >= 0xd800 && c < 0xe000) {
45
+ c = (c & 1023) + 64;
46
+ d = str.charCodeAt(i++) & 1023;
47
+ a += 240 | ((c >> 8) & 7);
48
+ b += a;
49
+ --M;
50
+ a += 128 | ((c >> 2) & 63);
51
+ b += a;
52
+ --M;
53
+ a += 128 | ((d >> 6) & 15) | ((c & 3) << 4);
54
+ b += a;
55
+ --M;
56
+ a += 128 | (d & 63);
57
+ } else {
58
+ a += 224 | ((c >> 12) & 15);
59
+ b += a;
60
+ --M;
61
+ a += 128 | ((c >> 6) & 63);
62
+ b += a;
63
+ --M;
64
+ a += 128 | (c & 63);
65
+ }
66
+ b += a;
67
+ --M;
68
+ }
69
+ a = 15 * (a >>> 16) + (a & 65535);
70
+ b = 15 * (b >>> 16) + (b & 65535);
71
+ }
72
+ return ((b % 65521) << 16) | (a % 65521);
73
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium",
3
- "version": "3.2.2",
3
+ "version": "3.3.1",
4
4
  "description": "Automation for Apps.",
5
5
  "keywords": [
6
6
  "automation",
@@ -60,32 +60,31 @@
60
60
  "test:unit": "mocha \"./test/unit/**/*.spec.ts\""
61
61
  },
62
62
  "dependencies": {
63
- "@appium/base-driver": "^10.2.2",
64
- "@appium/base-plugin": "^3.1.1",
65
- "@appium/docutils": "^2.2.2",
66
- "@appium/logger": "^2.0.5",
67
- "@appium/schema": "^1.1.0",
68
- "@appium/support": "^7.0.6",
69
- "@appium/types": "^1.2.1",
70
- "@sidvind/better-ajv-errors": "4.0.1",
63
+ "@appium/base-driver": "10.4.0",
64
+ "@appium/base-plugin": "3.2.1",
65
+ "@appium/docutils": "2.3.1",
66
+ "@appium/logger": "2.0.7",
67
+ "@appium/schema": "1.1.0",
68
+ "@appium/support": "7.1.1",
69
+ "@appium/types": "1.3.1",
70
+ "@sidvind/better-ajv-errors": "5.0.0",
71
71
  "ajv": "8.18.0",
72
72
  "ajv-formats": "3.0.1",
73
73
  "argparse": "2.0.1",
74
- "async-lock": "1.4.1",
75
- "axios": "1.13.6",
74
+ "axios": "1.15.0",
76
75
  "bluebird": "3.7.2",
77
76
  "lilconfig": "3.1.3",
78
- "lodash": "4.17.23",
79
- "lru-cache": "11.2.6",
77
+ "lodash": "4.18.1",
78
+ "lru-cache": "11.3.5",
80
79
  "ora": "5.4.1",
81
80
  "package-changed": "3.0.0",
82
81
  "resolve-from": "5.0.0",
83
82
  "semver": "7.7.4",
84
- "teen_process": "4.0.10",
85
- "type-fest": "5.4.4",
83
+ "teen_process": "4.1.1",
84
+ "type-fest": "5.6.0",
86
85
  "winston": "3.19.0",
87
- "ws": "8.19.0",
88
- "yaml": "2.8.2"
86
+ "ws": "8.20.0",
87
+ "yaml": "2.8.3"
89
88
  },
90
89
  "engines": {
91
90
  "node": "^20.19.0 || ^22.12.0 || >=24.0.0",
@@ -94,5 +93,5 @@
94
93
  "publishConfig": {
95
94
  "access": "public"
96
95
  },
97
- "gitHead": "c745352c6500937a4590d1ef6ef19785143a8870"
96
+ "gitHead": "17f84265d10944fec06ae7684ae8ad77d1224b50"
98
97
  }
@@ -98,6 +98,9 @@ async function init() {
98
98
  }
99
99
  }
100
100
 
101
+ /**
102
+ * Installs drivers/plugins requested via npm config vars.
103
+ */
101
104
  async function main() {
102
105
  if (!(await init())) {
103
106
  return;
@@ -1,100 +0,0 @@
1
- /**
2
- * Given an array of errors and the result of loading a config file, generate a
3
- * helpful string for the user.
4
- *
5
- * - If `opts` contains a `json` property, this should be the original JSON
6
- * _string_ of the config file. This is only applicable if the config file
7
- * was in JSON format. If present, it will associate line numbers with errors.
8
- * - If `errors` happens to be empty, this will throw.
9
- * @param {import('ajv').ErrorObject[]} errors - Non-empty array of errors. Required.
10
- * @param {ReadConfigFileResult['config']|any} [config] -
11
- * Configuration & metadata
12
- * @param {FormatConfigErrorsOptions} [opts]
13
- * @throws {TypeError} If `errors` is empty
14
- * @returns {string}
15
- */
16
- export function formatErrors(errors?: import("ajv").ErrorObject[], config?: ReadConfigFileResult["config"] | any, opts?: FormatConfigErrorsOptions): string;
17
- /**
18
- * Given an optional path, read a config file. Validates the config file.
19
- *
20
- * Call {@link validate} if you already have a config object.
21
- * @param {string} [filepath] - Path to config file, if we have one
22
- * @param {ReadConfigFileOptions} [opts] - Options
23
- * @public
24
- * @returns {Promise<ReadConfigFileResult>} Contains config and filepath, if found, and any errors
25
- */
26
- export function readConfigFile(filepath?: string, opts?: ReadConfigFileOptions): Promise<ReadConfigFileResult>;
27
- /**
28
- * Convert schema property names to either a) the value of the `appiumCliDest` property, if any; or b) camel-case
29
- * @param {AppiumConfig} config - Configuration object
30
- * @returns {NormalizedAppiumConfig} New object with camel-cased keys (or `dest` keys).
31
- */
32
- export function normalizeConfig(config: AppiumConfig): NormalizedAppiumConfig;
33
- /**
34
- * Result of calling {@link readConfigFile}.
35
- */
36
- export type ReadConfigFileResult = {
37
- /**
38
- * - Validation errors
39
- */
40
- errors?: import("ajv").ErrorObject<string, Record<string, any>, any>[] | undefined;
41
- /**
42
- * - The path to the config file, if found
43
- */
44
- filepath?: string | undefined;
45
- /**
46
- * - If `true`, the config file exists but is empty
47
- */
48
- isEmpty?: boolean | undefined;
49
- /**
50
- * - The parsed configuration
51
- */
52
- config?: import("@appium/types").NormalizedAppiumConfig | undefined;
53
- /**
54
- * - Human-readable error messages and suggestions. If the `pretty` option is `true`, this will be a nice string to print.
55
- */
56
- reason?: string | import("@sidvind/better-ajv-errors").IOutputError[] | undefined;
57
- };
58
- /**
59
- * Options for {@link readConfigFile}.
60
- */
61
- export type ReadConfigFileOptions = {
62
- /**
63
- * If `false`, do not use color and fancy formatting in the `reason` property of the {@link ReadConfigFileResult}. The value of `reason` is then suitable for machine-reading.
64
- */
65
- pretty?: boolean | undefined;
66
- };
67
- /**
68
- * This is an `AsyncSearcher` which is inexplicably _not_ exported by the `lilconfig` type definition.
69
- */
70
- export type LilconfigAsyncSearcher = ReturnType<typeof import("lilconfig")["lilconfig"]>;
71
- /**
72
- * The contents of an Appium config file. Generated from schema
73
- */
74
- export type AppiumConfig = import("@appium/types").AppiumConfig;
75
- /**
76
- * The contents of an Appium config file with camelcased property names (and using `appiumCliDest` value if present). Generated from {@link AppiumConfig}
77
- */
78
- export type NormalizedAppiumConfig = import("@appium/types").NormalizedAppiumConfig;
79
- /**
80
- * The string should be a raw JSON string.
81
- */
82
- export type RawJson = string;
83
- /**
84
- * Options for {@link formatErrors}.
85
- */
86
- export type FormatConfigErrorsOptions = {
87
- /**
88
- * - Raw JSON config (as string)
89
- */
90
- json?: string | undefined;
91
- /**
92
- * - Whether to format errors as a CLI-friendly string
93
- */
94
- pretty?: boolean | undefined;
95
- /**
96
- * - Specific ID of a prop; otherwise entire schema
97
- */
98
- schemaId?: string | undefined;
99
- };
100
- //# sourceMappingURL=config-file.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-file.d.ts","sourceRoot":"","sources":["../../lib/config-file.js"],"names":[],"mappings":"AA0EA;;;;;;;;;;;;;;GAcG;AACH,sCAPW,OAAO,KAAK,EAAE,WAAW,EAAE,WAC3B,oBAAoB,CAAC,QAAQ,CAAC,GAAC,GAAG,SAElC,yBAAyB,GAEvB,MAAM,CAUlB;AAED;;;;;;;;GAQG;AACH,0CALW,MAAM,SACN,qBAAqB,GAEnB,OAAO,CAAC,oBAAoB,CAAC,CAwCzC;AAED;;;;GAIG;AACH,wCAHW,YAAY,GACV,sBAAsB,CAgClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCAoBY,UAAU,CAAC,0BAAmB,CAAC,WAAW,CAAC,CAAC;;;;2BAK5C,OAAO,eAAe,EAAE,YAAY;;;;qCAKpC,OAAO,eAAe,EAAE,sBAAsB;;;;sBAK9C,MAAM"}