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
@@ -4,36 +4,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.isAllowedSchemaFileExtension = exports.getDefaultsForExtension = exports.getDefaultsForSchema = exports.flattenSchema = exports.getSchema = exports.validate = exports.resetSchema = exports.finalizeSchema = exports.isFinalized = exports.hasArgSpec = exports.getArgSpec = exports.getAllArgSpecs = exports.registerSchema = exports.SchemaUnsupportedSchemaError = exports.SchemaUnknownSchemaError = exports.SchemaNameConflictError = exports.SchemaFinalizationError = exports.ALLOWED_SCHEMA_EXTENSIONS = exports.RoachHotelMap = void 0;
7
- const ajv_1 = require("ajv");
7
+ const ajv_1 = __importDefault(require("ajv"));
8
8
  const ajv_formats_1 = __importDefault(require("ajv-formats"));
9
9
  const lodash_1 = __importDefault(require("lodash"));
10
10
  const node_path_1 = __importDefault(require("node:path"));
11
- const constants_1 = require("../constants");
12
11
  const schema_1 = require("@appium/schema");
12
+ const constants_1 = require("../constants");
13
13
  const arg_spec_1 = require("./arg-spec");
14
14
  const keywords_1 = require("./keywords");
15
15
  /**
16
16
  * Key/value pairs go in... but they don't come out.
17
- *
18
- * @template K,V
19
- * @extends {Map<K,V>}
20
17
  */
21
18
  class RoachHotelMap extends Map {
22
- /**
23
- * @param {K} key
24
- * @param {V} value
25
- */
26
19
  set(key, value) {
27
20
  if (this.has(key)) {
28
- throw new Error(`${key} is already set`);
21
+ throw new Error(`${String(key)} is already set`);
29
22
  }
30
23
  return super.set(key, value);
31
24
  }
32
- /**
33
- * @param {K} key
34
- */
35
25
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
36
- delete(key) {
26
+ delete(_key) {
37
27
  return false;
38
28
  }
39
29
  clear() {
@@ -41,66 +31,22 @@ class RoachHotelMap extends Map {
41
31
  }
42
32
  }
43
33
  exports.RoachHotelMap = RoachHotelMap;
44
- /**
45
- * Extensions that an extension schema file can have.
46
- */
47
- exports.ALLOWED_SCHEMA_EXTENSIONS = Object.freeze(new Set(/** @type {AllowedSchemaExtension[]} */ (['.json', '.js', '.cjs'])));
34
+ exports.ALLOWED_SCHEMA_EXTENSIONS = Object.freeze(new Set(['.json', '.js', '.cjs']));
48
35
  const SCHEMA_KEY = '$schema';
49
- /**
50
- * A wrapper around Ajv and schema-related functions.
51
- *
52
- * Should have been named Highlander, because _there can only be one_
53
- */
54
36
  class AppiumSchema {
55
- /**
56
- * A mapping of unique argument IDs to their corresponding {@link ArgSpec}s.
57
- *
58
- * An "argument" is a CLI argument or a config property.
59
- *
60
- * Used to provide easy lookups of argument metadata when converting between different representations of those arguments.
61
- * @type {RoachHotelMap<string,ArgSpec>}
62
- */
63
37
  #argSpecs = new RoachHotelMap();
64
- /**
65
- * A map of extension types to extension names to schema objects.
66
- *
67
- * This data structure is used to ensure there are no naming conflicts. The schemas
68
- * are stored here in memory until the instance is _finalized_.
69
- * @type {Record<ExtensionType,Map<string,SchemaObject>>}
70
- */
71
- #registeredSchemas = { [constants_1.DRIVER_TYPE]: new Map(), [constants_1.PLUGIN_TYPE]: new Map() };
72
- /**
73
- * Ajv instance
74
- *
75
- * @type {Ajv}
76
- */
38
+ #registeredSchemas = {
39
+ [constants_1.DRIVER_TYPE]: new Map(),
40
+ [constants_1.PLUGIN_TYPE]: new Map(),
41
+ };
77
42
  #ajv;
78
- /**
79
- * Singleton instance.
80
- * @type {AppiumSchema}
81
- */
82
43
  static #instance;
83
- /**
84
- * Lookup of schema IDs to finalized schemas.
85
- *
86
- * This does not include references, but rather the root schemas themselves.
87
- * @type {Record<string,StrictSchemaObject>?}
88
- */
89
44
  #finalizedSchemas = null;
90
- /**
91
- * Initializes Ajv, adds standard formats and our custom keywords.
92
- * @see https://npm.im/ajv-formats
93
- * @private
94
- */
95
45
  constructor() {
96
46
  this.#ajv = AppiumSchema._instantiateAjv();
97
47
  }
98
48
  /**
99
- * Factory function for {@link AppiumSchema} instances.
100
- *
101
- * Returns a singleton instance if one exists, otherwise creates a new one.
102
- * Binds public methods to the instance.
103
- * @returns {AppiumSchema}
49
+ * Returns a singleton instance.
104
50
  */
105
51
  static create() {
106
52
  if (!AppiumSchema.#instance) {
@@ -125,97 +71,57 @@ class AppiumSchema {
125
71
  return AppiumSchema.#instance;
126
72
  }
127
73
  /**
128
- * Returns `true` if a schema has been registered using given extension type and name.
129
- *
130
- * This does not depend on whether or not the instance has been _finalized_.
131
- * @param {ExtensionType} extType - Extension type
132
- * @param {string} extName - Name
133
- * @returns {boolean} If registered
74
+ * Returns `true` if a schema has been registered for extension type/name.
134
75
  */
135
76
  hasRegisteredSchema(extType, extName) {
136
77
  return this.#registeredSchemas[extType].has(extName);
137
78
  }
138
79
  /**
139
- * Return `true` if {@link AppiumSchema.finalize finalize} has been called
140
- * successfully and {@link AppiumSchema.reset reset} has not been called since.
141
- * @returns {boolean} If finalized
80
+ * Returns `true` if this instance has been finalized.
142
81
  */
143
82
  isFinalized() {
144
83
  return Boolean(this.#finalizedSchemas);
145
84
  }
85
+ /**
86
+ * Returns map of known argument specs.
87
+ */
146
88
  getAllArgSpecs() {
147
89
  return this.#argSpecs;
148
90
  }
149
91
  /**
150
- * Call this when no more schemas will be registered.
151
- *
152
- * This does three things:
153
- * 1. It combines all schemas from extensions into the Appium config schema,
154
- * then adds the result to the `Ajv` instance.
155
- * 2. It adds schemas for _each_ argument/property for validation purposes.
156
- * The CLI uses these schemas to validate specific arguments.
157
- * 3. The schemas are validated against JSON schema draft-07 (which is the
158
- * only one supported at this time)
159
- *
160
- * Any method in this instance that needs to interact with the `Ajv` instance
161
- * will throw if this method has not been called.
162
- *
163
- * If the instance has already been finalized, this is a no-op.
164
- * @public
165
- * @throws {Error} If the schema is not valid
166
- * @returns {Readonly<Record<string,StrictSchemaObject>>} Record of schema IDs to full schema objects
92
+ * Finalizes all registered schemas into Ajv and generates arg-spec lookups.
167
93
  */
168
94
  finalize() {
169
95
  if (this.isFinalized()) {
170
- return /** @type {Record<string,StrictSchemaObject>} */ (this.#finalizedSchemas);
96
+ return this.#finalizedSchemas;
171
97
  }
172
98
  const ajv = this.#ajv;
173
- // Ajv will _mutate_ the schema, so we need to clone it.
174
99
  const baseSchema = lodash_1.default.cloneDeep(schema_1.AppiumConfigJsonSchema);
175
- /**
176
- *
177
- * @param {SchemaObject} schema
178
- * @param {ExtensionType} [extType]
179
- * @param {string} [extName]
180
- */
181
100
  const addArgSpecs = (schema, extType, extName) => {
182
- for (let [propName, propSchema] of Object.entries(schema)) {
101
+ for (const [propName, propSchema] of Object.entries(schema)) {
183
102
  const argSpec = arg_spec_1.ArgSpec.create(propName, {
184
103
  dest: propSchema.appiumCliDest,
185
104
  defaultValue: propSchema.default,
186
105
  extType,
187
106
  extName,
188
107
  });
189
- const { arg } = argSpec;
190
- this.#argSpecs.set(arg, argSpec);
108
+ this.#argSpecs.set(argSpec.arg, argSpec);
191
109
  }
192
110
  };
193
111
  addArgSpecs(lodash_1.default.omit(baseSchema.properties.server.properties, [constants_1.DRIVER_TYPE, constants_1.PLUGIN_TYPE]));
194
- /**
195
- * @type {Record<string,StrictSchemaObject>}
196
- */
197
112
  const finalizedSchemas = {};
198
- const finalSchema = lodash_1.default.reduce(this.#registeredSchemas,
199
- /**
200
- * @param {typeof baseSchema} baseSchema
201
- * @param {Map<string,SchemaObject>} extensionSchemas
202
- * @param {ExtensionType} extType
203
- */
204
- (baseSchema, extensionSchemas, extType) => {
113
+ const finalSchema = lodash_1.default.reduce(this.#registeredSchemas, (base, extensionSchemas, extType) => {
205
114
  extensionSchemas.forEach((schema, extName) => {
206
115
  const $ref = arg_spec_1.ArgSpec.toSchemaBaseRef(extType, extName);
207
116
  schema.$id = $ref;
208
- schema.additionalProperties = false; // this makes `schema` become a `StrictSchemaObject`
209
- baseSchema.properties.server.properties[extType].properties[extName] = {
210
- $ref,
211
- $comment: extName,
212
- };
117
+ schema.additionalProperties = false;
118
+ base.properties.server.properties[extType].properties[extName] = { $ref, $comment: extName };
213
119
  ajv.validateSchema(schema, true);
214
120
  addArgSpecs(schema.properties, extType, extName);
215
121
  ajv.addSchema(schema, $ref);
216
- finalizedSchemas[$ref] = /** @type {StrictSchemaObject} */ (schema);
122
+ finalizedSchemas[$ref] = schema;
217
123
  });
218
- return baseSchema;
124
+ return base;
219
125
  }, baseSchema);
220
126
  ajv.addSchema(finalSchema, arg_spec_1.APPIUM_CONFIG_SCHEMA_ID);
221
127
  finalizedSchemas[arg_spec_1.APPIUM_CONFIG_SCHEMA_ID] = finalSchema;
@@ -224,56 +130,19 @@ class AppiumSchema {
224
130
  return Object.freeze(finalizedSchemas);
225
131
  }
226
132
  /**
227
- * Configures and creates an Ajv instance.
228
- * @private
229
- * @returns {Ajv}
230
- */
231
- static _instantiateAjv() {
232
- const ajv = (0, ajv_formats_1.default)(new ajv_1.Ajv({
233
- // without this not much validation actually happens
234
- allErrors: true,
235
- }));
236
- // add custom keywords to ajv. see schema-keywords.js
237
- lodash_1.default.forEach(keywords_1.keywords, (keyword) => {
238
- ajv.addKeyword(keyword);
239
- });
240
- return ajv;
241
- }
242
- /**
243
- * Resets this instance to its original state.
244
- *
245
- * - Removes all added schemas from the `Ajv` instance
246
- * - Resets the map of {@link ArgSpec ArgSpecs}
247
- * - Resets the map of registered schemas
248
- * - Sets the {@link AppiumSchema._finalized _finalized} flag to `false`
249
- *
250
- * If you need to call {@link AppiumSchema.finalize} again, you'll want to call this first.
251
- * @returns {void}
133
+ * Resets this instance to initial state.
252
134
  */
253
135
  reset() {
254
136
  for (const schemaId of Object.keys(this.#finalizedSchemas ?? {})) {
255
137
  this.#ajv.removeSchema(schemaId);
256
138
  }
257
139
  this.#argSpecs = new RoachHotelMap();
258
- this.#registeredSchemas = {
259
- [constants_1.DRIVER_TYPE]: new Map(),
260
- [constants_1.PLUGIN_TYPE]: new Map(),
261
- };
140
+ this.#registeredSchemas = { [constants_1.DRIVER_TYPE]: new Map(), [constants_1.PLUGIN_TYPE]: new Map() };
262
141
  this.#finalizedSchemas = null;
263
- // Ajv seems to have an over-eager cache, so we have to dump the object entirely.
264
142
  this.#ajv = AppiumSchema._instantiateAjv();
265
143
  }
266
144
  /**
267
- * Registers a schema from an extension.
268
- *
269
- * This is "fail-fast" in that the schema will immediately be validated against JSON schema draft-07 _or_ whatever the value of the schema's `$schema` prop is.
270
- *
271
- * Does _not_ add the schema to the `ajv` instance (this is done by {@link AppiumSchema.finalize}).
272
- * @param {ExtensionType} extType - Extension type
273
- * @param {string} extName - Unique extension name for `type`
274
- * @param {SchemaObject} schema - Schema object
275
- * @throws {SchemaNameConflictError} If the schema is an invalid
276
- * @returns {void}
145
+ * Registers an extension schema.
277
146
  */
278
147
  registerSchema(extType, extName, schema) {
279
148
  if (!(extType && extName) || lodash_1.default.isUndefined(schema)) {
@@ -293,49 +162,24 @@ class AppiumSchema {
293
162
  this.#registeredSchemas[extType].set(normalizedExtName, schema);
294
163
  }
295
164
  /**
296
- * Returns a {@link ArgSpec} for the given argument name.
297
- * @param {string} name - CLI argument name
298
- * @param {ExtensionType} [extType] - Extension type
299
- * @param {string} [extName] - Extension name
300
- * @returns {ArgSpec|undefined} ArgSpec or `undefined` if not found
165
+ * Returns an `ArgSpec` for argument name/ext context, if present.
301
166
  */
302
167
  getArgSpec(name, extType, extName) {
303
168
  return this.#argSpecs.get(arg_spec_1.ArgSpec.toArg(name, extType, extName));
304
169
  }
305
170
  /**
306
- * Returns `true` if the instance knows about an argument by the given `name`.
307
- * @param {string} name - CLI argument name
308
- * @param {ExtensionType} [extType] - Extension type
309
- * @param {string} [extName] - Extension name
310
- * @returns {boolean} `true` if such an {@link ArgSpec} exists
171
+ * Returns `true` if an `ArgSpec` exists for argument name/ext context.
311
172
  */
312
173
  hasArgSpec(name, extType, extName) {
313
174
  return this.#argSpecs.has(arg_spec_1.ArgSpec.toArg(name, extType, extName));
314
175
  }
315
176
  /**
316
- * Returns a `Record` of argument "dest" strings to default values.
317
- *
318
- * The "dest" string is the property name in object returned by
319
- * `argparse.ArgumentParser['parse_args']`.
320
- * @template {boolean|undefined} Flattened
321
- * @param {Flattened} [flatten=true] - If `true`, flattens the returned object
322
- * using "keypath"-style keys of the format `<extType>.<extName>.<argName>`.
323
- * Otherwise, returns a nested object using `extType` and `extName` as
324
- * properties. Base arguments (server arguments) are always at the top level.
325
- * @returns {DefaultValues<Flattened>}
177
+ * Returns default values for all args, flattened or nested.
326
178
  */
327
- getDefaults(flatten = /** @type {Flattened} */ (true)) {
179
+ getDefaults(flatten = true) {
328
180
  if (!this.isFinalized()) {
329
181
  throw new SchemaFinalizationError();
330
182
  }
331
- /**
332
- * @private
333
- * @callback DefaultReducer
334
- * @param {DefaultValues<Flattened>} defaults
335
- * @param {ArgSpec} argSpec
336
- * @returns {DefaultValues<Flattened>}
337
- */
338
- /** @type {DefaultReducer} */
339
183
  const reducer = flatten
340
184
  ? (defaults, { defaultValue, dest }) => {
341
185
  if (!lodash_1.default.isUndefined(defaultValue)) {
@@ -349,16 +193,11 @@ class AppiumSchema {
349
193
  }
350
194
  return defaults;
351
195
  };
352
- /** @type {DefaultValues<Flattened>} */
353
196
  const retval = {};
354
197
  return [...this.#argSpecs.values()].reduce(reducer, retval);
355
198
  }
356
199
  /**
357
- * Returns a flattened Record of defaults for a specific extension. Keys will
358
- * be of format `<argName>`.
359
- * @param {ExtensionType} extType - Extension type
360
- * @param {string} extName - Extension name
361
- * @returns {Record<string,ArgSpecDefaultValue>}
200
+ * Returns flattened defaults for a specific extension.
362
201
  */
363
202
  getDefaultsForExtension(extType, extName) {
364
203
  if (!this.isFinalized()) {
@@ -373,27 +212,14 @@ class AppiumSchema {
373
212
  }, {});
374
213
  }
375
214
  /**
376
- * Flatten schema into an array of `SchemaObject`s and associated
377
- * {@link ArgSpec ArgSpecs}.
378
- *
379
- * Converts nested extension schemas to keys based on the extension type and
380
- * name. Used when translating to `argparse` options or getting the list of
381
- * default values (see {@link AppiumSchema.getDefaults}) for CLI or otherwise.
382
- *
383
- * The return value is an intermediate representation used by `cli-args`
384
- * module's `toParserArgs`, which converts the finalized schema to parameters
385
- * used by `argparse`.
386
- * @throws If {@link AppiumSchema.finalize} has not been called yet.
387
- * @returns {FlattenedSchema}
215
+ * Flattens finalized schemas into schema + argSpec tuples.
388
216
  */
389
217
  flatten() {
390
218
  const schema = this.getSchema();
391
- /** @type { {properties: SchemaObject, prefix: string[]}[] } */
392
- const stack = [{ properties: schema.properties, prefix: [] }];
393
- /** @type {FlattenedSchema} */
219
+ const stack = [
220
+ { properties: schema.properties, prefix: [] },
221
+ ];
394
222
  const flattened = [];
395
- // this bit is a recursive algorithm rewritten as a for loop.
396
- // when we find something we want to traverse, we add it to `stack`
397
223
  for (const { properties, prefix } of stack) {
398
224
  const pairs = lodash_1.default.toPairs(properties);
399
225
  for (const [key, value] of pairs) {
@@ -402,10 +228,7 @@ class AppiumSchema {
402
228
  }
403
229
  const { properties, $ref } = value;
404
230
  if (properties) {
405
- stack.push({
406
- properties,
407
- prefix: key === arg_spec_1.SERVER_PROP_NAME ? [] : [...prefix, key],
408
- });
231
+ stack.push({ properties, prefix: key === arg_spec_1.SERVER_PROP_NAME ? [] : [...prefix, key] });
409
232
  }
410
233
  else if ($ref) {
411
234
  let refSchema;
@@ -413,24 +236,18 @@ class AppiumSchema {
413
236
  refSchema = this.getSchema($ref);
414
237
  }
415
238
  catch {
416
- // this can happen if an extension schema supplies a $ref to a non-existent schema
417
239
  throw new SchemaUnknownSchemaError($ref);
418
240
  }
419
241
  const { normalizedExtName } = arg_spec_1.ArgSpec.extensionInfoFromRootSchemaId($ref);
420
242
  if (!normalizedExtName) {
421
- /* istanbul ignore next */
422
243
  throw new ReferenceError(`Could not determine extension name from schema ID ${$ref}. This is a bug.`);
423
244
  }
424
- stack.push({
425
- properties: refSchema.properties,
426
- prefix: [...prefix, key, normalizedExtName],
427
- });
245
+ stack.push({ properties: refSchema.properties, prefix: [...prefix, key, normalizedExtName] });
428
246
  }
429
247
  else if (key !== constants_1.DRIVER_TYPE && key !== constants_1.PLUGIN_TYPE) {
430
248
  const [extType, extName] = prefix;
431
- const argSpec = this.getArgSpec(key, /** @type {ExtensionType} */ (extType), extName);
249
+ const argSpec = this.getArgSpec(key, extType, extName);
432
250
  if (!argSpec) {
433
- /* istanbul ignore next */
434
251
  throw new ReferenceError(`Unknown argument with key ${key}, extType ${extType} and extName ${extName}. This is a bug.`);
435
252
  }
436
253
  flattened.push({ schema: lodash_1.default.cloneDeep(value), argSpec });
@@ -440,71 +257,58 @@ class AppiumSchema {
440
257
  return flattened;
441
258
  }
442
259
  /**
443
- * Retrieves the schema itself
444
- * @public
445
- * @param {string} [ref] - Schema ID
446
- * @throws If the schema has not yet been finalized
447
- * @returns {SchemaObject}
260
+ * Returns schema by ID (default: base Appium schema).
448
261
  */
449
262
  getSchema(ref = arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
450
- return /** @type {SchemaObject} */ (this._getValidator(ref).schema);
451
- }
452
- /**
453
- * Retrieves schema validator function from Ajv
454
- * @param {string} [id] - Schema ID
455
- * @private
456
- * @returns {import('ajv').ValidateFunction}
457
- */
458
- _getValidator(id = arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
459
- const validator = this.#ajv.getSchema(id);
460
- if (!validator) {
461
- if (id === arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
462
- throw new SchemaFinalizationError();
463
- }
464
- else {
465
- throw new SchemaUnknownSchemaError(id);
466
- }
467
- }
468
- return validator;
263
+ return this._getValidator(ref).schema;
469
264
  }
470
265
  /**
471
- * Given an object, validates it against the Appium config schema.
472
- * If errors occur, the returned array will be non-empty.
473
- * @param {any} value - The value (hopefully an object) to validate against the schema
474
- * @param {string} [ref] - Schema ID or ref.
475
- * @public
476
- * @returns {import('ajv').ErrorObject[]} Array of errors, if any.
266
+ * Validates a value against schema by ID/reference.
477
267
  */
478
268
  validate(value, ref = arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
479
269
  const validator = this._getValidator(ref);
480
270
  return !validator(value) && lodash_1.default.isArray(validator.errors) ? [...validator.errors] : [];
481
271
  }
482
272
  /**
483
- * Returns `true` if `filename`'s file extension is allowed (in {@link ALLOWED_SCHEMA_EXTENSIONS}).
484
- * @param {import('type-fest').LiteralUnion<AllowedSchemaExtension, string>} filename
485
- * @returns {boolean}
273
+ * Returns `true` if filename extension is an allowed schema extension.
486
274
  */
487
275
  static isAllowedSchemaFileExtension(filename) {
488
- return exports.ALLOWED_SCHEMA_EXTENSIONS.has(
489
- /** @type {AllowedSchemaExtension} */ (node_path_1.default.extname(filename)));
276
+ return exports.ALLOWED_SCHEMA_EXTENSIONS.has(node_path_1.default.extname(filename));
490
277
  }
491
278
  /**
492
- * Returns `true` if `schema` is a plain object with a non-true `$async` property.
493
- * @param {any} schema - Schema to check
494
- * @returns {schema is SchemaObject}
279
+ * Returns `true` if schema is a plain object and not async.
495
280
  */
496
281
  static isSupportedSchemaType(schema) {
497
282
  return lodash_1.default.isPlainObject(schema) && schema.$async !== true;
498
283
  }
499
- }
500
- /**
501
- * Thrown when the {@link AppiumSchema} instance has not yet been finalized, but
502
- * the method called requires it.
503
- */
504
- class SchemaFinalizationError extends Error {
505
284
  /**
506
- * @type {Readonly<string>}
285
+ * Configures and creates an Ajv instance.
286
+ */
287
+ static _instantiateAjv() {
288
+ const ajv = (0, ajv_formats_1.default)(new ajv_1.default({
289
+ // without this not much validation actually happens
290
+ allErrors: true,
291
+ }));
292
+ lodash_1.default.forEach(keywords_1.keywords, (keyword) => {
293
+ ajv.addKeyword(keyword);
294
+ });
295
+ return ajv;
296
+ }
297
+ /**
298
+ * Retrieves schema validator function from Ajv.
507
299
  */
300
+ _getValidator(id = arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
301
+ const validator = this.#ajv.getSchema(id);
302
+ if (!validator) {
303
+ if (id === arg_spec_1.APPIUM_CONFIG_SCHEMA_ID) {
304
+ throw new SchemaFinalizationError();
305
+ }
306
+ throw new SchemaUnknownSchemaError(id);
307
+ }
308
+ return validator;
309
+ }
310
+ }
311
+ class SchemaFinalizationError extends Error {
508
312
  code = 'APPIUMERR_SCHEMA_FINALIZATION';
509
313
  constructor() {
510
314
  super('Schema not yet finalized; `finalize()` must be called first.');
@@ -512,23 +316,11 @@ class SchemaFinalizationError extends Error {
512
316
  }
513
317
  exports.SchemaFinalizationError = SchemaFinalizationError;
514
318
  /**
515
- * Thrown when a "unique" schema ID conflicts with an existing schema ID.
516
- *
517
- * This is likely going to be caused by attempting to register the same schema twice.
319
+ * Thrown when a unique extension schema name conflicts with an existing one.
518
320
  */
519
321
  class SchemaNameConflictError extends Error {
520
- /**
521
- * @type {Readonly<string>}
522
- */
523
322
  code = 'APPIUMERR_SCHEMA_NAME_CONFLICT';
524
- /**
525
- * @type {Readonly<{extType: ExtensionType, extName: string}>}
526
- */
527
323
  data;
528
- /**
529
- * @param {ExtensionType} extType
530
- * @param {string} extName
531
- */
532
324
  constructor(extType, extName) {
533
325
  super(`Name for ${extType} schema "${extName}" conflicts with an existing schema`);
534
326
  this.data = { extType, extName };
@@ -536,20 +328,11 @@ class SchemaNameConflictError extends Error {
536
328
  }
537
329
  exports.SchemaNameConflictError = SchemaNameConflictError;
538
330
  /**
539
- * Thrown when a schema ID was expected, but it doesn't exist on the {@link Ajv} instance.
331
+ * Thrown when requested schema ID is unknown to Ajv.
540
332
  */
541
333
  class SchemaUnknownSchemaError extends ReferenceError {
542
- /**
543
- * @type {Readonly<string>}
544
- */
545
334
  code = 'APPIUMERR_SCHEMA_UNKNOWN_SCHEMA';
546
- /**
547
- * @type {Readonly<{schemaId: string}>}
548
- */
549
335
  data;
550
- /**
551
- * @param {string} schemaId
552
- */
553
336
  constructor(schemaId) {
554
337
  super(`Unknown schema: "${schemaId}"`);
555
338
  this.data = { schemaId };
@@ -557,29 +340,14 @@ class SchemaUnknownSchemaError extends ReferenceError {
557
340
  }
558
341
  exports.SchemaUnknownSchemaError = SchemaUnknownSchemaError;
559
342
  /**
560
- * Thrown when a schema is provided, but it's of an unsupported type.
561
- *
562
- * "Valid" schemas which are unsupported include boolean schemas and async schemas
563
- * (having a `true` `$async` property).
343
+ * Thrown when provided schema type is unsupported (boolean/async/non-object).
564
344
  */
565
345
  class SchemaUnsupportedSchemaError extends TypeError {
566
- /**
567
- * @type {Readonly<string>}
568
- */
569
346
  code = 'APPIUMERR_SCHEMA_UNSUPPORTED_SCHEMA';
570
- /**
571
- * @type {Readonly<{schema: any, extType: ExtensionType, extName: string}>}
572
- */
573
347
  data;
574
- /**
575
- * @param {any} schema
576
- * @param {ExtensionType} extType
577
- * @param {string} extName
578
- */
579
348
  constructor(schema, extType, extName) {
580
- // https://github.com/Microsoft/TypeScript/issues/8277
581
349
  super((() => {
582
- let msg = `Unsupported schema from ${extType} "${extName}":`;
350
+ const msg = `Unsupported schema from ${extType} "${extName}":`;
583
351
  if (lodash_1.default.isBoolean(schema)) {
584
352
  return `${msg} schema cannot be a boolean`;
585
353
  }
@@ -587,7 +355,6 @@ class SchemaUnsupportedSchemaError extends TypeError {
587
355
  if (schema.$async) {
588
356
  return `${msg} schema cannot be an async schema`;
589
357
  }
590
- /* istanbul ignore next */
591
358
  throw new TypeError(`schema IS supported; this error should not be thrown (this is a bug). value of schema: ${JSON.stringify(schema)}`);
592
359
  }
593
360
  return `${msg} schema must be a plain object without a true "$async" property`;
@@ -599,41 +366,4 @@ exports.SchemaUnsupportedSchemaError = SchemaUnsupportedSchemaError;
599
366
  const appiumSchema = AppiumSchema.create();
600
367
  exports.registerSchema = appiumSchema.registerSchema, exports.getAllArgSpecs = appiumSchema.getAllArgSpecs, exports.getArgSpec = appiumSchema.getArgSpec, exports.hasArgSpec = appiumSchema.hasArgSpec, exports.isFinalized = appiumSchema.isFinalized, exports.finalizeSchema = appiumSchema.finalize, exports.resetSchema = appiumSchema.reset, exports.validate = appiumSchema.validate, exports.getSchema = appiumSchema.getSchema, exports.flattenSchema = appiumSchema.flatten, exports.getDefaultsForSchema = appiumSchema.getDefaults, exports.getDefaultsForExtension = appiumSchema.getDefaultsForExtension;
601
368
  exports.isAllowedSchemaFileExtension = AppiumSchema.isAllowedSchemaFileExtension;
602
- /**
603
- * Appium only supports schemas that are plain objects; not arrays.
604
- * @typedef {import('ajv').SchemaObject & {[key: number]: never}} SchemaObject
605
- */
606
- /**
607
- * @typedef {import('@appium/types').ExtensionType} ExtensionType
608
- */
609
- /**
610
- * An object having property `additionalProperties: false`
611
- * @typedef StrictProp
612
- * @property {false} additionalProperties
613
- */
614
- /**
615
- * A {@link SchemaObject} with `additionalProperties: false`
616
- * @typedef {SchemaObject & StrictProp} StrictSchemaObject
617
- */
618
- /**
619
- * A list of schemas associated with properties and their corresponding {@link ArgSpec} objects.
620
- *
621
- * Intermediate data structure used when converting the entire schema down to CLI arguments.
622
- * @typedef { {schema: SchemaObject, argSpec: ArgSpec}[] } FlattenedSchema
623
- */
624
- /**
625
- * @typedef {ArgSpec['defaultValue']} ArgSpecDefaultValue
626
- */
627
- /**
628
- * e.g. `{driver: {foo: 'bar'}}` where `foo` is the arg name and `bar` is the default value.
629
- * @typedef {Record<string,Record<string,ArgSpecDefaultValue>>} NestedArgSpecDefaultValue
630
- */
631
- /**
632
- * Helper type for the return value of {@link AppiumSchema.getDefaults}
633
- * @template {boolean|undefined} Flattened
634
- * @typedef {Record<string,Flattened extends true ? ArgSpecDefaultValue : ArgSpecDefaultValue | NestedArgSpecDefaultValue>} DefaultValues
635
- */
636
- /**
637
- * @typedef {'.json'|'.js'|'.cjs'} AllowedSchemaExtension
638
- */
639
369
  //# sourceMappingURL=schema.js.map