Compare commits

..
Author SHA1 Message Date
Christopher Hiller 2ca1581870 chore: publish
- appium@2.0.0-beta.69
 - @appium/docutils@0.3.12
2023-05-19 14:56:44 -07:00
Christopher Hiller 6aec50b074 chore(docutils): lint
- consolidate some eslint overrides
2023-05-19 13:42:08 -07:00
Christopher Hiller 426830d14a fix(docutils): exec mike/mkdocs via python -m
- also adds a "custom typedoc path" option
- consolidate the `whichPython*` functions into a single `findPython` fn
2023-05-19 13:42:08 -07:00
Christopher Hiller 9538c34131 fix(docutils): add @types/which as it is exported 2023-05-19 13:42:08 -07:00
Christopher Hiller 5d24ea1ad2 fix(docutils): run mkdocs via python -m 2023-05-19 13:42:08 -07:00
Christopher Hiller db73971018 fix(docutils): provide CJS executable for proper linking 2023-05-19 13:42:08 -07:00
Christopher Hiller 7b17754786 fix(docutils): try python3 if python not in PATH 2023-05-19 13:42:08 -07:00
Christopher Hiller ba07d2a854 docs(typedoc-plugin-appium): update README.md
- add option documentation
- add warning about using the module directly
- add instructions for updating snapshots
2023-05-19 12:49:48 -07:00
17 changed files with 262 additions and 137 deletions
+9 -7
View File
@@ -10,12 +10,6 @@
"files": "packages/*/test/**/*",
"rules": {"func-names": "off"}
},
{
"files": ["packages/*/index.js", "packages/*/scripts/**/*.js", "test/*.js"],
"parserOptions": {
"sourceType": "script"
}
},
{
"files": [
"packages/appium/support.js",
@@ -27,9 +21,17 @@
}
},
{
"files": ["./test/setup.js", "./**/scripts/**/*.js", "./packages/*/index.js"],
"files": [
"./test/setup.js",
"./**/scripts/**/*.js",
"./packages/*/index.js",
"./packages/docutils/bin/appium-docs.js"
],
"rules": {
"@typescript-eslint/no-var-requires": "off"
},
"parserOptions": {
"sourceType": "script"
}
},
{
+17 -5
View File
@@ -22614,13 +22614,13 @@
}
},
"packages/appium": {
"version": "2.0.0-beta.68",
"version": "2.0.0-beta.69",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@appium/base-driver": "^9.3.9",
"@appium/base-plugin": "^2.2.9",
"@appium/docutils": "^0.3.11",
"@appium/docutils": "^0.3.12",
"@appium/schema": "^0.2.6",
"@appium/support": "^4.0.1",
"@appium/types": "^0.11.1",
@@ -22915,13 +22915,14 @@
},
"packages/docutils": {
"name": "@appium/docutils",
"version": "0.3.11",
"version": "0.3.12",
"license": "Apache-2.0",
"dependencies": {
"@appium/support": "^4.0.1",
"@appium/tsconfig": "^0.3.0",
"@appium/typedoc-plugin-appium": "^0.6.4",
"@sliphua/lilconfig-ts-loader": "3.2.2",
"@types/which": "3.0.0",
"chalk": "4.1.2",
"consola": "2.15.3",
"diff": "5.1.0",
@@ -22946,13 +22947,18 @@
"yargs-parser": "21.1.1"
},
"bin": {
"appium-docs": "build/lib/cli/index.js"
"appium-docs": "bin/appium-docs.js"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0",
"npm": ">=8"
}
},
"packages/docutils/node_modules/@types/which": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.0.tgz",
"integrity": "sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ=="
},
"packages/docutils/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -23696,6 +23702,7 @@
"@appium/tsconfig": "^0.3.0",
"@appium/typedoc-plugin-appium": "^0.6.4",
"@sliphua/lilconfig-ts-loader": "3.2.2",
"@types/which": "3.0.0",
"chalk": "4.1.2",
"consola": "2.15.3",
"diff": "5.1.0",
@@ -23720,6 +23727,11 @@
"yargs-parser": "21.1.1"
},
"dependencies": {
"@types/which": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.0.tgz",
"integrity": "sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ=="
},
"ansi-styles": {
"version": "4.3.0",
"requires": {
@@ -27794,7 +27806,7 @@
"requires": {
"@appium/base-driver": "^9.3.9",
"@appium/base-plugin": "^2.2.9",
"@appium/docutils": "^0.3.11",
"@appium/docutils": "^0.3.12",
"@appium/schema": "^0.2.6",
"@appium/support": "^4.0.1",
"@appium/types": "^0.11.1",
+8
View File
@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.0.0-beta.69](https://github.com/appium/appium/compare/appium@2.0.0-beta.68...appium@2.0.0-beta.69) (2023-05-19)
**Note:** Version bump only for package appium
## [2.0.0-beta.68](https://github.com/appium/appium/compare/appium@2.0.0-beta.67...appium@2.0.0-beta.68) (2023-05-19)
**Note:** Version bump only for package appium
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "appium",
"version": "2.0.0-beta.68",
"version": "2.0.0-beta.69",
"description": "Automation for Apps.",
"keywords": [
"automation",
@@ -62,7 +62,7 @@
"dependencies": {
"@appium/base-driver": "^9.3.9",
"@appium/base-plugin": "^2.2.9",
"@appium/docutils": "^0.3.11",
"@appium/docutils": "^0.3.12",
"@appium/schema": "^0.2.6",
"@appium/support": "^4.0.1",
"@appium/types": "^0.11.1",
+13
View File
@@ -3,6 +3,19 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.3.12](https://github.com/appium/appium/compare/@appium/docutils@0.3.11...@appium/docutils@0.3.12) (2023-05-19)
### Bug Fixes
* **docutils:** add @types/which as it is exported ([9538c34](https://github.com/appium/appium/commit/9538c34131cd2f8a3c45039efd65678bc0980497))
* **docutils:** exec mike/mkdocs via python -m ([426830d](https://github.com/appium/appium/commit/426830d14a348f163535a7f935a65b028008738d))
* **docutils:** provide CJS executable for proper linking ([db73971](https://github.com/appium/appium/commit/db73971018b560ca47527173094720eee3d20a55))
* **docutils:** run mkdocs via python -m ([5d24ea1](https://github.com/appium/appium/commit/5d24ea1ad294fa28f7ecce125e5342b081a84c83))
* **docutils:** try python3 if python not in PATH ([7b17754](https://github.com/appium/appium/commit/7b177547865a8343625cf089c97cebfb93fd6955))
## [0.3.11](https://github.com/appium/appium/compare/@appium/docutils@0.3.10...@appium/docutils@0.3.11) (2023-05-19)
**Note:** Version bump only for package @appium/docutils
+5
View File
@@ -0,0 +1,5 @@
#!/usr/bin/env node
'use strict';
module.exports = require('../build/lib/cli');
+28 -15
View File
@@ -13,10 +13,12 @@ import {
DEFAULT_SERVE_HOST,
DEFAULT_SERVE_PORT,
NAME_BIN,
NAME_MIKE,
NAME_MKDOCS_YML,
NAME_PYTHON,
} from '../constants';
import {DocutilsError} from '../error';
import {findMkDocsYml, readPackageJson, whichMike} from '../fs';
import {findMkDocsYml, findPython, readPackageJson} from '../fs';
import {getLogger} from '../logger';
import {argify, spawnBackgroundProcess, SpawnBackgroundProcessOpts, stopwatch} from '../util';
@@ -24,31 +26,33 @@ const log = getLogger('builder:deploy');
/**
* Runs `mike serve`
* @param pythonPath Path to Python 3 executable
* @param args Extra args to `mike build`
* @param opts Extra options for `teen_process.Subprocess.start`
* @param mikePath Path to `mike` executable
*/
async function doServe(
pythonPath: string,
args: string[] = [],
opts: SpawnBackgroundProcessOpts = {},
mikePath?: string
opts: SpawnBackgroundProcessOpts = {}
) {
mikePath = mikePath ?? (await whichMike());
const finalArgs = ['serve', ...args];
return spawnBackgroundProcess(mikePath, finalArgs, opts);
const finalArgs = ['-m,', NAME_MIKE, 'serve', ...args];
return spawnBackgroundProcess(pythonPath, finalArgs, opts);
}
/**
* Runs `mike build`
* @param pythonPath Path to Python 3 executable
* @param args Extra args to `mike build`
* @param opts Extra options to `teen_process.exec`
* @param mikePath Path to `mike` executable
*/
async function doDeploy(args: string[] = [], opts: TeenProcessExecOptions = {}, mikePath?: string) {
mikePath = mikePath ?? (await whichMike());
const finalArgs = ['deploy', ...args];
log.debug('Launching %s with args: %O', mikePath, finalArgs);
return await exec(mikePath, finalArgs, opts);
async function doDeploy(
pythonPath: string,
args: string[] = [],
opts: TeenProcessExecOptions = {}
) {
const finalArgs = ['-m', NAME_MIKE, 'deploy', ...args];
log.debug('Executing %s via: %s %O', NAME_MIKE, pythonPath, finalArgs);
return await exec(pythonPath, finalArgs, opts);
}
/**
@@ -90,6 +94,15 @@ export async function deploy({
execOpts,
}: DeployOpts = {}) {
const stop = stopwatch('deploy');
const pythonPath = await findPython();
if (!pythonPath) {
throw new DocutilsError(
`Could not find ${NAME_PYTHON}3/${NAME_PYTHON} executable in PATH; please install Python v3`
);
}
mkDocsYmlPath = mkDocsYmlPath ?? (await findMkDocsYml(cwd));
if (!mkDocsYmlPath) {
throw new DocutilsError(
@@ -122,7 +135,7 @@ export async function deploy({
}
stop(); // discard
// unsure about how SIGHUP is handled here
await doServe(mikeArgs, serveOpts);
await doServe(pythonPath, mikeArgs, serveOpts);
} else {
log.info('Deploying into branch %s', branch);
const mikeArgs = [
@@ -137,7 +150,7 @@ export async function deploy({
if (alias) {
mikeArgs.push(alias);
}
await doDeploy(mikeArgs, execOpts);
await doDeploy(pythonPath, mikeArgs, execOpts);
log.success('Finished deployment into branch %s (%dms)', branch, stop());
}
+2
View File
@@ -75,6 +75,7 @@ export function parseNav(nav: MkDocsYmlNav): ParsedNavData[] {
const queue: QueueItem[] = [{entries, keypath: ''}];
while (queue.length) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const {entries, keypath} = queue.shift()!;
for (const [key, item] of entries) {
if (_.isString(item)) {
@@ -153,6 +154,7 @@ function getRootHeaderKeypath(headerItems: ParsedNavData[], header: string) {
// these are the parts of the keypath of the first item, which will contain the header string. it
// dosn't matter whether we pick the first one or any one; they will all contain the same root
// keypath by definition.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const rootHeaderKeypathParts = _.toPath(_.first(headerItems)!.keypath);
// this is the keypath up to the header string, inclusive.
+23 -21
View File
@@ -7,9 +7,9 @@
import path from 'node:path';
import {exec, TeenProcessExecOptions} from 'teen_process';
import {DEFAULT_SITE_DIR, NAME_BIN, NAME_MKDOCS_YML} from '../constants';
import {DEFAULT_SITE_DIR, NAME_BIN, NAME_MKDOCS, NAME_MKDOCS_YML, NAME_PYTHON} from '../constants';
import {DocutilsError} from '../error';
import {findMkDocsYml, readMkDocsYml, whichMkDocs} from '../fs';
import {findMkDocsYml, findPython, readMkDocsYml} from '../fs';
import {getLogger} from '../logger';
import {relative, spawnBackgroundProcess, SpawnBackgroundProcessOpts, stopwatch} from '../util';
@@ -17,37 +17,31 @@ const log = getLogger('mkdocs');
/**
* Runs `mkdocs serve`
* @param pythonPath Path to Python 3 executable
* @param args Extra args to `mkdocs build`
* @param opts Extra options for `teen_process.Subprocess.start`
* @param mkDocsPath Path to `mkdocs` executable
*/
async function doServe(
pythonPath: string,
args: string[] = [],
opts: SpawnBackgroundProcessOpts = {},
mkDocsPath?: string
opts: SpawnBackgroundProcessOpts = {}
) {
mkDocsPath = mkDocsPath ?? (await whichMkDocs());
const finalArgs = ['serve', ...args];
log.debug('Launching %s with args: %s', mkDocsPath, finalArgs);
return spawnBackgroundProcess(mkDocsPath, finalArgs, opts);
const finalArgs = ['-m', NAME_MKDOCS, 'serve', ...args];
log.debug('Executing %s via: %s, %O', NAME_MKDOCS, pythonPath, finalArgs);
return spawnBackgroundProcess(pythonPath, finalArgs, opts);
}
/**
* Runs `mkdocs build`
* @param pythonPath Path to Python 3 executable
* @param args Extra args to `mkdocs build`
* @param opts Extra options to `teen_process.exec`
* @param mkDocsPath Path to `mkdocs` executable
*/
async function doBuild(
args: string[] = [],
opts: TeenProcessExecOptions = {},
mkDocsPath?: string
) {
mkDocsPath = mkDocsPath ?? (await whichMkDocs());
const finalArgs = ['build', ...args];
log.debug('Launching %s with args: %O', mkDocsPath, finalArgs);
return await exec(mkDocsPath, finalArgs, opts);
async function doBuild(pythonPath: string, args: string[] = [], opts: TeenProcessExecOptions = {}) {
const finalArgs = ['-m', NAME_MKDOCS, 'build', ...args];
log.debug('Executing %s via: %s, %O', NAME_MKDOCS, pythonPath, finalArgs);
return await exec(pythonPath, finalArgs, opts);
}
/**
@@ -63,6 +57,14 @@ export async function buildSite({
execOpts,
}: BuildMkDocsOpts = {}) {
const stop = stopwatch('build-mkdocs');
const pythonPath = await findPython();
if (!pythonPath) {
throw new DocutilsError(
`Could not find ${NAME_PYTHON}3/${NAME_PYTHON} executable in PATH; please install Python v3`
);
}
mkDocsYmlPath = mkDocsYmlPath
? path.resolve(process.cwd(), mkDocsYmlPath)
: await findMkDocsYml(cwd);
@@ -77,10 +79,10 @@ export async function buildSite({
}
if (serve) {
// unsure about how SIGHUP is handled here
await doServe(mkdocsArgs, serveOpts);
await doServe(pythonPath, mkdocsArgs, serveOpts);
} else {
log.info('Building site...');
await doBuild(mkdocsArgs, execOpts);
await doBuild(pythonPath, mkdocsArgs, execOpts);
let relSiteDir;
if (siteDir) {
relSiteDir = relative(cwd, siteDir);
+10 -1
View File
@@ -50,7 +50,7 @@ const opts = {
},
'python-path': {
defaultDescription: '(derived from shell)',
description: 'Path to python 3 executable',
description: 'Path to python3 executable',
group: ValidateCommandGroup.Paths,
nargs: 1,
normalize: true,
@@ -81,6 +81,15 @@ const opts = {
requiresArg: true,
type: 'string',
},
'typedoc-path': {
defaultDescription: '(derived from shell)',
description: 'Path to typedoc executable',
group: ValidateCommandGroup.Paths,
nargs: 1,
normalize: true,
requiresArg: true,
type: 'string',
},
typescript: {
default: true,
description: 'Validate TypeScript environment',
+41 -20
View File
@@ -3,27 +3,26 @@
* @module
*/
import findUp from 'find-up';
import YAML from 'yaml';
import readPkg, {NormalizedPackageJson, PackageJson} from 'read-pkg';
import path from 'node:path';
import {JsonValue} from 'type-fest';
import {fs} from '@appium/support';
import findUp from 'find-up';
import * as JSON5 from 'json5';
import _ from 'lodash';
import path from 'node:path';
import _pkgDir from 'pkg-dir';
import {getLogger} from './logger';
import readPkg, {NormalizedPackageJson, PackageJson} from 'read-pkg';
import {JsonValue} from 'type-fest';
import {Application, TypeDocReader} from 'typedoc';
import YAML from 'yaml';
import {
NAME_TYPEDOC_JSON,
NAME_MKDOCS_YML,
NAME_PACKAGE_JSON,
NAME_MKDOCS,
NAME_NPM,
NAME_PACKAGE_JSON,
NAME_PYTHON,
NAME_MIKE,
NAME_TYPEDOC,
NAME_TYPEDOC_JSON,
} from './constants';
import {DocutilsError} from './error';
import {getLogger} from './logger';
import {MkDocsYml} from './model';
const log = getLogger('fs');
@@ -207,27 +206,49 @@ export function safeWriteFile(filepath: string, content: JsonValue, overwrite =
/**
* `which` with memoization
*/
export const cachedWhich = _.memoize(fs.which);
/**
* Finds `mkdocs` executable
*/
export const whichMkDocs = _.partial(cachedWhich, NAME_MKDOCS);
const cachedWhich = _.memoize(fs.which as typeof import('which'));
/**
* Finds `npm` executable
*/
export const whichNpm = _.partial(cachedWhich, NAME_NPM);
export const whichNpm = _.partial(cachedWhich, NAME_NPM, {nothrow: true});
/**
* Finds `python` executable
*/
export const whichPython = _.partial(cachedWhich, NAME_PYTHON);
const whichPython = _.partial(cachedWhich, NAME_PYTHON, {nothrow: true});
/**
* Finds `mike` executable
* Finds `python3` executable
*/
export const whichMike = _.partial(cachedWhich, NAME_MIKE);
const whichPython3 = _.partial(cachedWhich, `${NAME_PYTHON}3`, {nothrow: true});
/**
* Finds `typedoc` executable
*/
const whichTypeDoc = _.partial(cachedWhich, NAME_TYPEDOC, {nothrow: true});
/**
* Finds the `typedoc` executable.
*
* Looks in the `node_modules/.bin` dir from the current working directory, and if this fails, in the `node_modules` dir for the file which `.bin/typedoc` should be a symlink of, and if _that_ fails, try the `PATH`.
*/
export const findTypeDoc = _.memoize(async (cwd = process.cwd()): Promise<string | undefined> => {
// .cmd is for win32, of course. note that glob _always_ uses posix dir separators.
const globResult =
(await fs.glob('node_modules/.bin/typedoc?(.cmd)', {cwd, nodir: true})) ??
(await fs.glob('node_modules/**/typedoc/bin/typedoc', {cwd, nodir: true, follow: true}));
return _.first(globResult) ?? (await whichTypeDoc());
});
/**
* Finds the `python3` or `python` executable in the user's `PATH`.
*
* `python3` is preferred over `python`, since the latter could be Python 2.
*/
export const findPython = _.memoize(
async (): Promise<string | undefined> => (await whichPython3()) ?? (await whichPython())
);
/**
* Reads an `mkdocs.yml` file, merges inherited configs, and returns the result. The result is cached.
+4 -2
View File
@@ -20,7 +20,7 @@ import {createScaffoldTask, ScaffoldTaskOptions} from './scaffold';
import {getLogger} from './logger';
import {MkDocsYml, TsConfigJson, TypeDocJson} from './model';
import _ from 'lodash';
import {stringifyJson5, stringifyYaml} from './fs';
import {findPython, stringifyJson5, stringifyYaml} from './fs';
/**
* Data for the base `mkdocs.yml` file
@@ -158,10 +158,12 @@ export const initMkDocs = createScaffoldTask<InitMkDocsOptions, MkDocsYml>(
* @param opts Options
*/
export async function initPython({
pythonPath = NAME_PYTHON,
pythonPath,
dryRun = false,
upgrade = false,
}: InitPythonOptions = {}): Promise<void> {
pythonPath = pythonPath ?? (await findPython()) ?? NAME_PYTHON;
const args = ['-m', 'pip', 'install', '-r', REQUIREMENTS_TXT_PATH];
if (upgrade) {
args.push('--upgrade');
+9 -10
View File
@@ -6,20 +6,19 @@
* @module
*/
import figures from 'figures';
import logSymbols from 'log-symbols';
import chalk, {ForegroundColor, BackgroundColor} from 'chalk';
import chalk, {type BackgroundColor, type ForegroundColor} from 'chalk';
import consola, {
logType as LogType,
ConsolaReporterLogObject,
type Consola,
type ConsolaReporterLogObject,
FancyReporter,
FancyReporterOptions,
Consola,
ConsolaOptions,
LogLevel,
type FancyReporterOptions,
type LogLevel,
type logType as LogType,
} from 'consola';
import {DEFAULT_LOG_LEVEL, LogLevelMap} from './constants';
import figures from 'figures';
import _ from 'lodash';
import logSymbols from 'log-symbols';
import {DEFAULT_LOG_LEVEL, LogLevelMap} from './constants';
/**
* This is a reporter for `consola` which uses some extra/custom icons and colors.
+1 -2
View File
@@ -6,7 +6,6 @@
import _ from 'lodash';
import {SpawnOptions, spawn} from 'node:child_process';
import path from 'node:path';
import type {SubProcess} from 'teen_process';
/**
* Computes a relative path, prepending `./`
@@ -26,7 +25,7 @@ export function stopwatch(id: string) {
const start = Date.now();
stopwatch.cache.set(id, start);
return () => {
const result = Date.now() - stopwatch.cache.get(id)!;
const result = Date.now() - (stopwatch.cache.get(id) ?? 0);
stopwatch.cache.delete(id);
return result;
};
+49 -30
View File
@@ -31,14 +31,14 @@ import {
} from './constants';
import {DocutilsError} from './error';
import {
findPkgDir,
findMkDocsYml,
findPkgDir,
findTypeDoc,
readJson5,
readTypedocJson,
whichMkDocs,
whichNpm,
whichPython,
readMkDocsYml,
readTypedocJson,
whichNpm,
findPython,
} from './fs';
import {getLogger} from './logger';
import {MkDocsYml, PipPackage, TypeDocJson} from './model';
@@ -62,7 +62,7 @@ const TYPEDOC_VERSION_REGEX = /TypeDoc\s(\d+\.\d+\..+)/;
/**
* Matches the MkDocs version string from `mkdocs --version`
*/
const MKDOCS_VERSION_REGEX = /mkdocs,\s+version\s+(\d+\.\d+\.\S+)/;
const MKDOCS_VERSION_REGEX = /\s+version\s+(\d+\.\d+\.\S+)/;
const log = getLogger('validate');
@@ -95,12 +95,12 @@ export class DocutilsValidator extends EventEmitter {
/**
* Path to `npm` executable.
*/
protected readonly npmPath: string | undefined;
protected readonly npmPath?: string;
/**
* Path to `python` executable.
*/
protected readonly pythonPath: string | undefined;
protected readonly pythonPath?: string;
/**
* List of validations to perform
@@ -120,27 +120,29 @@ export class DocutilsValidator extends EventEmitter {
/**
* Path to `mkdocs.yml`. If not provided, will be lazily resolved.
*/
protected mkDocsYmlPath: string | undefined;
protected mkDocsYmlPath?: string;
/**
* Path to `package.json`. If not provided, will be lazily resolved.
*/
protected packageJsonPath: string | undefined;
protected packageJsonPath?: string;
/**
* Path to the package directory. If not provided, will be lazily resolved.
*/
protected pkgDir: string | undefined;
protected pkgDir?: string;
/**
* Path to `tsconfig.json`. If not provided, will be lazily resolved.
*/
protected tsconfigJsonPath: string | undefined;
protected tsconfigJsonPath?: string;
/**
* Path to `typedoc.json`. If not provided, will be lazily resolved.
*/
protected typeDocJsonPath: string | undefined;
protected typeDocJsonPath?: string;
protected typeDocPath?: string;
/**
* Emitted when validation begins with a list of validation kinds to be performed
@@ -181,6 +183,7 @@ export class DocutilsValidator extends EventEmitter {
this.typeDocJsonPath = opts.typedocJson;
this.npmPath = opts.npm;
this.mkDocsYmlPath = opts.mkdocsYml;
this.typeDocPath = opts.typedocPath;
if (opts.python) {
this.validations.add(NAME_PYTHON);
@@ -314,21 +317,19 @@ export class DocutilsValidator extends EventEmitter {
* Validates that the correct version of `mkdocs` is installed
*/
protected async validateMkDocs() {
let mkDocsPath: string | undefined;
try {
mkDocsPath = await whichMkDocs();
} catch {
// _pretty sure_ the exception code is always ENOENT
const pythonPath = this.pythonPath ?? (await findPython());
if (!pythonPath) {
return this.fail(
`Could not find ${NAME_MKDOCS} executable in PATH. If it is installed, check your PATH environment variable.`
`Could not find ${NAME_PYTHON} executable in PATH. If it is installed, check your PATH environment variable.`
);
}
let rawMkDocsVersion: string | undefined;
try {
({stdout: rawMkDocsVersion} = await exec(mkDocsPath, ['--version']));
({stdout: rawMkDocsVersion} = await exec(pythonPath, ['-m', NAME_MKDOCS, '--version']));
} catch (err) {
return this.fail(`${mkDocsPath} --version failed: ${err}`);
return this.fail(`Failed to get MkDocs version: ${err}`);
}
const match = rawMkDocsVersion.match(MKDOCS_VERSION_REGEX);
if (match) {
@@ -343,12 +344,12 @@ export class DocutilsValidator extends EventEmitter {
const {version: mkDocsReqdVersion} = mkDocsPipPkg;
if (version !== mkDocsReqdVersion) {
return this.fail(
`${NAME_MKDOCS} at ${mkDocsPath} is v${version}, but ${REQUIREMENTS_TXT_PATH} requires v${mkDocsReqdVersion}`
`${NAME_MKDOCS} is v${version}, but ${REQUIREMENTS_TXT_PATH} requires v${mkDocsReqdVersion}`
);
}
} else {
throw new DocutilsError(
`Could not parse version from "${mkDocsPath} --version". This is a bug. Output was ${rawMkDocsVersion}`
`Could not parse version from MkDocs. This is a bug. Output was ${rawMkDocsVersion}`
);
}
@@ -423,7 +424,7 @@ export class DocutilsValidator extends EventEmitter {
*/
protected async validatePythonDeps() {
let pipListOutput: string;
const pythonPath = this.pythonPath ?? (await whichPython());
const pythonPath = this.pythonPath ?? (await findPython());
if (!pythonPath) {
return this.fail(`Could not find ${NAME_PYTHON} in PATH. Is it installed?`);
}
@@ -499,7 +500,7 @@ export class DocutilsValidator extends EventEmitter {
* Asserts that the Python version is 3.x
*/
protected async validatePythonVersion() {
const pythonPath = this.pythonPath ?? (await whichPython());
const pythonPath = this.pythonPath ?? (await findPython());
if (!pythonPath) {
return this.fail(`Could not find ${NAME_PYTHON} in PATH. Is it installed?`);
}
@@ -520,17 +521,30 @@ export class DocutilsValidator extends EventEmitter {
/**
* Asserts TypeDoc is installed, runnable, the correct version, and that the config file is readable
* and constaints required options
*
* @todo Another option would be to `npm exec typedoc@<version>` which delegates to `npx`.
*/
protected async validateTypeDoc() {
const pkgDir = await this.findPkgDir();
const typeDocPath = this.typeDocPath ?? (await findTypeDoc(pkgDir));
if (!typeDocPath) {
return this.fail(`Could not find ${NAME_TYPEDOC}; is it installed?`);
}
log.debug('Found %s at %s', NAME_TYPEDOC, typeDocPath);
let rawTypeDocVersion: string;
let typeDocVersion: string;
try {
({stdout: rawTypeDocVersion} = await exec('npm', ['exec', NAME_TYPEDOC, '--', '--version'], {
({stdout: rawTypeDocVersion} = await exec(process.execPath, [typeDocPath, '--version'], {
cwd: pkgDir,
}));
} catch {
return this.fail(`Could not find ${NAME_TYPEDOC} executable from ${pkgDir}`);
} catch (err) {
return this.fail(
`Could not execute ${process.execPath} ${typeDocPath} from ${pkgDir}. Reason: ${
(err as Error).message
}`
);
}
if (rawTypeDocVersion) {
@@ -543,7 +557,8 @@ export class DocutilsValidator extends EventEmitter {
);
}
const reqdTypeDocVersion = DOCUTILS_PKG.dependencies!.typedoc!;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const reqdTypeDocVersion = DOCUTILS_PKG.dependencies!.typedoc!; // this is our own package.json
if (!satisfies(typeDocVersion, reqdTypeDocVersion)) {
return this.fail(
`Found TypeDoc version ${typeDocVersion}, but ${reqdTypeDocVersion} is required`
@@ -596,7 +611,7 @@ export class DocutilsValidator extends EventEmitter {
if (!typeDocJson.out) {
return this.fail(
new DocutilsError(
`Missing "out" property in ${relTypeDocJsonPath}; path "${DEFAULT_REL_TYPEDOC_OUT_PATH} is recommended`
`Missing "out" property in ${relTypeDocJsonPath}; path "${DEFAULT_REL_TYPEDOC_OUT_PATH}" is recommended`
)
);
}
@@ -714,6 +729,10 @@ export interface DocutilsValidatorOpts {
* If `true`, run TypeDoc validation
*/
typedoc?: boolean;
/**
* Path to `typedoc` executable
*/
typedocPath?: string;
/**
* Path to `typedoc.json`
*/
+3 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@appium/docutils",
"version": "0.3.11",
"version": "0.3.12",
"description": "Documentation generation utilities for Appium and related projects",
"keywords": [
"automation",
@@ -28,7 +28,7 @@
"lib": "lib"
},
"bin": {
"appium-docs": "./build/lib/cli/index.js"
"appium-docs": "./bin/appium-docs.js"
},
"files": [
"index.js",
@@ -53,6 +53,7 @@
"@appium/tsconfig": "^0.3.0",
"@appium/typedoc-plugin-appium": "^0.6.4",
"@sliphua/lilconfig-ts-loader": "3.2.2",
"@types/which": "3.0.0",
"chalk": "4.1.2",
"consola": "2.15.3",
"diff": "5.1.0",
+38 -20
View File
@@ -6,32 +6,34 @@
This package leverages [TypeDoc](https://typedoc.org) to generate command documentation (HTTP endpoints, payload information, etc.) for Appium v2+ drivers and plugins.
## Important Note
_If you are an Appium extension author and just want to build HTML docs_, **don't install this directly**--instead, install [`@appium/docutils`](https://github.com/appium/appium/tree/master/packages/docutils), which is a higher-level package that configures everything for you.
If you _only_ want to build markdown docs for your extension, then you can use this package directly.
## Installation
`npm` v8+ is required to install this package.
```bash
npm install appium@next typedoc @appium/typedoc-plugin-appium --save-dev
npm install @appium/typedoc-plugin-appium --save-dev
```
`typedoc` and `appium` are peer dependencies of this package. Newer versions of `npm` will install these automatically (if possible).
The above command installs the plugin as well as all necessary peer dependencies. See [`package.json`](https://github.com/appium/appium/blob/master/packages/docutils/package.json) for the full list of dependencies.
## Usage
TypeDoc is configured via a `typedoc.json` or `typedoc.js` file ([read the docs](https://typedoc.org/guides/options/) for more information).
An Appium extension author wishing to generate documentation for their extension will need to create a `typedoc.json`. At minimum, it should contain:
> TODO: The plugin should be able to detect the entry points automatically, so this should not be necessary
An Appium extension author wishing to generate markdown documentation for their extension will need to create a `typedoc.json`. At minimum, it should contain:
```json
{
"entryPointStrategy": "packages",
"entryPoints": [
"./node_modules/appium",
"./node_modules/@appium/base-driver",
"./node_modules/@appium/types",
"."
],
"entryPoints": ["."],
"name": "<name of extension>",
"theme": "appium",
"out": "<path to output directory>"
}
```
@@ -42,21 +44,37 @@ Once this file is created, you can run `typedoc` to generate the documentation,
This plugin supports all of the options from [typedoc-plugin-markdown](https://npm.im/typedoc-plugin-markdown), as well as the following:
### `commandsDir`
### `outputModules`
> TODO
### `forceBreadcrumbs`
> TODO
`boolean` - Output module, class, interface, and other type information (the usual TypeDoc output) in addition to command documentation. This is needed for full documentation of types. _Default value: `true`_
### `outputBuiltinCommands`
> TODO
`boolean` - Outputs _all_ commands and types from Appium builtins--not just your extension. This is intended to be used by Appium itself. _Default value: `false`_
### `outputModules`
### `packageTitles`
> TODO
`Array<{name: string, title: string}>`: An array of objects containing module name `name` and display name `title`. By default, the module name is used for the title; use this to override that behavior. _Default value: `undefined`_
### `commandsDir`
`string` - The name of the "commands" directory relative to the TypeDoc output directory (`out`). _Default value: `commands`_
### `forceBreadcrumbs`
`boolean` - Forces breadcrumbs to be output; overrides `hideBreadcrumbs` from `typedoc-plugin-markdown`. _Default value: `false`_
## Development
This packages uses snapshot tests to assert the generated markdown is correct. If you have made changes which affect the plugin's output, you will need to update the snapshots.
To update the snapshots, execute:
```bash
UPDATE_SNAPSHOT=1 npm test
```
This will (likely) modify the snapshots in your working copy, so you will then need to commit them.
## License