docs(docutils): more docstrings dogg
MODIFY
packages/docutils/lib/model.ts
packages/docutils/lib/model.ts
/**
- * Utility types
+ * Various data models, mostly referring to config files
+ *
* @module
*/
@@ -8,6 +9,10 @@ import type {TypeDocOptions} from 'typedoc';
/**
* A `tsconfig.json` file w/ `$schema` prop
+ *
+ * Due to some `unknown` types in {@linkcode type-fest.TsConfigJson}, we cannot use that type
+ * directly and need to use `Jsonify`.
+ *
*/
export type TsConfigJson = Jsonify<
TsConfigJsonBase & {
@@ -17,6 +22,9 @@ export type TsConfigJson = Jsonify<
/**
* A `typedoc.json` file w/ `$schema` and `extends` props
+ *
+ * TypeDoc doesn't recognize `$schema` and ignores it; its own config parser expands the value of
+ * `extends` before it reaches its `Options` class. This is why we cannot use `TypeDocOptions` directly.
*/
export type TypeDocJson = Jsonify<
Partial<TypeDocOptions> & {
@@ -25,6 +33,10 @@ export type TypeDocJson = Jsonify<
}
>;
+/**
+ * This was built by hand from the MkDocs documentation
+ * @see https://www.mkdocs.org/user-guide/configuration/
+ */
export type MkDocsYml = Jsonify<{
copyright?: string;
dev_addr?: string;
@@ -52,6 +64,10 @@ export type MkDocsYml = Jsonify<{
watch?: string[];
}>;
+/**
+ * The `theme` prop of an `mkdocs.yml`
+ * @see {@linkcode MkDocsYml}
+ */
export type MkDocsYmlTheme =
| string
| ({
@@ -61,6 +77,9 @@ export type MkDocsYmlTheme =
static_templates?: string[];
} & Record<string, JsonValue>);
+/**
+ * The data parsed from a `requirements.txt` file, or the output of `pip list --json`
+ */
export interface PipPackage {
name: string;
version: string;

MODIFY
packages/docutils/lib/nav.ts
packages/docutils/lib/nav.ts
+/**
+ * Handles updating/adding the `nav` property of `mkdocs.yml`, based on the output of `typedoc`;
+ * specifically, the command documentation generated by `@appium/typedoc-plugin-appium`.
+ *
+ * @module
+ */
+
import {fs} from '@appium/support';
import _ from 'lodash';
import path from 'node:path';
@@ -19,7 +26,7 @@ const DEFAULT_REFERENCE_HEADER = 'Reference';
const log = logger.withTag('mkdocs-nav');
/**
- *
+ * Update the `nav` property of `mkdocs.yml` with a list of "command" files generated by TypeDoc via `@appium/typedoc-plugin-appium`
* @param opts - Options
* @todo implement `dryRun` option
*/
@@ -155,15 +162,37 @@ const isStringArray = _.overEvery(_.isArray, _.partial(_.every, _, _.isString))
value: any
) => value is string[];
+/**
+ * Options for {@linkcode updateNav}
+ */
export interface UpdateNavOpts<S extends string> {
+ /**
+ * Current working directory
+ */
cwd?: string;
+ /**
+ * Path to `mkdocs.yml`
+ */
mkdocsYml?: string;
+ /**
+ * Path to `package.json`
+ */
packageJson?: string;
+ /**
+ * The name of the header in `nav` to use for reference docs.
+ */
referenceHeader?: S;
/**
* If `true`, do not add a reference header to `nav` if one does not exist
*/
noReferenceHeader?: boolean;
+ /**
+ * Path to `typedoc.json`
+ */
typedocJson?: string;
+ /**
+ * If `true`, do not write any files
+ * @remarks Not yet implemented
+ */
dryRun?: boolean;
}

MODIFY
packages/docutils/lib/scaffold.ts
packages/docutils/lib/scaffold.ts
+/**
+ * Implementation of a generic "create and/or update some file" task
+ * @module
+ */
+
import {fs} from '@appium/support';
import logger from './logger';
import path from 'node:path';
@@ -13,7 +18,7 @@ const NAME_ERR_ENOENT = 'ENOENT';
const NAME_ERR_EEXIST = 'EEXIST';
const log = logger.withTag('init');
-const dryRunLog = logger.withTag('dry-run');
+const dryRunLog = log.withTag('dry-run');
/**
* Creates a unified patch for display in "dry run" mode
@@ -35,11 +40,19 @@ function makePatch<T extends JsonValue>(
);
}
+/**
+ * Options for a task which are not the {@link ScaffoldTaskOptions base options}
+ */
export type TaskSpecificOpts<Opts extends ScaffoldTaskOptions> = Omit<
Opts,
- 'overwrite' | 'cwd' | 'packageJson' | 'dest' | 'dryRun'
+ keyof ScaffoldTaskOptions
>;
+/**
+ * A function which performs some scaffolding task.
+ *
+ * @see {@linkcode createScaffoldTask}
+ */
export type ScaffoldTask<Opts extends ScaffoldTaskOptions, T extends JsonObject> = (
opts: Opts
) => Promise<ScaffoldTaskResult<T>>;
@@ -135,23 +148,47 @@ export function createScaffoldTask<Opts extends ScaffoldTaskOptions, T extends J
};
}
+/**
+ * Optional function which can be used to post-process the content of a file. Usually used to merge
+ * various options with existing content
+ */
export type ScaffoldTaskTransformer<Opts extends ScaffoldTaskOptions, T extends JsonValue> = (
content: Readonly<T>,
opts: TaskSpecificOpts<Opts>,
pkg: NormalizedPackageJson
) => T;
-export type ScaffoldTaskDeserializer<T extends JsonValue> = (content: string) => T;
+/**
+ * A function which deserializes a string into a JS value.
+ */
+export type ScaffoldTaskDeserializer<T> = (content: string) => T;
-export type ScaffoldTaskSerializer<T extends JsonValue> = (content: T) => string;
+/**
+ * A function which serializes a JS value into a string.
+ */
+export type ScaffoldTaskSerializer<T> = (content: T) => string;
+/**
+ * Options for {@linkcode createScaffoldTask}
+ */
export interface CreateScaffoldTaskOptions<Opts extends ScaffoldTaskOptions, T extends JsonValue> {
+ /**
+ * Transformer function
+ */
transform?: ScaffoldTaskTransformer<Opts, T>;
+ /**
+ * Deserializer function
+ */
deserialize?: ScaffoldTaskDeserializer<T>;
+ /**
+ * Serializer function
+ */
serialize?: ScaffoldTaskSerializer<T>;
- toggleOption?: string;
}
+/**
+ * Base options for all scaffold tasks
+ */
export interface ScaffoldTaskOptions {
/**
* Current working directory
@@ -175,7 +212,16 @@ export interface ScaffoldTaskOptions {
packageJson?: string;
}
+/**
+ * The return value of a {@linkcode ScaffoldTask}
+ */
export interface ScaffoldTaskResult<T> {
+ /**
+ * The content of whatever it wrote or would write
+ */
content: T;
+ /**
+ * The filepath of whatever it wrote or would write
+ */
path: string;
}

MODIFY
packages/docutils/lib/typedoc.ts
packages/docutils/lib/typedoc.ts
+/**
+ * Runs TypeDoc
+ *
+ * @module
+ */
+
import {fs} from '@appium/support';
import glob from 'glob';
import _ from 'lodash';
@@ -37,15 +43,15 @@ const argify: (obj: Record<string, string>) => string[] = _.flow(_.entries, _.fl
);
/**
- * Executes TypeDoc in the current process
+ * Executes TypeDoc _in the current process_
*
- * Monkeypatch's TypeDoc's homebrew "glob" implementation because it is broken
+ * Monkeypatches TypeDoc's homebrew "glob" implementation because it is broken
* @param pkgRoot - Package root path
* @param opts - TypeDoc options
*/
export async function runTypedoc(pkgRoot: string, opts: Record<string, string>) {
monkeyPatchGlob(pkgRoot);
- log.debug('Monkeypatched TypeDoc\'s "glob" implementation');
+ log.debug('Monkeypatched TypeDoc');
const args = argify(opts);
log.debug('TypeDoc args:', args);
@@ -53,19 +59,39 @@ export async function runTypedoc(pkgRoot: string, opts: Record<string, string>)
app.options.addReader(new TypeDocReader());
app.options.addReader(new ArgumentsReader(100, args));
app.bootstrap();
- log.debug('Final TypeDoc options: %O', app.options.getRawValues());
- const project = app.convert();
+ log.debug('Frozen options as computed by TypeDoc: %O', app.options.getRawValues());
const out = app.options.getValue('out');
- if (project && out) {
- await app.generateDocs(project, out);
+ const project = app.convert();
+ if (project) {
+ return await app.generateDocs(project, out);
}
+
+ throw new DocutilsError('TypeDoc found nothing to document. Is your package empty?');
}
+/**
+ * Options for {@linkcode buildReference}
+ */
export interface BuildReferenceOptions {
+ /**
+ * Path to `typedoc.json`
+ */
typedocJson?: string;
+ /**
+ * Current working directory
+ */
cwd?: string;
+ /**
+ * Path to `package.json`
+ */
packageJson?: string;
+ /**
+ * Path to `tsconfig.json`
+ */
tsconfigJson?: string;
+ /**
+ * "Title" for generated docs; this corresponds to {@linkcode typedoc.TypeDocOptionMap.name}
+ */
title?: string;
/**
* This is here because we pass it thru to TypeDoc
@@ -73,6 +99,11 @@ export interface BuildReferenceOptions {
logLevel?: LogLevelName;
}
+/**
+ * Log level names as supported by this package
+ *
+ * Used to convert our log level to TypeDoc's
+ */
type LogLevelName = 'debug' | 'info' | 'error' | 'warn';
/**
@@ -88,6 +119,10 @@ const TypeDocLogLevelMap: Record<LogLevelName, string> = {
error: 'Error',
};
+/**
+ * Build reference documentation via TypeDoc
+ * @param opts - Options
+ */
export async function buildReference({
typedocJson: typeDocJsonPath,
cwd = process.cwd(),

MODIFY
packages/docutils/lib/validate.ts
packages/docutils/lib/validate.ts
+/**
+ * Validates an environment for building documentation
+ *
+ * @module
+ */
+
import {fs} from '@appium/support';
import chalk from 'chalk';
import _ from 'lodash';
@@ -44,6 +50,9 @@ const TYPEDOC_VERSION_REGEX = /TypeDoc\s(\d+\.\d+\..+)/;
const log = logger.withTag('validate');
+/**
+ * The "kinds" of validation which were requested to be performed
+ */
export type ValidationKind =
| typeof NAME_PYTHON
| typeof NAME_TYPESCRIPT
@@ -56,52 +65,61 @@ export type ValidationKind =
*
* Whenever a method _rejects or throws_, this is considered an "unexpected" error, and the validation
* will abort.
- */
-export class DocutilsValidator extends EventEmitter {
- /**
- * Mapping of error messages to errors.
- *
- * Used to prevent duplicate emission of errors and track error count; if non-empty, the validation
- * process should be considered to have failed.
*
- * Reset after {@linkcode DocutilsValidator.validate validate} completes.
+ * @todo Use [`strict-event-emitter-types`](https://npm.im/strict-event-emitter-types)
*/
- private emittedErrors = new Map<string, DocutilsError>();
-
+export class DocutilsValidator extends EventEmitter {
/**
* Current working directory. Defaults to `process.cwd()`
* @todo This cannot yet be overriden by user
*/
protected readonly cwd: string;
+
/**
* Path to `npm` executable. Defaults to `npm`
*/
protected readonly npmPath: string;
+
/**
* Path to `python` executable. Defaults to `python`
*/
protected readonly pythonPath: string;
+
/**
* List of validations to perform
*/
protected readonly validations = new Set<ValidationKind>();
+ /**
+ * Mapping of error messages to errors.
+ *
+ * Used to prevent duplicate emission of errors and track error count; if non-empty, the validation
+ * process should be considered to have failed.
+ *
+ * Reset after {@linkcode DocutilsValidator.validate validate} completes.
+ */
+ protected emittedErrors = new Map<string, DocutilsError>();
+
/**
* Path to `mkdocs.yml`. If not provided, will be lazily resolved.
*/
protected mkDocsYmlPath: string | undefined;
+
/**
* Path to `package.json`. If not provided, will be lazily resolved.
*/
protected packageJsonPath: string | undefined;
+
/**
* Path to the package directory. If not provided, will be lazily resolved.
*/
protected pkgDir: string | undefined;
+
/**
* Path to `tsconfig.json`. If not provided, will be lazily resolved.
*/
protected tsconfigJsonPath: string | undefined;
+
/**
* Path to `typedoc.json`. If not provided, will be lazily resolved.
*/
@@ -112,16 +130,19 @@ export class DocutilsValidator extends EventEmitter {
* @event
*/
public static readonly BEGIN = 'begin';
+
/**
* Emitted when validation ends with an error count
* @event
*/
public static readonly END = 'end';
+
/**
* Emitted when a validation fails, with the associated {@linkcode DocutilsError}
* @event
*/
public static readonly FAILURE = 'fail';
+
/**
* Emitted when a validation succeeds
* @event
@@ -217,6 +238,10 @@ export class DocutilsValidator extends EventEmitter {
);
}
+ /**
+ * Emits a {@linkcode DocutilsValidator.SUCCESS} event
+ * @param message Success message
+ */
protected ok(message: string) {
this.emit(DocutilsValidator.SUCCESS, message);
}
@@ -248,10 +273,16 @@ export class DocutilsValidator extends EventEmitter {
return requiredPackages;
}
+ /**
+ * Resets the cache of emitted errors
+ */
protected reset() {
this.emittedErrors.clear();
}
+ /**
+ * @todo implement
+ */
protected async validateMkDocs() {}
/**
@@ -552,15 +583,49 @@ export class DocutilsValidator extends EventEmitter {
}
}
+/**
+ * Options for {@linkcode DocutilsValidator} constructor
+ */
+
export interface DocutilsValidatorOpts {
+ /**
+ * Current working directory
+ */
cwd?: string;
+ /**
+ * Path to `mkdocs.yml`
+ */
mkdocsYml?: string;
+ /**
+ * Path to `npm` executable
+ */
npm?: string;
+ /**
+ * Path to `package.json`
+ */
packageJson?: string;
+ /**
+ * If `true`, run Python validation
+ */
python?: boolean;
+ /**
+ * Path to `python` executable
+ */
pythonPath?: string;
+ /**
+ * Path to `tsconfig.json`
+ */
tsconfigJson?: string;
+ /**
+ * If `true`, run TypeDoc validation
+ */
typedoc?: boolean;
+ /**
+ * Path to `typedoc.json`
+ */
typedocJson?: string;
+ /**
+ * If `true`, run TypeScript validation
+ */
typescript?: boolean;
}

docs(docutils): more docstrings dogg