UNPKG

@appium/docutils

Version:

Documentation generation utilities for Appium and related projects

98 lines (89 loc) 3.08 kB
/** * Utilities * @module */ import _ from 'lodash'; import {SpawnOptions, spawn} from 'node:child_process'; import path from 'node:path'; /** * Computes a relative path, prepending `./` */ export const relative = _.curry( (from: string, to: string): string => `.${path.sep}${path.relative(from, to)}` ); /** * A stopwatch-like thing * * Used for displaying elapsed time in milliseconds * @param id - Unique identifier * @returns Function that returns the elapsed time in milliseconds */ export function stopwatch(id: string) { const start = Date.now(); stopwatch.cache.set(id, start); return () => { const result = Date.now() - (stopwatch.cache.get(id) ?? 0); stopwatch.cache.delete(id); return result; }; } stopwatch.cache = new Map<string, number>(); /** * Converts a tuple to an object; use for extracting parameter types from a function signature */ export type TupleToObject< T extends readonly any[], M extends Record<Exclude<keyof T, keyof any[]>, PropertyKey> > = {[K in Exclude<keyof T, keyof any[]> as M[K]]: T[K]}; /** * Type guard to narrow an array to a string array * @param value any value * @returns `true` if the array is `string[]` */ export const isStringArray = _.overEvery(_.isArray, _.partial(_.every, _, _.isString)) as ( value: any ) => value is string[]; /** * Converts an object of string values to an array of arguments for CLI * * Supports `boolean` and `number` values as well. `boolean`s are assumed to be flags which default * to `false`, so they will only be added to the array if the value is `true`. */ export const argify: (obj: Record<string, string | number | boolean | undefined>) => string[] = _.flow( _.entries, (list) => list.map(([key, value]) => { if (value === true) { return [`--${key}`]; } else if (value === false || value === undefined) { return; } return [`--${key}`, value]; }), _.flatten ); /** * Spawns a long-running "background" child process. This is expected to only return control to the * parent process in the case of a nonzero exit code from the child process. * @param command Command to run * @param args Args to pass to command * @param opts Spawn options. `{stdio: 'inherit'}` will always be true * @privateRemarks `teen_process` is good for running a one-shot command, but not so great for * background tasks; we use node's `child_process` directly here to pass `stdio` through, since * `teen_process` basically does not respect `{stdio: 'inherit'}`. */ export async function spawnBackgroundProcess(command: string, args: string[], opts: SpawnOptions) { return new Promise<void>((resolve, reject) => { spawn(command, args, {...opts, stdio: 'inherit'}) .on('error', reject) .on('close', (code) => { // can be null or number if (code) { return reject(new Error(`${command} exited with code ${code}`)); } resolve(); }); }); } export type SpawnBackgroundProcessOpts = Omit<SpawnOptions, 'stdio'>;