feat(typedoc-plugin-appium): implemented outputBuiltinCommands

This value defaults to `false`, as extension authors will typically not want that stuff.

As with removal of non-command reflections (via the plugin's `outputModules` option), this happens in a post-processing step after conversion but before rendering.
This commit is contained in:
Christopher Hiller
2023-02-02 13:28:52 -08:00
parent d9304d8212
commit 6bb06e2c19
3 changed files with 83 additions and 7 deletions
@@ -4,8 +4,15 @@
* @module
*/
import _ from 'lodash';
import pluralize from 'pluralize';
import {ContainerReflection, Context, DeclarationReflection, ProjectReflection} from 'typedoc';
import {
ContainerReflection,
Context,
DeclarationReflection,
ProjectReflection,
ReflectionKind,
} from 'typedoc';
import {isParentReflection} from '../guards';
import {AppiumPluginLogger} from '../logger';
import {
@@ -19,6 +26,7 @@ import {
ProjectCommands,
Route,
} from '../model';
import {NAME_BUILTIN_COMMAND_MODULE} from './builtin-method-map';
import {findChildByNameAndGuard} from './utils';
/**
@@ -58,7 +66,6 @@ export function createCommandReflection(
* Note that the return value is mainly for informational purposes, since this method mutates
* TypeDoc's state.
* @param log - Logger
* @param ctx - Current context
* @param parent - Parent module (or project)
* @param moduleCmds - Command information for `module`
* @internal
@@ -66,11 +73,11 @@ export function createCommandReflection(
export function createExtensionReflection(
log: AppiumPluginLogger,
ctx: Context,
parent: ParentReflection,
name: string,
moduleCmds: ModuleCommands
): ExtensionReflection {
// TODO: parent.name may not be right here
const extRefl = new ExtensionReflection(parent.name, parent, moduleCmds);
const extRefl = new ExtensionReflection(name, ctx.project, moduleCmds);
/**
* See note in {@link createCommandReflection} above about this call
*/
@@ -121,7 +128,7 @@ export function createReflections(
? project
: findChildByNameAndGuard(project, parentName, isParentReflection)!;
const cmdsRefl = createExtensionReflection(log, ctx, parentRefl, parentCmds);
const cmdsRefl = createExtensionReflection(log, ctx, parentRefl.name, parentCmds);
log.info(
'(%s) Created %d new command %s',
@@ -152,3 +159,29 @@ export function omitDefaultReflections(
return removed;
}
/**
* Removes extension reflection(s) which are part of Appium itself. This is desirable for most
* extension authors.
* @param project - Current TypeDoc project
* @param refl - A {@linkcode ContainerReflection} to remove children from; defaults to `project`
* @returns A set of removed {@linkcode DeclarationReflection}s
*/
export function omitBuiltinReflections(
project: ProjectReflection,
refl: ContainerReflection = project
) {
let removed = new Set<DeclarationReflection>();
const extRefls = refl.getChildrenByKind(
AppiumPluginReflectionKind.Extension as any
) as DeclarationReflection[];
const builtinRefl = _.find(extRefls, {name: NAME_BUILTIN_COMMAND_MODULE});
if (!builtinRefl) {
throw new Error(`Could not find builtin commands reflection "${NAME_BUILTIN_COMMAND_MODULE}"`);
}
project.removeReflection(builtinRefl);
removed.add(builtinRefl);
return removed;
}
+20 -2
View File
@@ -4,13 +4,21 @@
*/
import _ from 'lodash';
import pluralize from 'pluralize';
import {Application, Context, Converter, DeclarationReflection} from 'typedoc';
import {convertCommands, createReflections, omitDefaultReflections} from './converter';
import {
convertCommands,
createReflections,
omitBuiltinReflections,
omitDefaultReflections,
} from './converter';
import {AppiumPluginLogger, AppiumPluginParentLogger} from './logger';
import {ExtensionReflection, NS, ProjectCommands} from './model';
import {configureOptions, declarations} from './options';
import {configureTheme, THEME_NAME} from './theme';
let log: AppiumPluginLogger;
/**
* Loads the Appium TypeDoc plugin.
*
@@ -48,7 +56,7 @@ export async function convert(app: Application): Promise<ConvertResult> {
let projectCommands: ProjectCommands | undefined;
// we don't want to do this work if we're not using the custom theme!
const log = new AppiumPluginLogger(app.logger, NS);
log = log ?? new AppiumPluginLogger(app.logger, NS);
// this should not be necessary given the `AppiumPluginOptionsReader` forces the issue, but
// it's a safeguard nonetheless.
@@ -98,12 +106,22 @@ export interface ConvertResult {
* @returns Typedoc `Context` at the time of the {@linkcode Converter.EVENT_RESOLVE_END} event
*/
export async function postProcess(app: Application): Promise<PostProcessResult> {
log = log ?? new AppiumPluginLogger(app.logger, NS);
return new Promise((resolve) => {
app.converter.once(Converter.EVENT_RESOLVE_END, (ctx: Context) => {
let removed: Set<DeclarationReflection> | undefined;
// if the `outputModules` option is false, then we want to remove all the usual TypeDoc reflections.
if (!app.options.getValue(declarations.outputModules.name)) {
removed = omitDefaultReflections(ctx.project);
log.info('%s omitted from output', pluralize('default reflection', removed.size, true));
}
if (!app.options.getValue(declarations.outputBuiltinCommands.name)) {
const removedBuiltinRefls = omitBuiltinReflections(ctx.project);
removed = new Set([...(removed ?? []), ...removedBuiltinRefls]);
log.info(
'%s omitted from output',
pluralize('builtin reflection', removedBuiltinRefls.size, true)
);
}
resolve({ctx, removed});
});
@@ -1,3 +1,4 @@
import _ from 'lodash';
import {
Application,
Context,
@@ -127,6 +128,7 @@ describe('@appium/typedoc-plugin-appium', function () {
before(async function () {
const app = reset();
app.options.setValue('outputModules', true);
app.options.setValue('outputBuiltinCommands', true); // do not pollute result
resolveBeginCtxPromise = convert(app);
resolveEndCtxPromise = postProcess(app);
app.convert();
@@ -147,5 +149,28 @@ describe('@appium/typedoc-plugin-appium', function () {
expect(removed).to.be.undefined;
});
});
describe('when the `outputBuiltinCommands` option is false', function () {
before(async function () {
const app = reset();
app.options.setValue('outputModules', true); // as to not pollute the 'removed' set
app.options.setValue('outputBuiltinCommands', false);
resolveBeginCtxPromise = convert(app);
resolveEndCtxPromise = postProcess(app);
app.convert();
[, {ctx, removed}] = await Promise.all([resolveBeginCtxPromise, resolveEndCtxPromise]);
({project} = ctx);
});
it('should remove the builtin commands', function () {
expect(removed).to.have.lengthOf(1);
});
it('should not output builtin commands', async function () {
const extRefls = project.getChildrenByKind(AppiumPluginReflectionKind.Extension as any);
expect(extRefls).to.not.be.empty;
expect(_.find(extRefls, {name: NAME_BUILTIN_COMMAND_MODULE})).to.be.undefined;
});
});
});
});