appium 3.2.2 → 3.3.0

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 (120) hide show
  1. package/build/lib/cli/args.d.ts +16 -12
  2. package/build/lib/cli/args.d.ts.map +1 -1
  3. package/build/lib/cli/args.js +15 -35
  4. package/build/lib/cli/args.js.map +1 -1
  5. package/build/lib/cli/driver-command.d.ts +51 -93
  6. package/build/lib/cli/driver-command.d.ts.map +1 -1
  7. package/build/lib/cli/driver-command.js +11 -66
  8. package/build/lib/cli/driver-command.js.map +1 -1
  9. package/build/lib/cli/extension-command.d.ts +211 -415
  10. package/build/lib/cli/extension-command.d.ts.map +1 -1
  11. package/build/lib/cli/extension-command.js +384 -653
  12. package/build/lib/cli/extension-command.js.map +1 -1
  13. package/build/lib/cli/extension.d.ts +11 -16
  14. package/build/lib/cli/extension.d.ts.map +1 -1
  15. package/build/lib/cli/extension.js +10 -28
  16. package/build/lib/cli/extension.js.map +1 -1
  17. package/build/lib/cli/parser.d.ts +40 -69
  18. package/build/lib/cli/parser.d.ts.map +1 -1
  19. package/build/lib/cli/parser.js +24 -59
  20. package/build/lib/cli/parser.js.map +1 -1
  21. package/build/lib/cli/plugin-command.d.ts +50 -90
  22. package/build/lib/cli/plugin-command.d.ts.map +1 -1
  23. package/build/lib/cli/plugin-command.js +11 -63
  24. package/build/lib/cli/plugin-command.js.map +1 -1
  25. package/build/lib/cli/setup-command.d.ts +21 -26
  26. package/build/lib/cli/setup-command.d.ts.map +1 -1
  27. package/build/lib/cli/setup-command.js +13 -55
  28. package/build/lib/cli/setup-command.js.map +1 -1
  29. package/build/lib/cli/utils.d.ts +27 -29
  30. package/build/lib/cli/utils.d.ts.map +1 -1
  31. package/build/lib/cli/utils.js +29 -31
  32. package/build/lib/cli/utils.js.map +1 -1
  33. package/build/lib/config-file.d.ts +24 -67
  34. package/build/lib/config-file.d.ts.map +1 -1
  35. package/build/lib/config-file.js +56 -115
  36. package/build/lib/config-file.js.map +1 -1
  37. package/build/lib/config.d.ts +42 -44
  38. package/build/lib/config.d.ts.map +1 -1
  39. package/build/lib/config.js +75 -107
  40. package/build/lib/config.js.map +1 -1
  41. package/build/lib/constants.d.ts +23 -23
  42. package/build/lib/constants.d.ts.map +1 -1
  43. package/build/lib/constants.js +10 -15
  44. package/build/lib/constants.js.map +1 -1
  45. package/build/lib/doctor/doctor.d.ts +40 -57
  46. package/build/lib/doctor/doctor.d.ts.map +1 -1
  47. package/build/lib/doctor/doctor.js +29 -60
  48. package/build/lib/doctor/doctor.js.map +1 -1
  49. package/build/lib/grid-register.d.ts +32 -7
  50. package/build/lib/grid-register.d.ts.map +1 -1
  51. package/build/lib/grid-register.js +84 -48
  52. package/build/lib/grid-register.js.map +1 -1
  53. package/build/lib/logsink.d.ts +13 -22
  54. package/build/lib/logsink.d.ts.map +1 -1
  55. package/build/lib/logsink.js +48 -103
  56. package/build/lib/logsink.js.map +1 -1
  57. package/build/lib/main.js +1 -1
  58. package/build/lib/main.js.map +1 -1
  59. package/build/lib/schema/arg-spec.d.ts +32 -107
  60. package/build/lib/schema/arg-spec.d.ts.map +1 -1
  61. package/build/lib/schema/arg-spec.js +11 -107
  62. package/build/lib/schema/arg-spec.js.map +1 -1
  63. package/build/lib/schema/cli-args.d.ts +3 -15
  64. package/build/lib/schema/cli-args.d.ts.map +1 -1
  65. package/build/lib/schema/cli-args.js +15 -105
  66. package/build/lib/schema/cli-args.js.map +1 -1
  67. package/build/lib/schema/cli-transformers.d.ts +15 -12
  68. package/build/lib/schema/cli-transformers.d.ts.map +1 -1
  69. package/build/lib/schema/cli-transformers.js +15 -45
  70. package/build/lib/schema/cli-transformers.js.map +1 -1
  71. package/build/lib/schema/index.d.ts +2 -2
  72. package/build/lib/schema/index.d.ts.map +1 -1
  73. package/build/lib/schema/index.js.map +1 -1
  74. package/build/lib/schema/keywords.d.ts +12 -20
  75. package/build/lib/schema/keywords.d.ts.map +1 -1
  76. package/build/lib/schema/keywords.js +6 -51
  77. package/build/lib/schema/keywords.js.map +1 -1
  78. package/build/lib/schema/schema.d.ts +106 -231
  79. package/build/lib/schema/schema.d.ts.map +1 -1
  80. package/build/lib/schema/schema.js +75 -345
  81. package/build/lib/schema/schema.js.map +1 -1
  82. package/build/lib/utils.d.ts +59 -238
  83. package/build/lib/utils.d.ts.map +1 -1
  84. package/build/lib/utils.js +55 -207
  85. package/build/lib/utils.js.map +1 -1
  86. package/lib/cli/{args.js → args.ts} +40 -51
  87. package/lib/cli/driver-command.ts +122 -0
  88. package/lib/cli/{extension-command.js → extension-command.ts} +610 -689
  89. package/lib/cli/extension.ts +65 -0
  90. package/lib/cli/{parser.js → parser.ts} +48 -71
  91. package/lib/cli/plugin-command.ts +117 -0
  92. package/lib/cli/{setup-command.js → setup-command.ts} +57 -72
  93. package/lib/cli/utils.ts +97 -0
  94. package/lib/config-file.ts +212 -0
  95. package/lib/{config.js → config.ts} +129 -141
  96. package/lib/{constants.js → constants.ts} +30 -41
  97. package/lib/doctor/{doctor.js → doctor.ts} +81 -91
  98. package/lib/grid-register.ts +250 -0
  99. package/lib/{logsink.js → logsink.ts} +91 -137
  100. package/lib/main.js +1 -1
  101. package/lib/schema/arg-spec.ts +131 -0
  102. package/lib/schema/cli-args.ts +171 -0
  103. package/lib/schema/cli-transformers.ts +83 -0
  104. package/lib/schema/keywords.ts +96 -0
  105. package/lib/schema/schema.ts +449 -0
  106. package/lib/utils.ts +404 -0
  107. package/package.json +16 -16
  108. package/lib/cli/driver-command.js +0 -174
  109. package/lib/cli/extension.js +0 -74
  110. package/lib/cli/plugin-command.js +0 -164
  111. package/lib/cli/utils.js +0 -91
  112. package/lib/config-file.js +0 -228
  113. package/lib/grid-register.js +0 -146
  114. package/lib/schema/arg-spec.js +0 -229
  115. package/lib/schema/cli-args.js +0 -254
  116. package/lib/schema/cli-transformers.js +0 -113
  117. package/lib/schema/keywords.js +0 -136
  118. package/lib/schema/schema.js +0 -725
  119. package/lib/utils.js +0 -512
  120. /package/lib/schema/{index.js → index.ts} +0 -0
@@ -0,0 +1,449 @@
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
+ #argSpecs = new RoachHotelMap<string, ArgSpec>();
50
+ #registeredSchemas: Record<ExtensionType, Map<string, SchemaObject>> = {
51
+ [DRIVER_TYPE]: new Map(),
52
+ [PLUGIN_TYPE]: new Map(),
53
+ };
54
+ #ajv: Ajv;
55
+ static #instance: AppiumSchema;
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 a schema has been registered for extension type/name.
90
+ */
91
+ hasRegisteredSchema(extType: ExtensionType, extName: string): boolean {
92
+ return this.#registeredSchemas[extType].has(extName);
93
+ }
94
+
95
+ /**
96
+ * Returns `true` if this instance has been finalized.
97
+ */
98
+ isFinalized(): boolean {
99
+ return Boolean(this.#finalizedSchemas);
100
+ }
101
+
102
+ /**
103
+ * Returns map of known argument specs.
104
+ */
105
+ getAllArgSpecs(): ReadonlyMap<string, ArgSpec> {
106
+ return this.#argSpecs;
107
+ }
108
+
109
+ /**
110
+ * Finalizes all registered schemas into Ajv and generates arg-spec lookups.
111
+ */
112
+ finalize(): Readonly<Record<string, StrictSchemaObject>> {
113
+ if (this.isFinalized()) {
114
+ return this.#finalizedSchemas as Record<string, StrictSchemaObject>;
115
+ }
116
+
117
+ const ajv = this.#ajv;
118
+ const baseSchema = _.cloneDeep(AppiumConfigJsonSchema) as any;
119
+
120
+ const addArgSpecs = (
121
+ schema: Record<string, any>,
122
+ extType?: ExtensionType,
123
+ extName?: string
124
+ ): void => {
125
+ for (const [propName, propSchema] of Object.entries(schema)) {
126
+ const argSpec = ArgSpec.create(propName, {
127
+ dest: (propSchema as any).appiumCliDest,
128
+ defaultValue: (propSchema as any).default,
129
+ extType,
130
+ extName,
131
+ });
132
+ this.#argSpecs.set(argSpec.arg, argSpec);
133
+ }
134
+ };
135
+
136
+ addArgSpecs(_.omit(baseSchema.properties.server.properties, [DRIVER_TYPE, PLUGIN_TYPE]));
137
+
138
+ const finalizedSchemas: Record<string, StrictSchemaObject> = {};
139
+
140
+ const finalSchema = _.reduce(
141
+ this.#registeredSchemas,
142
+ (base: any, extensionSchemas: Map<string, SchemaObject>, extType: ExtensionType) => {
143
+ extensionSchemas.forEach((schema, extName) => {
144
+ const $ref = ArgSpec.toSchemaBaseRef(extType, extName);
145
+ (schema as any).$id = $ref;
146
+ (schema as any).additionalProperties = false;
147
+ base.properties.server.properties[extType].properties[extName] = {$ref, $comment: extName};
148
+ ajv.validateSchema(schema, true);
149
+ addArgSpecs((schema as any).properties, extType, extName);
150
+ ajv.addSchema(schema, $ref);
151
+ finalizedSchemas[$ref] = schema as StrictSchemaObject;
152
+ });
153
+ return base;
154
+ },
155
+ baseSchema
156
+ ) as StrictSchemaObject;
157
+
158
+ ajv.addSchema(finalSchema, APPIUM_CONFIG_SCHEMA_ID);
159
+ finalizedSchemas[APPIUM_CONFIG_SCHEMA_ID] = finalSchema;
160
+ ajv.validateSchema(finalSchema, true);
161
+ this.#finalizedSchemas = finalizedSchemas;
162
+ return Object.freeze(finalizedSchemas);
163
+ }
164
+
165
+ /**
166
+ * Resets this instance to initial state.
167
+ */
168
+ reset(): void {
169
+ for (const schemaId of Object.keys(this.#finalizedSchemas ?? {})) {
170
+ this.#ajv.removeSchema(schemaId);
171
+ }
172
+ this.#argSpecs = new RoachHotelMap();
173
+ this.#registeredSchemas = {[DRIVER_TYPE]: new Map(), [PLUGIN_TYPE]: new Map()};
174
+ this.#finalizedSchemas = null;
175
+ this.#ajv = AppiumSchema._instantiateAjv();
176
+ }
177
+
178
+ /**
179
+ * Registers an extension schema.
180
+ */
181
+ registerSchema(extType: ExtensionType, extName: string, schema: SchemaObject): void {
182
+ if (!(extType && extName) || _.isUndefined(schema)) {
183
+ throw new TypeError('Expected extension type, extension name, and a defined schema');
184
+ }
185
+ if (!AppiumSchema.isSupportedSchemaType(schema)) {
186
+ throw new SchemaUnsupportedSchemaError(schema, extType, extName);
187
+ }
188
+ const normalizedExtName = _.kebabCase(extName);
189
+ if (this.hasRegisteredSchema(extType, normalizedExtName)) {
190
+ if (_.isEqual(this.#registeredSchemas[extType].get(normalizedExtName), schema)) {
191
+ return;
192
+ }
193
+ throw new SchemaNameConflictError(extType, extName);
194
+ }
195
+ this.#ajv.validateSchema(schema, true);
196
+ this.#registeredSchemas[extType].set(normalizedExtName, schema);
197
+ }
198
+
199
+ /**
200
+ * Returns an `ArgSpec` for argument name/ext context, if present.
201
+ */
202
+ getArgSpec(name: string, extType?: ExtensionType, extName?: string): ArgSpec | undefined {
203
+ return this.#argSpecs.get(ArgSpec.toArg(name, extType, extName));
204
+ }
205
+
206
+ /**
207
+ * Returns `true` if an `ArgSpec` exists for argument name/ext context.
208
+ */
209
+ hasArgSpec(name: string, extType?: ExtensionType, extName?: string): boolean {
210
+ return this.#argSpecs.has(ArgSpec.toArg(name, extType, extName));
211
+ }
212
+
213
+ /**
214
+ * Returns default values for all args, flattened or nested.
215
+ */
216
+ getDefaults<Flattened extends boolean | undefined = true>(
217
+ flatten = true as Flattened
218
+ ): DefaultValues<Flattened> {
219
+ if (!this.isFinalized()) {
220
+ throw new SchemaFinalizationError();
221
+ }
222
+
223
+ const reducer = flatten
224
+ ? (defaults: any, {defaultValue, dest}: ArgSpec) => {
225
+ if (!_.isUndefined(defaultValue)) {
226
+ defaults[dest] = defaultValue;
227
+ }
228
+ return defaults;
229
+ }
230
+ : (defaults: any, {defaultValue, dest}: ArgSpec) => {
231
+ if (!_.isUndefined(defaultValue)) {
232
+ _.set(defaults, dest, defaultValue);
233
+ }
234
+ return defaults;
235
+ };
236
+
237
+ const retval = {} as DefaultValues<Flattened>;
238
+ return [...this.#argSpecs.values()].reduce(reducer, retval);
239
+ }
240
+
241
+ /**
242
+ * Returns flattened defaults for a specific extension.
243
+ */
244
+ getDefaultsForExtension(
245
+ extType: ExtensionType,
246
+ extName: string
247
+ ): Record<string, ArgSpecDefaultValue> {
248
+ if (!this.isFinalized()) {
249
+ throw new SchemaFinalizationError();
250
+ }
251
+ const specs = [...this.#argSpecs.values()].filter(
252
+ (spec) => spec.extType === extType && spec.extName === extName
253
+ );
254
+ return specs.reduce((defaults, {defaultValue, rawDest}) => {
255
+ if (!_.isUndefined(defaultValue)) {
256
+ defaults[rawDest] = defaultValue;
257
+ }
258
+ return defaults;
259
+ }, {} as Record<string, ArgSpecDefaultValue>);
260
+ }
261
+
262
+ /**
263
+ * Flattens finalized schemas into schema + argSpec tuples.
264
+ */
265
+ flatten(): FlattenedSchema {
266
+ const schema = this.getSchema() as any;
267
+ const stack: {properties: Record<string, any>; prefix: string[]}[] = [
268
+ {properties: schema.properties, prefix: []},
269
+ ];
270
+ const flattened: FlattenedSchema = [];
271
+
272
+ for (const {properties, prefix} of stack) {
273
+ const pairs = _.toPairs(properties);
274
+ for (const [key, value] of pairs) {
275
+ if (key === SCHEMA_KEY) {
276
+ continue;
277
+ }
278
+ const {properties, $ref} = value as any;
279
+ if (properties) {
280
+ stack.push({properties, prefix: key === SERVER_PROP_NAME ? [] : [...prefix, key]});
281
+ } else if ($ref) {
282
+ let refSchema: any;
283
+ try {
284
+ refSchema = this.getSchema($ref);
285
+ } catch {
286
+ throw new SchemaUnknownSchemaError($ref);
287
+ }
288
+ const {normalizedExtName} = ArgSpec.extensionInfoFromRootSchemaId($ref);
289
+ if (!normalizedExtName) {
290
+ throw new ReferenceError(
291
+ `Could not determine extension name from schema ID ${$ref}. This is a bug.`
292
+ );
293
+ }
294
+ stack.push({properties: refSchema.properties, prefix: [...prefix, key, normalizedExtName]});
295
+ } else if (key !== DRIVER_TYPE && key !== PLUGIN_TYPE) {
296
+ const [extType, extName] = prefix;
297
+ const argSpec = this.getArgSpec(key, extType as ExtensionType, extName);
298
+ if (!argSpec) {
299
+ throw new ReferenceError(
300
+ `Unknown argument with key ${key}, extType ${extType} and extName ${extName}. This is a bug.`
301
+ );
302
+ }
303
+ flattened.push({schema: _.cloneDeep(value as SchemaObject), argSpec});
304
+ }
305
+ }
306
+ }
307
+ return flattened;
308
+ }
309
+
310
+ /**
311
+ * Returns schema by ID (default: base Appium schema).
312
+ */
313
+ getSchema(ref = APPIUM_CONFIG_SCHEMA_ID): SchemaObject {
314
+ return this._getValidator(ref).schema as SchemaObject;
315
+ }
316
+
317
+ /**
318
+ * Validates a value against schema by ID/reference.
319
+ */
320
+ validate(value: any, ref = APPIUM_CONFIG_SCHEMA_ID): ErrorObject[] {
321
+ const validator = this._getValidator(ref);
322
+ return !validator(value) && _.isArray(validator.errors) ? [...validator.errors] : [];
323
+ }
324
+
325
+ /**
326
+ * Returns `true` if filename extension is an allowed schema extension.
327
+ */
328
+ static isAllowedSchemaFileExtension(filename: string): boolean {
329
+ return ALLOWED_SCHEMA_EXTENSIONS.has(path.extname(filename) as AllowedSchemaExtension);
330
+ }
331
+
332
+ /**
333
+ * Returns `true` if schema is a plain object and not async.
334
+ */
335
+ static isSupportedSchemaType(schema: any): schema is SchemaObject {
336
+ return _.isPlainObject(schema) && (schema as any).$async !== true;
337
+ }
338
+
339
+ /**
340
+ * Configures and creates an Ajv instance.
341
+ */
342
+ private static _instantiateAjv(): Ajv {
343
+ const ajv = addFormats(
344
+ new Ajv({
345
+ // without this not much validation actually happens
346
+ allErrors: true,
347
+ })
348
+ );
349
+ _.forEach(keywords, (keyword) => {
350
+ ajv.addKeyword(keyword);
351
+ });
352
+ return ajv;
353
+ }
354
+
355
+ /**
356
+ * Retrieves schema validator function from Ajv.
357
+ */
358
+ private _getValidator(id = APPIUM_CONFIG_SCHEMA_ID): ValidateFunction {
359
+ const validator = this.#ajv.getSchema(id);
360
+ if (!validator) {
361
+ if (id === APPIUM_CONFIG_SCHEMA_ID) {
362
+ throw new SchemaFinalizationError();
363
+ }
364
+ throw new SchemaUnknownSchemaError(id);
365
+ }
366
+ return validator;
367
+ }
368
+ }
369
+
370
+ export class SchemaFinalizationError extends Error {
371
+ readonly code = 'APPIUMERR_SCHEMA_FINALIZATION' as const;
372
+ constructor() {
373
+ super('Schema not yet finalized; `finalize()` must be called first.');
374
+ }
375
+ }
376
+
377
+ /**
378
+ * Thrown when a unique extension schema name conflicts with an existing one.
379
+ */
380
+ export class SchemaNameConflictError extends Error {
381
+ readonly code = 'APPIUMERR_SCHEMA_NAME_CONFLICT' as const;
382
+ readonly data: Readonly<{extType: ExtensionType; extName: string}>;
383
+ constructor(extType: ExtensionType, extName: string) {
384
+ super(`Name for ${extType} schema "${extName}" conflicts with an existing schema`);
385
+ this.data = {extType, extName};
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Thrown when requested schema ID is unknown to Ajv.
391
+ */
392
+ export class SchemaUnknownSchemaError extends ReferenceError {
393
+ readonly code = 'APPIUMERR_SCHEMA_UNKNOWN_SCHEMA' as const;
394
+ readonly data: Readonly<{schemaId: string}>;
395
+ constructor(schemaId: string) {
396
+ super(`Unknown schema: "${schemaId}"`);
397
+ this.data = {schemaId};
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Thrown when provided schema type is unsupported (boolean/async/non-object).
403
+ */
404
+ export class SchemaUnsupportedSchemaError extends TypeError {
405
+ readonly code = 'APPIUMERR_SCHEMA_UNSUPPORTED_SCHEMA' as const;
406
+ readonly data: Readonly<{schema: any; extType: ExtensionType; extName: string}>;
407
+
408
+ constructor(schema: any, extType: ExtensionType, extName: string) {
409
+ super(
410
+ (() => {
411
+ const msg = `Unsupported schema from ${extType} "${extName}":`;
412
+ if (_.isBoolean(schema)) {
413
+ return `${msg} schema cannot be a boolean`;
414
+ }
415
+ if (_.isPlainObject(schema)) {
416
+ if ((schema as any).$async) {
417
+ return `${msg} schema cannot be an async schema`;
418
+ }
419
+ throw new TypeError(
420
+ `schema IS supported; this error should not be thrown (this is a bug). value of schema: ${JSON.stringify(
421
+ schema
422
+ )}`
423
+ );
424
+ }
425
+ return `${msg} schema must be a plain object without a true "$async" property`;
426
+ })()
427
+ );
428
+ this.data = {schema, extType, extName};
429
+ }
430
+ }
431
+
432
+ const appiumSchema = AppiumSchema.create();
433
+
434
+ export const {
435
+ registerSchema,
436
+ getAllArgSpecs,
437
+ getArgSpec,
438
+ hasArgSpec,
439
+ isFinalized,
440
+ finalize: finalizeSchema,
441
+ reset: resetSchema,
442
+ validate,
443
+ getSchema,
444
+ flatten: flattenSchema,
445
+ getDefaults: getDefaultsForSchema,
446
+ getDefaultsForExtension,
447
+ } = appiumSchema;
448
+
449
+ export const {isAllowedSchemaFileExtension} = AppiumSchema;