@appium/docutils 0.3.10 → 0.3.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/bin/appium-docs.js +5 -0
  2. package/build/lib/builder/deploy.d.ts.map +1 -1
  3. package/build/lib/builder/deploy.js +15 -13
  4. package/build/lib/builder/deploy.js.map +1 -1
  5. package/build/lib/builder/nav.d.ts.map +1 -1
  6. package/build/lib/builder/nav.js +2 -0
  7. package/build/lib/builder/nav.js.map +1 -1
  8. package/build/lib/builder/site.d.ts.map +1 -1
  9. package/build/lib/builder/site.js +16 -13
  10. package/build/lib/builder/site.js.map +1 -1
  11. package/build/lib/cli/command/validate.d.ts +10 -1
  12. package/build/lib/cli/command/validate.d.ts.map +1 -1
  13. package/build/lib/cli/command/validate.js +10 -1
  14. package/build/lib/cli/command/validate.js.map +1 -1
  15. package/build/lib/cli/index.d.ts +2 -2
  16. package/build/lib/cli/index.js +0 -0
  17. package/build/lib/fs.d.ts +10 -15
  18. package/build/lib/fs.d.ts.map +1 -1
  19. package/build/lib/fs.js +32 -15
  20. package/build/lib/fs.js.map +1 -1
  21. package/build/lib/init.d.ts +6 -6
  22. package/build/lib/init.d.ts.map +1 -1
  23. package/build/lib/init.js +2 -1
  24. package/build/lib/init.js.map +1 -1
  25. package/build/lib/logger.d.ts +1 -1
  26. package/build/lib/logger.d.ts.map +1 -1
  27. package/build/lib/logger.js +3 -3
  28. package/build/lib/logger.js.map +1 -1
  29. package/build/lib/util.d.ts.map +1 -1
  30. package/build/lib/util.js +1 -1
  31. package/build/lib/util.js.map +1 -1
  32. package/build/lib/validate.d.ts +14 -7
  33. package/build/lib/validate.d.ts.map +1 -1
  34. package/build/lib/validate.js +24 -19
  35. package/build/lib/validate.js.map +1 -1
  36. package/lib/builder/deploy.ts +28 -15
  37. package/lib/builder/nav.ts +2 -0
  38. package/lib/builder/site.ts +23 -21
  39. package/lib/cli/command/validate.ts +10 -1
  40. package/lib/fs.ts +40 -19
  41. package/lib/init.ts +4 -2
  42. package/lib/logger.ts +9 -10
  43. package/lib/util.ts +1 -2
  44. package/lib/validate.ts +48 -29
  45. package/package.json +5 -4
package/lib/fs.ts CHANGED
@@ -3,27 +3,26 @@
3
3
  * @module
4
4
  */
5
5
 
6
- import findUp from 'find-up';
7
- import YAML from 'yaml';
8
- import readPkg, {NormalizedPackageJson, PackageJson} from 'read-pkg';
9
- import path from 'node:path';
10
- import {JsonValue} from 'type-fest';
11
6
  import {fs} from '@appium/support';
7
+ import findUp from 'find-up';
12
8
  import * as JSON5 from 'json5';
13
9
  import _ from 'lodash';
10
+ import path from 'node:path';
14
11
  import _pkgDir from 'pkg-dir';
15
- import {getLogger} from './logger';
12
+ import readPkg, {NormalizedPackageJson, PackageJson} from 'read-pkg';
13
+ import {JsonValue} from 'type-fest';
16
14
  import {Application, TypeDocReader} from 'typedoc';
15
+ import YAML from 'yaml';
17
16
  import {
18
- NAME_TYPEDOC_JSON,
19
17
  NAME_MKDOCS_YML,
20
- NAME_PACKAGE_JSON,
21
- NAME_MKDOCS,
22
18
  NAME_NPM,
19
+ NAME_PACKAGE_JSON,
23
20
  NAME_PYTHON,
24
- NAME_MIKE,
21
+ NAME_TYPEDOC,
22
+ NAME_TYPEDOC_JSON,
25
23
  } from './constants';
26
24
  import {DocutilsError} from './error';
25
+ import {getLogger} from './logger';
27
26
  import {MkDocsYml} from './model';
28
27
 
29
28
  const log = getLogger('fs');
@@ -207,27 +206,49 @@ export function safeWriteFile(filepath: string, content: JsonValue, overwrite =
207
206
  /**
208
207
  * `which` with memoization
209
208
  */
210
- export const cachedWhich = _.memoize(fs.which);
209
+ const cachedWhich = _.memoize(fs.which as typeof import('which'));
211
210
 
212
211
  /**
213
- * Finds `mkdocs` executable
212
+ * Finds `npm` executable
214
213
  */
215
- export const whichMkDocs = _.partial(cachedWhich, NAME_MKDOCS);
214
+ export const whichNpm = _.partial(cachedWhich, NAME_NPM, {nothrow: true});
216
215
 
217
216
  /**
218
- * Finds `npm` executable
217
+ * Finds `python` executable
219
218
  */
220
- export const whichNpm = _.partial(cachedWhich, NAME_NPM);
219
+ const whichPython = _.partial(cachedWhich, NAME_PYTHON, {nothrow: true});
221
220
 
222
221
  /**
223
- * Finds `python` executable
222
+ * Finds `python3` executable
224
223
  */
225
- export const whichPython = _.partial(cachedWhich, NAME_PYTHON);
224
+ const whichPython3 = _.partial(cachedWhich, `${NAME_PYTHON}3`, {nothrow: true});
226
225
 
227
226
  /**
228
- * Finds `mike` executable
227
+ * Finds `typedoc` executable
229
228
  */
230
- export const whichMike = _.partial(cachedWhich, NAME_MIKE);
229
+ const whichTypeDoc = _.partial(cachedWhich, NAME_TYPEDOC, {nothrow: true});
230
+
231
+ /**
232
+ * Finds the `typedoc` executable.
233
+ *
234
+ * 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`.
235
+ */
236
+ export const findTypeDoc = _.memoize(async (cwd = process.cwd()): Promise<string | undefined> => {
237
+ // .cmd is for win32, of course. note that glob _always_ uses posix dir separators.
238
+ const globResult =
239
+ (await fs.glob('node_modules/.bin/typedoc?(.cmd)', {cwd, nodir: true})) ??
240
+ (await fs.glob('node_modules/**/typedoc/bin/typedoc', {cwd, nodir: true, follow: true}));
241
+ return _.first(globResult) ?? (await whichTypeDoc());
242
+ });
243
+
244
+ /**
245
+ * Finds the `python3` or `python` executable in the user's `PATH`.
246
+ *
247
+ * `python3` is preferred over `python`, since the latter could be Python 2.
248
+ */
249
+ export const findPython = _.memoize(
250
+ async (): Promise<string | undefined> => (await whichPython3()) ?? (await whichPython())
251
+ );
231
252
 
232
253
  /**
233
254
  * Reads an `mkdocs.yml` file, merges inherited configs, and returns the result. The result is cached.
package/lib/init.ts CHANGED
@@ -20,7 +20,7 @@ import {createScaffoldTask, ScaffoldTaskOptions} from './scaffold';
20
20
  import {getLogger} from './logger';
21
21
  import {MkDocsYml, TsConfigJson, TypeDocJson} from './model';
22
22
  import _ from 'lodash';
23
- import {stringifyJson5, stringifyYaml} from './fs';
23
+ import {findPython, stringifyJson5, stringifyYaml} from './fs';
24
24
 
25
25
  /**
26
26
  * Data for the base `mkdocs.yml` file
@@ -158,10 +158,12 @@ export const initMkDocs = createScaffoldTask<InitMkDocsOptions, MkDocsYml>(
158
158
  * @param opts Options
159
159
  */
160
160
  export async function initPython({
161
- pythonPath = NAME_PYTHON,
161
+ pythonPath,
162
162
  dryRun = false,
163
163
  upgrade = false,
164
164
  }: InitPythonOptions = {}): Promise<void> {
165
+ pythonPath = pythonPath ?? (await findPython()) ?? NAME_PYTHON;
166
+
165
167
  const args = ['-m', 'pip', 'install', '-r', REQUIREMENTS_TXT_PATH];
166
168
  if (upgrade) {
167
169
  args.push('--upgrade');
package/lib/logger.ts CHANGED
@@ -6,20 +6,19 @@
6
6
  * @module
7
7
  */
8
8
 
9
- import figures from 'figures';
10
- import logSymbols from 'log-symbols';
11
- import chalk, {ForegroundColor, BackgroundColor} from 'chalk';
9
+ import chalk, {type BackgroundColor, type ForegroundColor} from 'chalk';
12
10
  import consola, {
13
- logType as LogType,
14
- ConsolaReporterLogObject,
11
+ type Consola,
12
+ type ConsolaReporterLogObject,
15
13
  FancyReporter,
16
- FancyReporterOptions,
17
- Consola,
18
- ConsolaOptions,
19
- LogLevel,
14
+ type FancyReporterOptions,
15
+ type LogLevel,
16
+ type logType as LogType,
20
17
  } from 'consola';
21
- import {DEFAULT_LOG_LEVEL, LogLevelMap} from './constants';
18
+ import figures from 'figures';
22
19
  import _ from 'lodash';
20
+ import logSymbols from 'log-symbols';
21
+ import {DEFAULT_LOG_LEVEL, LogLevelMap} from './constants';
23
22
 
24
23
  /**
25
24
  * This is a reporter for `consola` which uses some extra/custom icons and colors.
package/lib/util.ts CHANGED
@@ -6,7 +6,6 @@
6
6
  import _ from 'lodash';
7
7
  import {SpawnOptions, spawn} from 'node:child_process';
8
8
  import path from 'node:path';
9
- import type {SubProcess} from 'teen_process';
10
9
 
11
10
  /**
12
11
  * Computes a relative path, prepending `./`
@@ -26,7 +25,7 @@ export function stopwatch(id: string) {
26
25
  const start = Date.now();
27
26
  stopwatch.cache.set(id, start);
28
27
  return () => {
29
- const result = Date.now() - stopwatch.cache.get(id)!;
28
+ const result = Date.now() - (stopwatch.cache.get(id) ?? 0);
30
29
  stopwatch.cache.delete(id);
31
30
  return result;
32
31
  };
package/lib/validate.ts CHANGED
@@ -31,14 +31,14 @@ import {
31
31
  } from './constants';
32
32
  import {DocutilsError} from './error';
33
33
  import {
34
- findPkgDir,
35
34
  findMkDocsYml,
35
+ findPkgDir,
36
+ findTypeDoc,
36
37
  readJson5,
38
+ readMkDocsYml,
37
39
  readTypedocJson,
38
- whichMkDocs,
39
40
  whichNpm,
40
- whichPython,
41
- readMkDocsYml,
41
+ findPython,
42
42
  } from './fs';
43
43
  import {getLogger} from './logger';
44
44
  import {MkDocsYml, PipPackage, TypeDocJson} from './model';
@@ -62,7 +62,7 @@ const TYPEDOC_VERSION_REGEX = /TypeDoc\s(\d+\.\d+\..+)/;
62
62
  /**
63
63
  * Matches the MkDocs version string from `mkdocs --version`
64
64
  */
65
- const MKDOCS_VERSION_REGEX = /mkdocs,\s+version\s+(\d+\.\d+\.\S+)/;
65
+ const MKDOCS_VERSION_REGEX = /\s+version\s+(\d+\.\d+\.\S+)/;
66
66
 
67
67
  const log = getLogger('validate');
68
68
 
@@ -95,12 +95,12 @@ export class DocutilsValidator extends EventEmitter {
95
95
  /**
96
96
  * Path to `npm` executable.
97
97
  */
98
- protected readonly npmPath: string | undefined;
98
+ protected readonly npmPath?: string;
99
99
 
100
100
  /**
101
101
  * Path to `python` executable.
102
102
  */
103
- protected readonly pythonPath: string | undefined;
103
+ protected readonly pythonPath?: string;
104
104
 
105
105
  /**
106
106
  * List of validations to perform
@@ -120,27 +120,29 @@ export class DocutilsValidator extends EventEmitter {
120
120
  /**
121
121
  * Path to `mkdocs.yml`. If not provided, will be lazily resolved.
122
122
  */
123
- protected mkDocsYmlPath: string | undefined;
123
+ protected mkDocsYmlPath?: string;
124
124
 
125
125
  /**
126
126
  * Path to `package.json`. If not provided, will be lazily resolved.
127
127
  */
128
- protected packageJsonPath: string | undefined;
128
+ protected packageJsonPath?: string;
129
129
 
130
130
  /**
131
131
  * Path to the package directory. If not provided, will be lazily resolved.
132
132
  */
133
- protected pkgDir: string | undefined;
133
+ protected pkgDir?: string;
134
134
 
135
135
  /**
136
136
  * Path to `tsconfig.json`. If not provided, will be lazily resolved.
137
137
  */
138
- protected tsconfigJsonPath: string | undefined;
138
+ protected tsconfigJsonPath?: string;
139
139
 
140
140
  /**
141
141
  * Path to `typedoc.json`. If not provided, will be lazily resolved.
142
142
  */
143
- protected typeDocJsonPath: string | undefined;
143
+ protected typeDocJsonPath?: string;
144
+
145
+ protected typeDocPath?: string;
144
146
 
145
147
  /**
146
148
  * Emitted when validation begins with a list of validation kinds to be performed
@@ -181,6 +183,7 @@ export class DocutilsValidator extends EventEmitter {
181
183
  this.typeDocJsonPath = opts.typedocJson;
182
184
  this.npmPath = opts.npm;
183
185
  this.mkDocsYmlPath = opts.mkdocsYml;
186
+ this.typeDocPath = opts.typedocPath;
184
187
 
185
188
  if (opts.python) {
186
189
  this.validations.add(NAME_PYTHON);
@@ -314,21 +317,19 @@ export class DocutilsValidator extends EventEmitter {
314
317
  * Validates that the correct version of `mkdocs` is installed
315
318
  */
316
319
  protected async validateMkDocs() {
317
- let mkDocsPath: string | undefined;
318
- try {
319
- mkDocsPath = await whichMkDocs();
320
- } catch {
321
- // _pretty sure_ the exception code is always ENOENT
320
+ const pythonPath = this.pythonPath ?? (await findPython());
321
+
322
+ if (!pythonPath) {
322
323
  return this.fail(
323
- `Could not find ${NAME_MKDOCS} executable in PATH. If it is installed, check your PATH environment variable.`
324
+ `Could not find ${NAME_PYTHON} executable in PATH. If it is installed, check your PATH environment variable.`
324
325
  );
325
326
  }
326
327
 
327
328
  let rawMkDocsVersion: string | undefined;
328
329
  try {
329
- ({stdout: rawMkDocsVersion} = await exec(mkDocsPath, ['--version']));
330
+ ({stdout: rawMkDocsVersion} = await exec(pythonPath, ['-m', NAME_MKDOCS, '--version']));
330
331
  } catch (err) {
331
- return this.fail(`${mkDocsPath} --version failed: ${err}`);
332
+ return this.fail(`Failed to get MkDocs version: ${err}`);
332
333
  }
333
334
  const match = rawMkDocsVersion.match(MKDOCS_VERSION_REGEX);
334
335
  if (match) {
@@ -343,12 +344,12 @@ export class DocutilsValidator extends EventEmitter {
343
344
  const {version: mkDocsReqdVersion} = mkDocsPipPkg;
344
345
  if (version !== mkDocsReqdVersion) {
345
346
  return this.fail(
346
- `${NAME_MKDOCS} at ${mkDocsPath} is v${version}, but ${REQUIREMENTS_TXT_PATH} requires v${mkDocsReqdVersion}`
347
+ `${NAME_MKDOCS} is v${version}, but ${REQUIREMENTS_TXT_PATH} requires v${mkDocsReqdVersion}`
347
348
  );
348
349
  }
349
350
  } else {
350
351
  throw new DocutilsError(
351
- `Could not parse version from "${mkDocsPath} --version". This is a bug. Output was ${rawMkDocsVersion}`
352
+ `Could not parse version from MkDocs. This is a bug. Output was ${rawMkDocsVersion}`
352
353
  );
353
354
  }
354
355
 
@@ -423,7 +424,7 @@ export class DocutilsValidator extends EventEmitter {
423
424
  */
424
425
  protected async validatePythonDeps() {
425
426
  let pipListOutput: string;
426
- const pythonPath = this.pythonPath ?? (await whichPython());
427
+ const pythonPath = this.pythonPath ?? (await findPython());
427
428
  if (!pythonPath) {
428
429
  return this.fail(`Could not find ${NAME_PYTHON} in PATH. Is it installed?`);
429
430
  }
@@ -499,7 +500,7 @@ export class DocutilsValidator extends EventEmitter {
499
500
  * Asserts that the Python version is 3.x
500
501
  */
501
502
  protected async validatePythonVersion() {
502
- const pythonPath = this.pythonPath ?? (await whichPython());
503
+ const pythonPath = this.pythonPath ?? (await findPython());
503
504
  if (!pythonPath) {
504
505
  return this.fail(`Could not find ${NAME_PYTHON} in PATH. Is it installed?`);
505
506
  }
@@ -520,17 +521,30 @@ export class DocutilsValidator extends EventEmitter {
520
521
  /**
521
522
  * Asserts TypeDoc is installed, runnable, the correct version, and that the config file is readable
522
523
  * and constaints required options
524
+ *
525
+ * @todo Another option would be to `npm exec typedoc@<version>` which delegates to `npx`.
523
526
  */
524
527
  protected async validateTypeDoc() {
525
528
  const pkgDir = await this.findPkgDir();
529
+ const typeDocPath = this.typeDocPath ?? (await findTypeDoc(pkgDir));
530
+
531
+ if (!typeDocPath) {
532
+ return this.fail(`Could not find ${NAME_TYPEDOC}; is it installed?`);
533
+ }
534
+ log.debug('Found %s at %s', NAME_TYPEDOC, typeDocPath);
535
+
526
536
  let rawTypeDocVersion: string;
527
537
  let typeDocVersion: string;
528
538
  try {
529
- ({stdout: rawTypeDocVersion} = await exec('npm', ['exec', NAME_TYPEDOC, '--', '--version'], {
539
+ ({stdout: rawTypeDocVersion} = await exec(process.execPath, [typeDocPath, '--version'], {
530
540
  cwd: pkgDir,
531
541
  }));
532
- } catch {
533
- return this.fail(`Could not find ${NAME_TYPEDOC} executable from ${pkgDir}`);
542
+ } catch (err) {
543
+ return this.fail(
544
+ `Could not execute ${process.execPath} ${typeDocPath} from ${pkgDir}. Reason: ${
545
+ (err as Error).message
546
+ }`
547
+ );
534
548
  }
535
549
 
536
550
  if (rawTypeDocVersion) {
@@ -543,7 +557,8 @@ export class DocutilsValidator extends EventEmitter {
543
557
  );
544
558
  }
545
559
 
546
- const reqdTypeDocVersion = DOCUTILS_PKG.dependencies!.typedoc!;
560
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
561
+ const reqdTypeDocVersion = DOCUTILS_PKG.dependencies!.typedoc!; // this is our own package.json
547
562
  if (!satisfies(typeDocVersion, reqdTypeDocVersion)) {
548
563
  return this.fail(
549
564
  `Found TypeDoc version ${typeDocVersion}, but ${reqdTypeDocVersion} is required`
@@ -596,7 +611,7 @@ export class DocutilsValidator extends EventEmitter {
596
611
  if (!typeDocJson.out) {
597
612
  return this.fail(
598
613
  new DocutilsError(
599
- `Missing "out" property in ${relTypeDocJsonPath}; path "${DEFAULT_REL_TYPEDOC_OUT_PATH} is recommended`
614
+ `Missing "out" property in ${relTypeDocJsonPath}; path "${DEFAULT_REL_TYPEDOC_OUT_PATH}" is recommended`
600
615
  )
601
616
  );
602
617
  }
@@ -714,6 +729,10 @@ export interface DocutilsValidatorOpts {
714
729
  * If `true`, run TypeDoc validation
715
730
  */
716
731
  typedoc?: boolean;
732
+ /**
733
+ * Path to `typedoc` executable
734
+ */
735
+ typedocPath?: string;
717
736
  /**
718
737
  * Path to `typedoc.json`
719
738
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appium/docutils",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Documentation generation utilities for Appium and related projects",
5
5
  "keywords": [
6
6
  "automation",
@@ -28,7 +28,7 @@
28
28
  "lib": "lib"
29
29
  },
30
30
  "bin": {
31
- "appium-docs": "./build/lib/cli/index.js"
31
+ "appium-docs": "./bin/appium-docs.js"
32
32
  },
33
33
  "files": [
34
34
  "index.js",
@@ -49,10 +49,11 @@
49
49
  "start": "node ./build/lib/cli/index.js"
50
50
  },
51
51
  "dependencies": {
52
- "@appium/support": "^4.0.0",
52
+ "@appium/support": "^4.0.1",
53
53
  "@appium/tsconfig": "^0.3.0",
54
54
  "@appium/typedoc-plugin-appium": "^0.6.4",
55
55
  "@sliphua/lilconfig-ts-loader": "3.2.2",
56
+ "@types/which": "3.0.0",
56
57
  "chalk": "4.1.2",
57
58
  "consola": "2.15.3",
58
59
  "diff": "5.1.0",
@@ -83,5 +84,5 @@
83
84
  "publishConfig": {
84
85
  "access": "public"
85
86
  },
86
- "gitHead": "6b245534c213f3b8d6405515aee1e89133295098"
87
+ "gitHead": "2ca15818701b0af3c909dcc696dcd26ae6f50014"
87
88
  }