chore(appium): fix access of wrong arguments object
Prevented subcommands from working properly.
In addition, cleaned up some types; `FlattenedAppiumConfig` is now just `ParsedArgs`.
MODIFY
packages/appium/lib/main.js
packages/appium/lib/main.js
@@ -23,7 +23,7 @@ import { inspectObject } from './utils';
/**
*
- * @param {FlattenedAppiumConfig} args
+ * @param {ParsedArgs} args
* @param {boolean} [throwInsteadOfExit]
*/
async function preflightChecks (args, throwInsteadOfExit = false) {
@@ -165,13 +165,13 @@ function getExtraMethodMap (driverClasses, pluginClasses) {
* const options = {}; // config object
* await init(options);
* const schema = getSchema(); // entire config schema including plugins and drivers
- * @param {FlattenedAppiumConfig} [args] - Parsed args
- * @returns {Promise<{parser: import('./cli/parser').ArgParser} & Partial<{appiumDriver: AppiumDriver, parsedArgs: FlattenedAppiumConfig}>>}
+ * @param {ParsedArgs} [args] - Parsed args
+ * @returns {Promise<{parser: import('./cli/parser').ArgParser} & Partial<{appiumDriver: AppiumDriver, parsedArgs: ParsedArgs}>>}
*/
async function init (args) {
const parser = await getParser();
let throwInsteadOfExit = false;
- /** @type {FlattenedAppiumConfig} */
+ /** @type {ParsedArgs} */
let parsedArgs;
if (args) {
// if we have a containing package instead of running as a CLI process,
@@ -182,10 +182,10 @@ async function init (args) {
// but remove it since it's not a real server arg per se
delete args.throwInsteadOfExit;
}
- parsedArgs = args;
+ parsedArgs = {...args, subcommand: args.subcommand ?? SERVER_SUBCOMMAND};
} else {
// otherwise parse from CLI
- parsedArgs = /** @type {FlattenedAppiumConfig} */(parser.parseArgs());
+ parsedArgs = parser.parseArgs();
}
const configResult = await readConfigFile(parsedArgs.configFile);
@@ -199,8 +199,7 @@ async function init (args) {
// 1. command line args
// 2. config file
// 3. defaults from config file.
- // if no "subcommand" specified (e.g., `args` came from not-`parser.parse_args()`), assume we want a server.
- if (parsedArgs.subcommand === SERVER_SUBCOMMAND || !parsedArgs.subcommand) {
+ if (parsedArgs.subcommand === SERVER_SUBCOMMAND) {
parsedArgs = _.defaultsDeep(
parsedArgs,
configResult.config?.server,
@@ -208,21 +207,21 @@ async function init (args) {
);
}
- args = _.defaultsDeep(
- args,
+ parsedArgs = _.defaultsDeep(
+ parsedArgs,
configResult.config ?? {},
);
- await logsinkInit(args);
+ await logsinkInit(parsedArgs);
// if the user has requested the 'driver' CLI, don't run the normal server,
// but instead pass control to the driver CLI
if (parsedArgs.subcommand === DRIVER_TYPE) {
- await runExtensionCommand(args, parsedArgs.subcommand, driverConfig);
+ await runExtensionCommand(parsedArgs, parsedArgs.subcommand, driverConfig);
return {parser};
}
if (parsedArgs.subcommand === PLUGIN_TYPE) {
- await runExtensionCommand(args, parsedArgs.subcommand, pluginConfig);
+ await runExtensionCommand(parsedArgs, parsedArgs.subcommand, pluginConfig);
return {parser};
}
@@ -239,7 +238,7 @@ async function init (args) {
}
}
- const appiumDriver = new AppiumDriver(args);
+ const appiumDriver = new AppiumDriver(parsedArgs);
// set the config on the umbrella driver so it can match drivers to caps
appiumDriver.driverConfig = driverConfig;
await preflightChecks(parsedArgs, throwInsteadOfExit);
@@ -249,7 +248,7 @@ async function init (args) {
/**
*
- * @param {FlattenedAppiumConfig} [args]
+ * @param {ParsedArgs} [args]
* @returns
*/
async function main (args) {
@@ -347,5 +346,5 @@ export { getSchema, validate, finalizeSchema } from './schema/schema';
export { readConfigFile } from './config-file';
/**
- * @typedef {import('../types/types').FlattenedAppiumConfig} FlattenedAppiumConfig
+ * @typedef {import('../types/types').ParsedArgs} ParsedArgs
*/

MODIFY
packages/appium/test/schema/schema-specs.js
packages/appium/test/schema/schema-specs.js
@@ -272,11 +272,11 @@ describe('schema', function () {
let expected;
beforeEach(function () {
- // TS complains about this require()
- // @ts-ignore
schema.registerSchema(
'driver',
'fake',
+ // TS complains about this require()
+ // @ts-ignore
require('@appium/fake-driver/build/lib/fake-driver-schema').default,
);
schema.finalizeSchema();

MODIFY
packages/appium/types/types.d.ts
packages/appium/types/types.d.ts
-import {AppiumConfiguration, ServerConfig} from './appium-config';
-import appiumConfigSchema from '../lib/schema/appium-config-schema';
-import {DRIVER_TYPE, PLUGIN_TYPE} from '../lib/ext-config-io';
+import {transformers} from '../lib/schema/cli-transformers';
import {SERVER_SUBCOMMAND} from '../lib/cli/parser';
+import {
+ DRIVER_TYPE as DRIVER_SUBCOMMAND,
+ PLUGIN_TYPE as PLUGIN_SUBCOMMAND,
+} from '../lib/ext-config-io';
+import appiumConfigSchema from '../lib/schema/appium-config-schema';
+import {AppiumConfiguration, ServerConfig} from './appium-config';
/**
* Converts a kebab-cased string into a camel-cased string.
@@ -35,19 +39,37 @@ export type KeysToCamelCase<T> = {
export type AppiumConfig = Partial<AppiumConfiguration>;
/**
- * Certain properties have an `appiumCliDest` prop, which affects the shape of {@link FlattenedAppiumConfig}.
- * This type helps recognize these properties.
+ * Certain properties have an `appiumCliDest` prop, which affects the shape of
+ * {@link ParsedArgs}. This type helps recognize these properties.
*
* See `../lib/schema/keywords` for definition of `appiumCliDest`.
*/
-type WithDest = {appiumCliDest: string};
+interface WithDest {
+ appiumCliDest: string;
+}
/**
- * Some properties have a `default` prop, which means practically they will not be `undefined` upon parsing.
+ * Some properties have a `default` prop, which means practically they will not
+ * be `undefined` upon parsing.
*
- * We use this to ensure that the {@link FlattenedAppiumConfig} makes guarantees about the presence of properties.
+ * We use this to ensure that the {@link ParsedArgs} makes guarantees
+ * about the presence of properties.
*/
-type WithDefault = {default: any};
+interface WithDefault {
+ default: any;
+}
+
+interface WithCliTransformer {
+ appiumCliTransformer: keyof typeof transformers;
+}
+
+interface WithTypeArray {
+ type: 'array';
+}
+interface WithTypeObject {
+ type: 'object';
+}
+type WithTransformer = WithCliTransformer | WithTypeArray | WithTypeObject;
/**
* Derive the "constant" type of the server properties from the schema.
@@ -65,70 +87,115 @@ type NormalizedServerConfig = {
};
/**
- * "Normalized" config, which is like the flattened config (camel-cased keys), but not flattened.
+ * "Normalized" config, which is like the flattened config (camel-cased keys),
+ * but not flattened.
*/
export type NormalizedAppiumConfig = {
server: NormalizedServerConfig;
};
/**
- * Utility type to associate {@link AppiumServerSchema} with {@link ServerConfig}.
+ * Utility type to associate {@link AppiumServerSchema} with
+ * {@link ServerConfig}.
*/
type ServerConfigMapping = {
[Prop in keyof Required<ServerConfig>]: AppiumServerSchema[Prop];
};
/**
- * This type checks if `appiumCliDest` is present in the object via {@link WithDest}, and uses the _value_
- * of that property for the key name; otherwise uses the camel-cased value of the key name.
- *
- * Further, it checks for the existence of default values, and ensures those properties will be defined.
- *
- * @todo Does not handle nested objects.
+ * This type checks if `appiumCliDest` is present in the object via
+ * {@link WithDest}, and uses the _value_ of that property for the key name;
+ * otherwise uses the camel-cased value of the key name.
*/
-type FlattenedArgProps = {
- [Prop in keyof ServerConfigMapping as AppiumServerSchema[Prop] extends WithDest
+type SetKeyForProp<Prop extends keyof ServerConfigMapping> =
+ AppiumServerSchema[Prop] extends WithDest
? AppiumServerSchema[Prop]['appiumCliDest']
- : KebabToCamel<Prop>]: AppiumServerSchema[Prop] extends WithDefault
+ : KebabToCamel<Prop>;
+
+/**
+ * Checks for the existence of default values, and ensures those properties will
+ * be defined (eliminate `| undefined` from the type).
+ */
+type DefaultForProp<Prop extends keyof ServerConfigMapping> =
+ AppiumServerSchema[Prop] extends WithDefault
? NonNullable<ServerConfig[Prop]>
: ServerConfig[Prop];
+
+/**
+ * The final shape of the parsed CLI arguments.
+ */
+type ParsedArgsFromConfig = {
+ [Prop in keyof ServerConfigMapping as SetKeyForProp<Prop>]: DefaultForProp<Prop>;
};
/**
- * Random stuff that may appear in the parsed args which has no equivalent in a config file.
+ * Possible subcommands for the `appium` CLI.
+ */
+type CliSubCommands =
+ | typeof SERVER_SUBCOMMAND
+ | typeof DRIVER_SUBCOMMAND
+ | typeof PLUGIN_SUBCOMMAND;
+
+/**
+ * Possible subcommands of {@link DRIVER_SUBCOMMAND} or
+ * {@link PLUGIN_SUBCOMMAND}.
+ */
+type CliExtensionSubcommands =
+ | 'list'
+ | 'install'
+ | 'uninstall'
+ | 'update'
+ | 'run';
+
+/**
+ * Random stuff that may appear in the parsed args which has no equivalent in a
+ * config file.
*/
-type ExtraCLIArgs = {
+interface MoreArgs {
/**
* Path to config file, if any
*/
- configFile: string | undefined;
+ configFile: string;
/**
* If true, show the build info and exit
*/
- showConfig: boolean | undefined;
+ showConfig: boolean;
/**
* If true, open a REPL
*/
- shell: boolean | undefined;
+ shell: boolean;
/**
- * If true, throw on error instead of exit. Not supported via CLI, but rather only programmatic usage.
+ * If true, throw on error instead of exit. Not supported via CLI, but rather
+ * only programmatic usage.
*/
- throwInsteadOfExit: boolean | undefined;
+ throwInsteadOfExit: boolean;
/**
* Possible subcommands
*/
subcommand:
- | typeof DRIVER_TYPE
- | typeof PLUGIN_TYPE
+ | typeof DRIVER_SUBCOMMAND
+ | typeof PLUGIN_SUBCOMMAND
| typeof SERVER_SUBCOMMAND;
-};
/**
- * The Appium configuration as a flattened object, parsed via CLI args _and_ any CLI args unsupported by the config file.
- * @todo Does not make any assumptions about property names derived from extensions.
+ * Subcommands of `driver` subcommand
+ */
+ driverCommand: CliExtensionSubcommands;
+
+ /**
+ * Subcommands of `plugin` subcommand
+ */
+ pluginCommand: CliExtensionSubcommands;
+}
+
+/**
+ * The Appium configuration as a flattened object, parsed via CLI args _and_ any
+ * CLI args unsupported by the config file.
+ * @todo Does not make any assumptions about property names derived from
+ * extensions.
*/
-export type FlattenedAppiumConfig = FlattenedArgProps & ExtraCLIArgs;
+export type ParsedArgs = ParsedArgsFromConfig & Partial<MoreArgs>;

MODIFY
packages/support/lib/log-internal.js
packages/support/lib/log-internal.js
@@ -103,7 +103,7 @@ class SecureValuesPreprocessor {
/**
* Loads rules from the given JSON file
*
- * @param {string|Array<string|Rule>} source The full path to the JSON file containing secure
+ * @param {string|string[]|Rule[]>} source The full path to the JSON file containing secure
* values replacement rules or the rules themselves represented as an array
* @throws {Error} If the format of the source file is invalid or
* it does not exist

MODIFY
packages/support/lib/logging.js
packages/support/lib/logging.js
@@ -117,7 +117,7 @@ function getLogger (prefix = null) {
* appear in Appium logs.
* Each call to this method replaces the previously loaded rules if any existed.
*
- * @param {string} rulesJsonPath The full path to the JSON file containing
+ * @param {string|string[]|Rule[]} rulesJsonPath The full path to the JSON file containing
* the replacement rules. Each rule could either be a string to be replaced
* or an object with predefined properties. See the `Rule` type definition in
* `log-internals.js` to get more details on its format.

chore(appium): fix access of wrong arguments object

Prevented subcommands from working properly.
In addition, cleaned up some types; `FlattenedAppiumConfig` is now just `ParsedArgs`.