appium 2.0.0-beta.3 → 2.0.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -11
- package/build/lib/appium.d.ts +215 -0
- package/build/lib/appium.d.ts.map +1 -0
- package/build/lib/appium.js +241 -132
- package/build/lib/cli/args.d.ts +20 -0
- package/build/lib/cli/args.d.ts.map +1 -0
- package/build/lib/cli/args.js +96 -282
- package/build/lib/cli/driver-command.d.ts +36 -0
- package/build/lib/cli/driver-command.d.ts.map +1 -0
- package/build/lib/cli/driver-command.js +19 -12
- package/build/lib/cli/extension-command.d.ts +345 -0
- package/build/lib/cli/extension-command.d.ts.map +1 -0
- package/build/lib/cli/extension-command.js +171 -96
- package/build/lib/cli/extension.d.ts +14 -0
- package/build/lib/cli/extension.d.ts.map +1 -0
- package/build/lib/cli/extension.js +31 -16
- package/build/lib/cli/parser.d.ts +80 -0
- package/build/lib/cli/parser.d.ts.map +1 -0
- package/build/lib/cli/parser.js +152 -95
- package/build/lib/cli/plugin-command.d.ts +39 -0
- package/build/lib/cli/plugin-command.d.ts.map +1 -0
- package/build/lib/cli/plugin-command.js +18 -13
- package/build/lib/cli/utils.d.ts +29 -0
- package/build/lib/cli/utils.d.ts.map +1 -0
- package/build/lib/cli/utils.js +27 -3
- package/build/lib/config-file.d.ts +100 -0
- package/build/lib/config-file.d.ts.map +1 -0
- package/build/lib/config-file.js +136 -0
- package/build/lib/config.d.ts +41 -0
- package/build/lib/config.d.ts.map +1 -0
- package/build/lib/config.js +92 -67
- package/build/lib/constants.d.ts +48 -0
- package/build/lib/constants.d.ts.map +1 -0
- package/build/lib/constants.js +60 -0
- package/build/lib/extension/driver-config.d.ts +84 -0
- package/build/lib/extension/driver-config.d.ts.map +1 -0
- package/build/lib/extension/driver-config.js +190 -0
- package/build/lib/extension/extension-config.d.ts +170 -0
- package/build/lib/extension/extension-config.d.ts.map +1 -0
- package/build/lib/extension/extension-config.js +297 -0
- package/build/lib/extension/index.d.ts +39 -0
- package/build/lib/extension/index.d.ts.map +1 -0
- package/build/lib/extension/index.js +77 -0
- package/build/lib/extension/manifest.d.ts +174 -0
- package/build/lib/extension/manifest.d.ts.map +1 -0
- package/build/lib/extension/manifest.js +246 -0
- package/build/lib/extension/package-changed.d.ts +11 -0
- package/build/lib/extension/package-changed.d.ts.map +1 -0
- package/build/lib/extension/package-changed.js +68 -0
- package/build/lib/extension/plugin-config.d.ts +62 -0
- package/build/lib/extension/plugin-config.d.ts.map +1 -0
- package/build/lib/extension/plugin-config.js +87 -0
- package/build/lib/grid-register.d.ts +10 -0
- package/build/lib/grid-register.d.ts.map +1 -0
- package/build/lib/grid-register.js +21 -25
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +4 -6
- package/build/lib/logsink.d.ts +4 -0
- package/build/lib/logsink.d.ts.map +1 -0
- package/build/lib/logsink.js +12 -16
- package/build/lib/main.d.ts +54 -0
- package/build/lib/main.d.ts.map +1 -0
- package/build/lib/main.js +189 -90
- package/build/lib/schema/arg-spec.d.ts +143 -0
- package/build/lib/schema/arg-spec.d.ts.map +1 -0
- package/build/lib/schema/arg-spec.js +119 -0
- package/build/lib/schema/cli-args.d.ts +19 -0
- package/build/lib/schema/cli-args.d.ts.map +1 -0
- package/build/lib/schema/cli-args.js +180 -0
- package/build/lib/schema/cli-transformers.d.ts +5 -0
- package/build/lib/schema/cli-transformers.d.ts.map +1 -0
- package/build/lib/schema/cli-transformers.js +74 -0
- package/build/lib/schema/index.d.ts +3 -0
- package/build/lib/schema/index.d.ts.map +1 -0
- package/build/lib/schema/index.js +34 -0
- package/build/lib/schema/keywords.d.ts +24 -0
- package/build/lib/schema/keywords.d.ts.map +1 -0
- package/build/lib/schema/keywords.js +70 -0
- package/build/lib/schema/schema.d.ts +259 -0
- package/build/lib/schema/schema.d.ts.map +1 -0
- package/build/lib/schema/schema.js +452 -0
- package/build/lib/utils.d.ts +66 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +35 -139
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/types/appium-manifest.d.ts +40 -0
- package/build/types/appium-manifest.d.ts.map +1 -0
- package/build/types/cli.d.ts +112 -0
- package/build/types/cli.d.ts.map +1 -0
- package/build/types/extension.d.ts +43 -0
- package/build/types/extension.d.ts.map +1 -0
- package/build/types/external-manifest.d.ts +47 -0
- package/build/types/external-manifest.d.ts.map +1 -0
- package/build/types/index.d.ts +15 -0
- package/build/types/index.d.ts.map +1 -0
- package/index.js +11 -0
- package/lib/appium-config.schema.json +278 -0
- package/lib/appium.js +402 -155
- package/lib/cli/args.js +174 -377
- package/lib/cli/driver-command.js +22 -7
- package/lib/cli/extension-command.js +372 -177
- package/lib/cli/extension.js +32 -10
- package/lib/cli/parser.js +253 -83
- package/lib/cli/plugin-command.js +19 -6
- package/lib/cli/utils.js +22 -2
- package/lib/config-file.js +223 -0
- package/lib/config.js +170 -69
- package/lib/constants.js +78 -0
- package/lib/extension/driver-config.js +249 -0
- package/lib/extension/extension-config.js +458 -0
- package/lib/extension/index.js +102 -0
- package/lib/extension/manifest.js +484 -0
- package/lib/extension/package-changed.js +63 -0
- package/lib/extension/plugin-config.js +113 -0
- package/lib/grid-register.js +25 -22
- package/lib/logger.js +1 -1
- package/lib/logsink.js +14 -7
- package/lib/main.js +255 -90
- package/lib/schema/arg-spec.js +232 -0
- package/lib/schema/cli-args.js +261 -0
- package/lib/schema/cli-transformers.js +122 -0
- package/lib/schema/index.js +2 -0
- package/lib/schema/keywords.js +134 -0
- package/lib/schema/schema.js +734 -0
- package/lib/utils.js +85 -129
- package/package.json +68 -85
- package/scripts/postinstall.js +71 -0
- package/types/appium-manifest.ts +61 -0
- package/types/cli.ts +153 -0
- package/types/extension.ts +56 -0
- package/types/external-manifest.ts +58 -0
- package/types/index.ts +14 -0
- package/CHANGELOG.md +0 -3515
- package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
- package/build/lib/cli/npm.js +0 -206
- package/build/lib/cli/parser-helpers.js +0 -82
- package/build/lib/driver-config.js +0 -77
- package/build/lib/drivers.js +0 -96
- package/build/lib/extension-config.js +0 -251
- package/build/lib/plugin-config.js +0 -59
- package/build/lib/plugins.js +0 -14
- package/lib/cli/npm.js +0 -183
- package/lib/cli/parser-helpers.js +0 -79
- package/lib/driver-config.js +0 -46
- package/lib/drivers.js +0 -81
- package/lib/extension-config.js +0 -208
- package/lib/plugin-config.js +0 -34
- package/lib/plugins.js +0 -10
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
|
|
2
|
+
import {ArgumentTypeError} from 'argparse';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import {formatErrors as formatErrors} from '../config-file';
|
|
5
|
+
import {flattenSchema, validate} from './schema';
|
|
6
|
+
import {transformers} from './cli-transformers';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* This module concerns functions which convert schema definitions to
|
|
10
|
+
* `argparse`-compatible data structures, for deriving CLI arguments from a
|
|
11
|
+
* schema.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lookup of possible values for the `type` field in a JSON schema.
|
|
16
|
+
* @type {Readonly<Record<string, import('json-schema').JSONSchema7TypeName>>}
|
|
17
|
+
*/
|
|
18
|
+
const TYPENAMES = Object.freeze({
|
|
19
|
+
ARRAY: 'array',
|
|
20
|
+
OBJECT: 'object',
|
|
21
|
+
BOOLEAN: 'boolean',
|
|
22
|
+
INTEGER: 'integer',
|
|
23
|
+
NUMBER: 'number',
|
|
24
|
+
NULL: 'null',
|
|
25
|
+
STRING: 'string',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Options with alias lengths less than this will be considered "short" flags.
|
|
30
|
+
*/
|
|
31
|
+
const SHORT_ARG_CUTOFF = 3;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Convert an alias (`foo`) to a flag (`--foo`) or a short flag (`-f`).
|
|
35
|
+
* @param {ArgSpec} argSpec - the argument specification
|
|
36
|
+
* @param {string} [alias] - the alias to convert to a flag
|
|
37
|
+
* @returns {string} the flag
|
|
38
|
+
*/
|
|
39
|
+
function aliasToFlag (argSpec, alias) {
|
|
40
|
+
const {extType, extName, name} = argSpec;
|
|
41
|
+
const arg = alias ?? name;
|
|
42
|
+
const isShort = arg.length < SHORT_ARG_CUTOFF;
|
|
43
|
+
if (extType && extName) {
|
|
44
|
+
return isShort
|
|
45
|
+
? `--${extType}-${_.kebabCase(extName)}-${arg}`
|
|
46
|
+
: `--${extType}-${_.kebabCase(extName)}-${_.kebabCase(arg)}`;
|
|
47
|
+
}
|
|
48
|
+
return isShort ? `-${arg}` : `--${_.kebabCase(arg)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Converts a string to SCREAMING_SNAKE_CASE
|
|
53
|
+
*/
|
|
54
|
+
const screamingSnakeCase = _.flow(_.snakeCase, _.toUpper);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Given unique property name `name`, return a function which validates a value
|
|
58
|
+
* against a property within the schema.
|
|
59
|
+
* @template Coerced
|
|
60
|
+
* @param {ArgSpec} argSpec - Argument name
|
|
61
|
+
* @param {(value: string) => Coerced} [coerce] - Function to coerce to a different
|
|
62
|
+
* primitive
|
|
63
|
+
* @todo See if we can remove `coerce` by allowing Ajv to coerce in its
|
|
64
|
+
* constructor options
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
function getSchemaValidator ({ref: schemaId}, coerce = _.identity) {
|
|
68
|
+
/** @param {string} value */
|
|
69
|
+
return (value) => {
|
|
70
|
+
const coerced = coerce(value);
|
|
71
|
+
const errors = validate(coerced, schemaId);
|
|
72
|
+
if (_.isEmpty(errors)) {
|
|
73
|
+
return coerced;
|
|
74
|
+
}
|
|
75
|
+
throw new ArgumentTypeError(
|
|
76
|
+
'\n\n' + formatErrors(errors, value, {schemaId}),
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Determine the description for display on the CLI, given the schema.
|
|
83
|
+
* @param {AppiumJSONSchema} schema
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
function makeDescription (schema) {
|
|
87
|
+
const {appiumCliDescription, description = '', appiumDeprecated} = schema;
|
|
88
|
+
let desc = appiumCliDescription ?? description;
|
|
89
|
+
if (appiumDeprecated) {
|
|
90
|
+
desc = `[DEPRECATED] ${desc}`;
|
|
91
|
+
}
|
|
92
|
+
return desc;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Given arg `name`, a JSON schema `subSchema`, and options, return an argument definition
|
|
97
|
+
* as understood by `argparse`.
|
|
98
|
+
* @param {AppiumJSONSchema} subSchema - JSON schema for the option
|
|
99
|
+
* @param {ArgSpec} argSpec - Argument spec tuple
|
|
100
|
+
* @returns {[string[], import('argparse').ArgumentOptions]} Tuple of flag and options
|
|
101
|
+
*/
|
|
102
|
+
function subSchemaToArgDef (subSchema, argSpec) {
|
|
103
|
+
let {
|
|
104
|
+
type,
|
|
105
|
+
appiumCliAliases,
|
|
106
|
+
appiumCliTransformer,
|
|
107
|
+
enum: enumValues,
|
|
108
|
+
} = subSchema;
|
|
109
|
+
|
|
110
|
+
const {name, arg} = argSpec;
|
|
111
|
+
|
|
112
|
+
const aliases = [
|
|
113
|
+
aliasToFlag(argSpec),
|
|
114
|
+
.../** @type {string[]} */ (appiumCliAliases ?? []).map((alias) =>
|
|
115
|
+
aliasToFlag(argSpec, alias),
|
|
116
|
+
),
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
/** @type {import('argparse').ArgumentOptions} */
|
|
120
|
+
let argOpts = {
|
|
121
|
+
required: false,
|
|
122
|
+
help: makeDescription(subSchema)
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Generally we will provide a `type` to `argparse` as a function which
|
|
127
|
+
* validates using ajv (which is much more full-featured than what `argparse`
|
|
128
|
+
* can offer). The exception is `boolean`-type options, which have no
|
|
129
|
+
* `argType`.
|
|
130
|
+
*
|
|
131
|
+
* Not sure if this type is correct, but it's not doing what I want. I want
|
|
132
|
+
* to say "this is a function which returns something of type `T` where `T` is
|
|
133
|
+
* never a `Promise`". This function must be sync.
|
|
134
|
+
* @type {((value: string) => unknown)|undefined}
|
|
135
|
+
*/
|
|
136
|
+
let argTypeFunction;
|
|
137
|
+
|
|
138
|
+
// handle special cases for various types
|
|
139
|
+
switch (type) {
|
|
140
|
+
// booleans do not have a type per `ArgumentOptions`, just an "action"
|
|
141
|
+
// NOTE: due to limitations of `argparse`, we cannot provide fancy help text, and must rely on its internal error messaging.
|
|
142
|
+
case TYPENAMES.BOOLEAN: {
|
|
143
|
+
argOpts.action = 'store_const';
|
|
144
|
+
argOpts.const = true;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
case TYPENAMES.OBJECT: {
|
|
149
|
+
argTypeFunction = transformers.json;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// arrays are treated as CSVs, because `argparse` doesn't handle array data.
|
|
154
|
+
case TYPENAMES.ARRAY: {
|
|
155
|
+
argTypeFunction = transformers.csv;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// "number" type is coerced to float. `argparse` does this for us if we use `float` type, but
|
|
160
|
+
// we don't.
|
|
161
|
+
case TYPENAMES.NUMBER: {
|
|
162
|
+
argTypeFunction = getSchemaValidator(argSpec, parseFloat);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// "integer" is coerced to an .. integer. again, `argparse` would do this for us if we used `int`.
|
|
167
|
+
case TYPENAMES.INTEGER: {
|
|
168
|
+
argTypeFunction = getSchemaValidator(argSpec, _.parseInt);
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// strings (like number and integer) are subject to further validation
|
|
173
|
+
// (e.g., must satisfy a mask or regex or even some custom validation
|
|
174
|
+
// function)
|
|
175
|
+
case TYPENAMES.STRING: {
|
|
176
|
+
argTypeFunction = getSchemaValidator(argSpec);
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// TODO: there may be some way to restrict this at the Ajv level --
|
|
181
|
+
// that may involve patching the metaschema.
|
|
182
|
+
case TYPENAMES.NULL:
|
|
183
|
+
// falls through
|
|
184
|
+
default: {
|
|
185
|
+
throw new TypeError(
|
|
186
|
+
`Schema property "${arg}": \`${type}\` type unknown or disallowed`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// metavar is used in help text. `boolean` cannot have a metavar--it is not
|
|
192
|
+
// displayed--and `argparse` throws if you give it one.
|
|
193
|
+
if (type !== TYPENAMES.BOOLEAN) {
|
|
194
|
+
argOpts.metavar = screamingSnakeCase(name);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// the validity of "appiumCliTransformer" should already have been determined
|
|
198
|
+
// by ajv during schema validation in `finalizeSchema()`. the `array` &
|
|
199
|
+
// `object` types have already added a formatter (see above, so we don't do it
|
|
200
|
+
// twice).
|
|
201
|
+
if (
|
|
202
|
+
type !== TYPENAMES.ARRAY &&
|
|
203
|
+
type !== TYPENAMES.OBJECT &&
|
|
204
|
+
appiumCliTransformer
|
|
205
|
+
) {
|
|
206
|
+
argTypeFunction = _.flow(
|
|
207
|
+
argTypeFunction ?? _.identity,
|
|
208
|
+
transformers[appiumCliTransformer],
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (argTypeFunction) {
|
|
213
|
+
argOpts.type = argTypeFunction;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// convert JSON schema `enum` to `choices`. `enum` can contain any JSON type, but `argparse`
|
|
217
|
+
// is limited to a single type per arg (I think). so let's make everything a string.
|
|
218
|
+
// and might as well _require_ the `type: string` while we're at it.
|
|
219
|
+
if (enumValues && !_.isEmpty(enumValues)) {
|
|
220
|
+
if (type === TYPENAMES.STRING) {
|
|
221
|
+
argOpts.choices = enumValues.map(String);
|
|
222
|
+
} else {
|
|
223
|
+
throw new TypeError(
|
|
224
|
+
`Problem with schema for ${arg}; \`enum\` is only supported for \`type: 'string'\``,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return [aliases, argOpts];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Converts the finalized, flattened schema representation into
|
|
234
|
+
* ArgumentDefinitions for handoff to `argparse`.
|
|
235
|
+
*
|
|
236
|
+
* @throws If schema has not been added to ajv (via `finalizeSchema()`)
|
|
237
|
+
* @returns {import('../cli/args').ArgumentDefinitions} A map of arryas of
|
|
238
|
+
* aliases to `argparse` arguments; empty if no schema found
|
|
239
|
+
*/
|
|
240
|
+
export function toParserArgs () {
|
|
241
|
+
const flattened = flattenSchema().filter(({schema}) => !schema.appiumCliIgnored);
|
|
242
|
+
return new Map(
|
|
243
|
+
_.map(flattened, ({schema, argSpec}) =>
|
|
244
|
+
subSchemaToArgDef(schema, argSpec),
|
|
245
|
+
),
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @template T
|
|
251
|
+
* @typedef {import('ajv/dist/types').FormatValidator<T>} FormatValidator<T>
|
|
252
|
+
*/
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* A JSON 7 schema with our custom keywords.
|
|
256
|
+
* @typedef {import('./keywords').AppiumJSONSchemaKeywords & import('json-schema').JSONSchema7} AppiumJSONSchema
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @typedef {import('./arg-spec').ArgSpec} ArgSpec
|
|
261
|
+
*/
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
import { ArgumentTypeError } from 'argparse';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This module provides custom keywords for Appium schemas, as well as
|
|
8
|
+
* "transformers" (see `argTransformers` below).
|
|
9
|
+
*
|
|
10
|
+
* Custom keywords are just properties that will appear in a schema (e.g.,
|
|
11
|
+
* `appium-config-schema.js`) beyond what the JSON Schema spec offers. These
|
|
12
|
+
* are usable by extensions, as well.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Splits a CSV string into an array
|
|
17
|
+
* @param {string} value
|
|
18
|
+
* @returns {string[]}
|
|
19
|
+
*/
|
|
20
|
+
function parseCsvLine (value) {
|
|
21
|
+
return value
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((v) => v.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Split a file by newline then calls {@link parseCsvLine} on each line.
|
|
29
|
+
* @param {string} value
|
|
30
|
+
* @returns {string[]}
|
|
31
|
+
*/
|
|
32
|
+
function parseCsvFile (value) {
|
|
33
|
+
return value
|
|
34
|
+
.split(/\r?\n/)
|
|
35
|
+
.map((v) => v.trim())
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.flatMap(parseCsvLine);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Namespace containing _transformers_ for CLI arguments. "Validators" and
|
|
42
|
+
* "formatters" do not actually modify the value, but these do.
|
|
43
|
+
*
|
|
44
|
+
* Use case is for when the config file can accept e.g., a `string[]`, but the
|
|
45
|
+
* CLI can only take a `string` (as `argparse` seems to be limited in that
|
|
46
|
+
* fashion; it also cannot understand an argument having multiple types).
|
|
47
|
+
*
|
|
48
|
+
* For example, the `csv` transform takes a `string` and returns a `string[]` by
|
|
49
|
+
* splitting it by comma--_or_ if that `string` happens to be a
|
|
50
|
+
* filepath--reading the file as a `.csv`.
|
|
51
|
+
*
|
|
52
|
+
* This contains some copy-pasted code from `lib/cli/parser-helpers.js`, which was
|
|
53
|
+
* obliterated.
|
|
54
|
+
*/
|
|
55
|
+
export const transformers = {
|
|
56
|
+
/**
|
|
57
|
+
* Given a CSV-style string or pathname, parse it into an array.
|
|
58
|
+
* The file can also be split on newlines.
|
|
59
|
+
* @param {string} value
|
|
60
|
+
* @returns {string[]}
|
|
61
|
+
*/
|
|
62
|
+
csv: (value) => {
|
|
63
|
+
let body;
|
|
64
|
+
// since this value could be a single string (no commas) _or_ a pathname, we will need
|
|
65
|
+
// to attempt to parse it as a file _first_.
|
|
66
|
+
try {
|
|
67
|
+
body = readFileSync(value, 'utf8');
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err.code !== 'ENOENT') {
|
|
70
|
+
throw new ArgumentTypeError(
|
|
71
|
+
`Could not read file ${body}: ${err.message}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
return body ? parseCsvFile(body) : parseCsvLine(value);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
throw new ArgumentTypeError(
|
|
80
|
+
'Must be a comma-delimited string, e.g., "foo,bar,baz"',
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Parse a string which could be a path to a JSON file or a JSON string.
|
|
87
|
+
* @param {string} jsonOrPath
|
|
88
|
+
* @returns {object}
|
|
89
|
+
*/
|
|
90
|
+
json: (jsonOrPath) => {
|
|
91
|
+
let json = jsonOrPath;
|
|
92
|
+
let loadedFromFile = false;
|
|
93
|
+
try {
|
|
94
|
+
// use synchronous file access, as `argparse` provides no way of either
|
|
95
|
+
// awaiting or using callbacks. This step happens in startup, in what is
|
|
96
|
+
// effectively command-line code, so nothing is blocked in terms of
|
|
97
|
+
// sessions, so holding up the event loop does not incur the usual
|
|
98
|
+
// drawbacks.
|
|
99
|
+
json = readFileSync(jsonOrPath, 'utf8');
|
|
100
|
+
loadedFromFile = true;
|
|
101
|
+
} catch (err) {
|
|
102
|
+
// unreadable files don't count... but other problems do.
|
|
103
|
+
if (err.code !== 'ENOENT') {
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const result = JSON.parse(json);
|
|
109
|
+
if (!_.isPlainObject(result)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`'${_.truncate(result, {length: 100})}' is not an object`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
} catch (e) {
|
|
116
|
+
const msg = loadedFromFile
|
|
117
|
+
? `The provided value of '${jsonOrPath}' must be a valid JSON`
|
|
118
|
+
: `The provided value must be a valid JSON`;
|
|
119
|
+
throw new TypeError(`${msg}. Original error: ${e.message}`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
|
|
2
|
+
import { transformers } from './cli-transformers';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Collection of keyword definitions to add to the singleton `Ajv` instance.
|
|
6
|
+
* @type {Record<string,KeywordDefinition>}
|
|
7
|
+
*/
|
|
8
|
+
export const keywords = {
|
|
9
|
+
/**
|
|
10
|
+
* Keyword to provide a list of command alias names for the CLI.
|
|
11
|
+
*
|
|
12
|
+
* If defined, there must be at least one item in the array and it must be non-empty.
|
|
13
|
+
* All items in the array must be unique.
|
|
14
|
+
*
|
|
15
|
+
* @todo Avoid alias collisions!
|
|
16
|
+
* @type {KeywordDefinition}
|
|
17
|
+
* @example
|
|
18
|
+
* {appiumCliAliases: ['B', 'bobby', 'robert']}
|
|
19
|
+
*/
|
|
20
|
+
appiumCliAliases: {
|
|
21
|
+
keyword: 'appiumCliAliases',
|
|
22
|
+
metaSchema: {
|
|
23
|
+
type: 'array',
|
|
24
|
+
items: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
minLength: 1,
|
|
27
|
+
},
|
|
28
|
+
minItems: 1,
|
|
29
|
+
uniqueItems: true,
|
|
30
|
+
description: 'List of aliases for the argument. Aliases shorter than three (3) characters will be prefixed with a single dash; otherwise two (2).'
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* Keyword to provide the name of the property in the destination (parsed
|
|
35
|
+
* args) object. By default, this value will be whatever the property name is,
|
|
36
|
+
* but camel-cased. If a flag needs something _other_ than just camel-casing,
|
|
37
|
+
* use this.
|
|
38
|
+
* @type {KeywordDefinition}
|
|
39
|
+
* @example
|
|
40
|
+
* // for prop 'no-color'
|
|
41
|
+
* {appiumCliDest: 'NOCOLOR'} // value will be stored as property `NOCOLOR` instead of `noColor`
|
|
42
|
+
*/
|
|
43
|
+
appiumCliDest: {
|
|
44
|
+
keyword: 'appiumCliDest',
|
|
45
|
+
metaSchema: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
minLength: 1,
|
|
48
|
+
description: 'Name of the associated property in the parsed CLI arguments object'
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* CLI-specific description of the property. Sometimes the allowed type can
|
|
54
|
+
* be different enough on the CLI that providing a description written for a
|
|
55
|
+
* config file context wouldn't make sense.
|
|
56
|
+
* @type {KeywordDefinition}
|
|
57
|
+
* @example
|
|
58
|
+
* {appiumCliDescription: 'This is a comma-delimited string, but in the config file it is an array'}
|
|
59
|
+
*/
|
|
60
|
+
appiumCliDescription: {
|
|
61
|
+
keyword: 'appiumCliDescription',
|
|
62
|
+
schemaType: 'string',
|
|
63
|
+
metaSchema: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
minLength: 1,
|
|
66
|
+
description: 'Description to provide in the --help text of the CLI. Overrides `description`'
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Transformers for CLI args. These usually take strings then do something with them, like
|
|
72
|
+
* read a file or parse further.
|
|
73
|
+
* @type {KeywordDefinition}
|
|
74
|
+
*/
|
|
75
|
+
appiumCliTransformer: {
|
|
76
|
+
keyword: 'appiumCliTransformer',
|
|
77
|
+
metaSchema: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
enum: Object.keys(transformers),
|
|
80
|
+
description: 'The name of a custom transformer to run against the value as provided via the CLI.'
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Flag to tell Appium to _not_ provide this property as a CLI argument.
|
|
86
|
+
* @type {KeywordDefinition}
|
|
87
|
+
*/
|
|
88
|
+
appiumCliIgnored: {
|
|
89
|
+
keyword: 'appiumCliIgnored',
|
|
90
|
+
metaSchema: {
|
|
91
|
+
type: 'boolean',
|
|
92
|
+
description: 'If `true`, Appium will not provide this property as a CLI argument. This is NOT the same as a "hidden" argument.',
|
|
93
|
+
enum: [true]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Mark this property as deprecated.
|
|
99
|
+
* @type {KeywordDefinition}
|
|
100
|
+
*/
|
|
101
|
+
appiumDeprecated: {
|
|
102
|
+
keyword: 'appiumDeprecated',
|
|
103
|
+
metaSchema: {
|
|
104
|
+
type: 'boolean',
|
|
105
|
+
description: 'If `true`, this property will be displayed as "deprecated" to the user',
|
|
106
|
+
enum: [true],
|
|
107
|
+
$comment: 'JSON schema draft-2019-09 keyword `deprecated` serves the same purpose. This keyword should itself be deprecated if we move to draft-2019-09!'
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* These are the valid values for the `appiumCliTransformer` keyword.
|
|
114
|
+
* Unfortunately, TS cannot infer this in a JS context. In TS, we'd use
|
|
115
|
+
* `as const` when defining `argTransformers`, then get `keyof typeof argTransformers`. alas.
|
|
116
|
+
* @typedef {'csv'|'json'} AppiumCliTransformerName
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* These are the custom keywords that Appium recognizes.
|
|
121
|
+
*
|
|
122
|
+
* @typedef AppiumJSONSchemaKeywords
|
|
123
|
+
* @property {string} [appiumCliDest]
|
|
124
|
+
* @property {string} [appiumCliDescription]
|
|
125
|
+
* @property {string[]} [appiumCliAliases]
|
|
126
|
+
* @property {boolean} [appiumCliIgnored]
|
|
127
|
+
* @property {AppiumCliTransformerName} [appiumCliTransformer]
|
|
128
|
+
* @property {boolean} [appiumDeprecated]
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @typedef {import('ajv').KeywordDefinition} KeywordDefinition
|
|
134
|
+
*/
|