Skip to content

Commit

Permalink
chore(typedoc-plugin-appium): tweaks
Browse files Browse the repository at this point in the history
- `BuiltinMethodMapConverter`'s `convert()` will _always_ return a `BuiltinCommands` / removed unused import
- Verbose logging for skipped methods
- Remove useless type aliases from option declarations and add some no-op typechecks (these will be compiled away)
- Add some docstrings to guards and types
- `CallSignatureReflectionWithParams` is now `CallSignatureReflectionWithArity`, and it is specific about having a nonzero arity. Broke out `CallSignatureReflection` from this, since the guard and type didn't fully match up
  • Loading branch information
boneskull committed Jan 9, 2023
1 parent 1bdab7b commit 8954adf
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 31 deletions.
Expand Up @@ -5,7 +5,6 @@ import {
isMethodMapDeclarationReflection,
} from '../guards';
import {AppiumPluginLogger} from '../logger';
import {ModuleCommands} from '../model';
import {BaseConverter} from './base-converter';
import {BuiltinCommands} from '../model/builtin-commands';
import {convertMethodMap} from './method-map';
Expand All @@ -28,7 +27,7 @@ export const NAME_BASE_DRIVER_CLASS = 'BaseDriver';
*/
export const NAME_BUILTIN_COMMAND_MODULE = '@appium/base-driver';

export class BuiltinMethodMapConverter extends BaseConverter<BuiltinCommands | undefined> {
export class BuiltinMethodMapConverter extends BaseConverter<BuiltinCommands> {
/**
* Creates a child logger for this instance
* @param ctx Typedoc Context
Expand Down
13 changes: 5 additions & 8 deletions packages/typedoc-plugin-appium/lib/converter/overrides.ts
Expand Up @@ -59,6 +59,11 @@ export function convertOverrides({
const builtinRoutes = builtinCommands.routesByCommandName.get(command);
if (!builtinMethods.has(command) || !builtinRoutes) {
// actually unknown method
log.verbose(
'(%s) No builtin route mapping to method "%s"; skipping',
parentRefl.name,
command
);
continue;
}

Expand Down Expand Up @@ -92,14 +97,6 @@ export function convertOverrides({
}
}

if (unknownMethods.size) {
// this is quite likely, as any async method is inspected.
log.info(
'(%s) The following async methods were not found in any method map: %s',
parentRefl.name,
[...unknownMethods].join(', ')
);
}
return routes;
}

Expand Down
85 changes: 79 additions & 6 deletions packages/typedoc-plugin-appium/lib/converter/types.ts
Expand Up @@ -2,6 +2,7 @@ import {
Comment,
DeclarationReflection,
LiteralType,
ParameterReflection,
ReferenceType,
ReflectionFlags,
ReflectionKind,
Expand Down Expand Up @@ -110,6 +111,9 @@ export type ExecMethodDeclarationReflection = WithName<
flags: ReflectionFlags & {isStatic: true};
};

export type WithStaticFlag = {flags: ReflectionFlags & {isStatic: true}};
export type WithoutStaticFlag = {flags: ReflectionFlags & {isStatic: false}};

/**
* Type corresponding to the `params` prop of a `MethodDef`
*/
Expand All @@ -127,40 +131,109 @@ export type ExecMethodDefParamsPropDeclarationReflection = WithName<
DeclarationReflectionWithReflectedType
>;

/**
* Type corresponding to `@appium/types` module
*/
export type AppiumTypesReflection = WithNameAndKind<
typeof NAME_TYPES_MODULE,
ReflectionKind.Module,
ParentReflection
>;

/**
* Type corresponding to a TS `interface`
*/
export type InterfaceDeclarationReflection = WithKind<
ReflectionKind.Interface,
DeclarationReflection
>;

/**
* Type corresponding to the `ExternalDriver` `interface` of `@appium/types`
*/
export type ExternalDriverDeclarationReflection = WithName<
typeof NAME_EXTERNAL_DRIVER,
InterfaceDeclarationReflection
>;

export type AsyncMethodDeclarationReflection = WithSomeType<ReferenceType, DeclarationReflection> &
WithKind<ReflectionKind.Method, DeclarationReflection>;
/**
* A call signature for a function that returns some sort of `Promise`.
*/
export type AsyncCallSignatureReflection = CallSignatureReflection & {
type: ReferenceType;
name: 'Promise';
};

/**
* An async method or reference to an async method. A command's method must be of this type.
*/
export type AsyncMethodDeclarationReflection<
T extends ReferenceType | ReflectionType = ReferenceType
> = WithSomeType<T, DeclarationReflection> &
WithKind<
T extends ReferenceType ? ReflectionKind.Method : ReflectionKind.Property,
DeclarationReflection
> &
WithoutStaticFlag &
(T extends ReferenceType
? {
signatures: NonEmptyArray<AsyncCallSignatureReflection>;
}
: T extends ReflectionType
? {
type: {
declaration: {
signatures: NonEmptyArray<AsyncCallSignatureReflection>;
};
};
}
: never);

/**
* A little "struct" containing a method and potentially a derived comment (which may not have been derived from
* the method itself).
*/
export interface KnownMethodData {
comment?: Comment;
method: AsyncMethodDeclarationReflection;
}

/**
* A lookup of command names to {@linkcode KnownMethodData} objects.
*/
export type KnownMethods = Map<string, KnownMethodData>;

export interface MethodDefParam {
name: string;
}

/**
* A {@linkcode DeclarationReflection} which is a `class`.
*/
export type ClassDeclarationReflection = WithKind<ReflectionKind.Class, DeclarationReflection>;

/**
* One of {@linkcode ExecMethodDefParamsPropDeclarationReflection} or
* {@linkcode MethodDefParamsPropDeclarationReflection}, which are "parameters" properties of method
* definition objects (as in a `MethodMap`) or execute method definitions (in an `ExecMethodMap`)
*/
export type ParamsPropDeclarationReflection =
| ExecMethodDefParamsPropDeclarationReflection
| MethodDefParamsPropDeclarationReflection;

/**
* A {@linkcode SignatureReflection} which is a call signature; a function signature.
*
* (Other types of signatures include things like "constructor signatures")
*/
export type CallSignatureReflection = WithKind<ReflectionKind.CallSignature, SignatureReflection>;

/**
* An array with a nonzero number of items.
*/
export type NonEmptyArray<T> = [T, ...T[]];

/**
* A {@linkcode CallSignatureReflection} with a nonzero number of parameters.
*
* This is used to rename parameters on commands to prefer the ones as defined in the method map.
*/
export type CallSignatureReflectionWithArity = CallSignatureReflection & {
parameters: NonEmptyArray<ParameterReflection>;
};
47 changes: 42 additions & 5 deletions packages/typedoc-plugin-appium/lib/guards.ts
Expand Up @@ -31,6 +31,7 @@ import {
AsyncMethodDeclarationReflection,
BaseDriverDeclarationReflection,
CallSignatureReflection,
CallSignatureReflectionWithArity,
ClassDeclarationReflection,
CommandPropDeclarationReflection,
DeclarationReflectionWithReflectedType,
Expand Down Expand Up @@ -157,7 +158,6 @@ export function isBaseDriverDeclarationReflection(
/**
* Type guard for a property of an object (a {@linkcode Reflection} having kind {@linkcode ReflectionKind.Property}).
* @param value any value
* @returns
*/
export function isPropertyKind(value: any) {
return value instanceof Reflection && value.kindOf(ReflectionKind.Property);
Expand Down Expand Up @@ -245,18 +245,36 @@ export function isExecMethodDefParamsPropDeclarationReflection(
return isReflectionWithReflectedType(value) && value.name === NAME_PAYLOAD_PARAMS;
}

/**
* Type guard for a {@linkcode InterfaceDeclarationReflection} corresponding to a TS interface.
* @param value any value
*/
export function isInterfaceDeclarationReflection(
value: any
): value is InterfaceDeclarationReflection {
return isDeclarationReflection(value) && value.kindOf(ReflectionKind.Interface);
}

/**
* Type guard for a {@linkcode ExternalDriverDeclarationReflection} which is the `ExternalDriver`
* interface defined in `@appium/types`.
* @param value any value
*/
export function isExternalDriverDeclarationReflection(
value: any
): value is ExternalDriverDeclarationReflection {
return isInterfaceDeclarationReflection(value) && value.name === NAME_EXTERNAL_DRIVER;
}

/**
* Type guard for an {@linkcode AsyncMethodDeclarationReflection}, which is _potentially_ a method
* for a command. Not all async methods in driver classes are mapped to commands, of course!
*
* A command method cannot be static, but it can be an actual (async) function or a reference to an
* (async) function; just depends how the code is written. Either way, this asserts there's a
* call signature returning a `Promise`.
* @param value
*/
export function isAsyncMethodDeclarationReflection(
value: any
): value is AsyncMethodDeclarationReflection {
Expand All @@ -275,14 +293,33 @@ export function isAsyncMethodDeclarationReflection(
);
}

/**
* Type guard for a {@linkcode ClassDeclarationReflection} which is just a {@linkcode DeclarationReflection}
* with a `kind` of {@linkcode ReflectionKind.Class}.
* @param value any value
*/
export function isClassDeclarationReflection(value: any): value is ClassDeclarationReflection {
return Boolean(isDeclarationReflection(value) && value.kindOf(ReflectionKind.Class));
}

export function isCallSignatureReflectionWithParams(value: any): value is CallSignatureReflection {
/**
* Type guard for a {@linkcode CallSignatureReflection} which is just a
* {@linkcode SignatureReflection} with kind {@linkcode ReflectionKind.CallSignature}.
* @param value any value
*/
export function isCallSignatureReflection(value: any): value is CallSignatureReflection {
return Boolean(
value instanceof SignatureReflection &&
value.kindOf(ReflectionKind.CallSignature) &&
value.parameters?.length
value instanceof SignatureReflection && value.kindOf(ReflectionKind.CallSignature)
);
}

/**
* Type guard for a {@linkcode CallSignatureReflectionWithArity}, which is a
* {@linkcode CallSignatureReflection} with an arity greater than zero.
* @param value any value
*/
export function isCallSignatureReflectionWithArity(
value: any
): value is CallSignatureReflectionWithArity {
return Boolean(isCallSignatureReflection(value) && value.parameters?.length);
}
4 changes: 2 additions & 2 deletions packages/typedoc-plugin-appium/lib/model/command-data.ts
Expand Up @@ -13,7 +13,7 @@ import {
ClassDeclarationReflection,
CommentSourceType,
} from '../converter';
import {isCallSignatureReflectionWithParams} from '../guards';
import {isCallSignatureReflectionWithArity} from '../guards';
import {AppiumPluginLogger} from '../logger';
import {AllowedHttpMethod, Command, Route} from './types';

Expand Down Expand Up @@ -84,7 +84,7 @@ export abstract class BaseCommandData {
if (this.#parameters) {
return this.#parameters;
}
const sig = this.methodRefl?.signatures?.find(isCallSignatureReflectionWithParams);
const sig = this.methodRefl?.signatures?.find(isCallSignatureReflectionWithArity);

if (!sig) {
return [];
Expand Down
14 changes: 10 additions & 4 deletions packages/typedoc-plugin-appium/lib/options/declarations.ts
Expand Up @@ -11,23 +11,29 @@ export const declarations = {
help: `(${NS}) Name of "commands" directory under the TypeDoc output directory. Not a full path`,
name: 'commandsDir',
type: ParameterType.String,
} as DeclarationOption,
},
forceBreadcrumbs: {
defaultValue: false,
help: `(${NS}) Force breadcrumbs to be shown; overrides "hideBreadcrumbs"`,
name: 'forceBreadcrumbs',
type: ParameterType.Boolean,
} as DeclarationOption,
},
outputBuiltinCommands: {
defaultValue: false,
help: `(${NS}) Output builtin commands`,
name: 'outputBuiltinCommands',
type: ParameterType.Boolean,
} as DeclarationOption,
},
outputModules: {
defaultValue: true,
help: `(${NS}) Output modules APIs in addition to commands. This is needed for complete typing information`,
name: 'outputModules',
type: ParameterType.Boolean,
} as DeclarationOption,
},
} as const;

// these are extra type checks to ensure these are the correct type.
declarations.outputModules as DeclarationOption;
declarations.forceBreadcrumbs as DeclarationOption;
declarations.outputBuiltinCommands as DeclarationOption;
declarations.commandsDir as DeclarationOption;
Expand Up @@ -10,7 +10,7 @@ import {
NAME_TYPES_MODULE,
} from '../../../lib/converter';
import {BuiltinCommands} from '../../../lib/model/builtin-commands';
import {isCallSignatureReflectionWithParams} from '../../../lib/guards';
import {isCallSignatureReflectionWithArity} from '../../../lib/guards';
import {AppiumPluginLogger} from '../../../lib/logger';
import {CommandSet, ModuleCommands, ProjectCommands} from '../../../lib/model';
import {initConverter, NAME_FAKE_DRIVER_MODULE} from '../helpers';
Expand Down Expand Up @@ -93,9 +93,8 @@ describe('ExternalConverter', function () {
it('should prefer method map parameters over method parameters', function () {
const postRoute = [...sessionCmdSet].find((cmdData) => cmdData.httpMethod === 'POST')!;

const pRefls = postRoute.methodRefl!.signatures!.find(
isCallSignatureReflectionWithParams
)!.parameters!;
const pRefls = postRoute.methodRefl!.signatures!.find(isCallSignatureReflectionWithArity)!
.parameters!;

// the method has 4 parameters, but the method map has 3
expect(pRefls).to.have.lengthOf(4);
Expand Down

0 comments on commit 8954adf

Please sign in to comment.