@appium/docutils 0.2.2 → 0.3.1

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 (97) hide show
  1. package/LICENSE +1 -1
  2. package/build/lib/builder/deploy.d.ts +3 -3
  3. package/build/lib/builder/deploy.d.ts.map +1 -1
  4. package/build/lib/builder/deploy.js +6 -5
  5. package/build/lib/builder/deploy.js.map +1 -1
  6. package/build/lib/builder/index.d.ts +4 -0
  7. package/build/lib/builder/index.d.ts.map +1 -1
  8. package/build/lib/builder/index.js +4 -0
  9. package/build/lib/builder/index.js.map +1 -1
  10. package/build/lib/builder/nav.d.ts +1 -1
  11. package/build/lib/builder/nav.d.ts.map +1 -1
  12. package/build/lib/builder/nav.js +3 -3
  13. package/build/lib/builder/nav.js.map +1 -1
  14. package/build/lib/builder/reference.d.ts.map +1 -1
  15. package/build/lib/builder/reference.js +1 -19
  16. package/build/lib/builder/reference.js.map +1 -1
  17. package/build/lib/builder/site.d.ts +3 -3
  18. package/build/lib/builder/site.d.ts.map +1 -1
  19. package/build/lib/builder/site.js +4 -5
  20. package/build/lib/builder/site.js.map +1 -1
  21. package/build/lib/cli/check.d.ts +19 -0
  22. package/build/lib/cli/check.d.ts.map +1 -0
  23. package/build/lib/cli/check.js +58 -0
  24. package/build/lib/cli/check.js.map +1 -0
  25. package/build/lib/cli/command/build.d.ts +189 -174
  26. package/build/lib/cli/command/build.d.ts.map +1 -1
  27. package/build/lib/cli/command/build.js +56 -38
  28. package/build/lib/cli/command/build.js.map +1 -1
  29. package/build/lib/cli/command/index.d.ts +4 -0
  30. package/build/lib/cli/command/index.d.ts.map +1 -1
  31. package/build/lib/cli/command/index.js +4 -0
  32. package/build/lib/cli/command/index.js.map +1 -1
  33. package/build/lib/cli/command/init.d.ts +156 -139
  34. package/build/lib/cli/command/init.d.ts.map +1 -1
  35. package/build/lib/cli/command/init.js +52 -27
  36. package/build/lib/cli/command/init.js.map +1 -1
  37. package/build/lib/cli/command/validate.d.ts +71 -63
  38. package/build/lib/cli/command/validate.d.ts.map +1 -1
  39. package/build/lib/cli/command/validate.js +31 -20
  40. package/build/lib/cli/command/validate.js.map +1 -1
  41. package/build/lib/cli/index.d.ts.map +1 -1
  42. package/build/lib/cli/index.js +29 -12
  43. package/build/lib/cli/index.js.map +1 -1
  44. package/build/lib/constants.d.ts +4 -0
  45. package/build/lib/constants.d.ts.map +1 -1
  46. package/build/lib/constants.js +5 -1
  47. package/build/lib/constants.js.map +1 -1
  48. package/build/lib/error.d.ts +5 -0
  49. package/build/lib/error.d.ts.map +1 -1
  50. package/build/lib/error.js +5 -0
  51. package/build/lib/error.js.map +1 -1
  52. package/build/lib/fs.d.ts +1 -1
  53. package/build/lib/fs.d.ts.map +1 -1
  54. package/build/lib/fs.js +2 -2
  55. package/build/lib/fs.js.map +1 -1
  56. package/build/lib/index.d.ts +4 -0
  57. package/build/lib/index.d.ts.map +1 -1
  58. package/build/lib/index.js +4 -0
  59. package/build/lib/index.js.map +1 -1
  60. package/build/lib/init.d.ts +13 -5
  61. package/build/lib/init.d.ts.map +1 -1
  62. package/build/lib/init.js +12 -7
  63. package/build/lib/init.js.map +1 -1
  64. package/build/lib/logger.js.map +1 -1
  65. package/build/lib/mike.d.ts.map +1 -1
  66. package/build/lib/mike.js +4 -0
  67. package/build/lib/mike.js.map +1 -1
  68. package/build/lib/util.d.ts +15 -3
  69. package/build/lib/util.d.ts.map +1 -1
  70. package/build/lib/util.js +26 -1
  71. package/build/lib/util.js.map +1 -1
  72. package/build/lib/validate.d.ts +4 -1
  73. package/build/lib/validate.d.ts.map +1 -1
  74. package/build/lib/validate.js +9 -7
  75. package/build/lib/validate.js.map +1 -1
  76. package/lib/builder/deploy.ts +11 -8
  77. package/lib/builder/index.ts +5 -0
  78. package/lib/builder/nav.ts +2 -3
  79. package/lib/builder/reference.ts +2 -22
  80. package/lib/builder/site.ts +11 -10
  81. package/lib/cli/check.ts +87 -0
  82. package/lib/cli/command/build.ts +61 -43
  83. package/lib/cli/command/index.ts +5 -0
  84. package/lib/cli/command/init.ts +54 -29
  85. package/lib/cli/command/validate.ts +33 -25
  86. package/lib/cli/index.ts +23 -4
  87. package/lib/constants.ts +5 -0
  88. package/lib/error.ts +6 -0
  89. package/lib/fs.ts +6 -3
  90. package/lib/index.ts +5 -0
  91. package/lib/init.ts +23 -6
  92. package/lib/logger.ts +1 -1
  93. package/lib/mike.js +5 -0
  94. package/lib/util.ts +27 -4
  95. package/lib/validate.ts +10 -9
  96. package/package.json +8 -10
  97. package/requirements.txt +1 -1
@@ -5,13 +5,14 @@
5
5
  * @module
6
6
  */
7
7
 
8
+ import {spawn, SpawnOptions} from 'node:child_process';
8
9
  import path from 'node:path';
9
- import {exec, SubProcess, TeenProcessExecOptions} from 'teen_process';
10
- import {NAME_BIN, NAME_MKDOCS, NAME_MKDOCS_YML} from '../constants';
10
+ import {exec, TeenProcessExecOptions} from 'teen_process';
11
+ import {NAME_BIN, NAME_MKDOCS, NAME_MKDOCS_YML, NAME_THEME} from '../constants';
11
12
  import {DocutilsError} from '../error';
12
13
  import {findMkDocsYml, readMkDocsYml, whichMkDocs} from '../fs';
13
14
  import logger from '../logger';
14
- import {relative, stopwatch, TeenProcessSubprocessStartOpts} from '../util';
15
+ import {relative, spawnBackgroundProcess, SpawnBackgroundProcessOpts, stopwatch} from '../util';
15
16
 
16
17
  const log = logger.withTag('mkdocs');
17
18
 
@@ -23,14 +24,14 @@ const log = logger.withTag('mkdocs');
23
24
  */
24
25
  async function doServe(
25
26
  args: string[] = [],
26
- {startDetector, detach, timeoutMs}: TeenProcessSubprocessStartOpts = {},
27
+ opts: SpawnBackgroundProcessOpts = {},
27
28
  mkDocsPath?: string
28
29
  ) {
29
30
  mkDocsPath = mkDocsPath ?? (await whichMkDocs());
30
31
  const finalArgs = ['serve', ...args];
31
- log.debug('Launching %s with args: %O', mkDocsPath, finalArgs);
32
- const proc = new SubProcess(mkDocsPath, finalArgs);
33
- return await proc.start(startDetector, detach, timeoutMs);
32
+
33
+ log.debug('Launching %s with args: %s', mkDocsPath, finalArgs);
34
+ return spawnBackgroundProcess(mkDocsPath, finalArgs, opts);
34
35
  }
35
36
 
36
37
  /**
@@ -57,7 +58,7 @@ async function doBuild(
57
58
  export async function buildSite({
58
59
  mkdocsYml: mkDocsYmlPath,
59
60
  siteDir,
60
- theme = NAME_MKDOCS,
61
+ theme = NAME_THEME,
61
62
  cwd = process.cwd(),
62
63
  serve = false,
63
64
  serveOpts,
@@ -137,7 +138,7 @@ export interface BuildMkDocsOpts {
137
138
  execOpts?: TeenProcessExecOptions;
138
139
 
139
140
  /**
140
- * Extra options for {@linkcode teen_process.Subprocess.start}
141
+ * Extra options for {@linkcode spawnBackgroundProcess}
141
142
  */
142
- serveOpts?: TeenProcessSubprocessStartOpts;
143
+ serveOpts?: SpawnBackgroundProcessOpts;
143
144
  }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Provides functions to validate user-provided options as part of Yargs' post-parsing "check" phase
3
+ * @module
4
+ */
5
+
6
+ import {fs, util} from '@appium/support';
7
+ import _ from 'lodash';
8
+ import type {Options} from 'yargs';
9
+ import logger from '../logger';
10
+
11
+ const log = logger.withTag('check');
12
+
13
+ /**
14
+ * Given a list of objects with `id` and `path` props, filters out the ones that do not exist
15
+ * @param paths Filepaths
16
+ * @returns Missing files
17
+ */
18
+ async function filterMissing(paths: MissingFileData[]): Promise<MissingFileData[]> {
19
+ const exists = await Promise.all(
20
+ paths.map(async ({id, path}) => ({id, path, exists: await fs.exists(path)}))
21
+ );
22
+ const results = _.reject(exists, 'exists');
23
+ return _.map(results, (result) => _.omit(result, 'exists'));
24
+ }
25
+
26
+ /**
27
+ * Data structure describing a missing file; returned by {@linkcode filterMissing}
28
+ */
29
+ interface MissingFileData {
30
+ /**
31
+ * Arbitrary identifier; intent was to map to an option name
32
+ */
33
+ id: string;
34
+ /**
35
+ * Normalized filepath
36
+ */
37
+ path: string;
38
+ }
39
+
40
+ /**
41
+ * Takes user-provided paths and checks for existence.
42
+ *
43
+ * Filters options to consider based on group name only.
44
+ *
45
+ * Meant to be used as a "fail-fast" strategy on the CLI, so we don't go all the way through some
46
+ * expensive behavior before realizing we're missing a path.
47
+ * @param opts Options object for a yargs command
48
+ * @param group Group name to filter on
49
+ * @param argv User-provided args
50
+ * @returns `true` if all paths exist or otherwise an error message
51
+ */
52
+ export async function checkMissingPaths<T extends Record<string, Options>>(
53
+ opts: T,
54
+ group: string,
55
+ argv: Record<string, unknown>
56
+ ): Promise<true | string> {
57
+ const argsToCheck = _.keys(
58
+ _.pickBy(opts, (opt: Options, id: string) => opt?.group === group && id in argv) as Partial<T>
59
+ );
60
+
61
+ // yargs is pretty loose about allowing CLI args multiple times, and the value could potentially
62
+ // be a `string[]` instead of `string`; we don't want to allow more than one path per arg.
63
+ if (!argsToCheck.every((id) => _.isString(argv[id]))) {
64
+ return 'Paths may only be provided once each';
65
+ }
66
+
67
+ const pathsToCheck: MissingFileData[] = _.map(argsToCheck, (id) => ({
68
+ id,
69
+ path: String(argv[id]), // this must be a string per the above check
70
+ }));
71
+
72
+ log.debug(
73
+ 'Checking for existence of %s: %s',
74
+ util.pluralize('path', pathsToCheck.length),
75
+ _.map(pathsToCheck, 'path')
76
+ );
77
+
78
+ const missingPaths = await filterMissing(pathsToCheck);
79
+
80
+ if (missingPaths.length) {
81
+ return missingPaths
82
+ .map(({id, path}) => `Path specified using --${_.kebabCase(id)} (${path}) does not exist`)
83
+ .join('\n');
84
+ }
85
+
86
+ return true;
87
+ }
@@ -1,53 +1,64 @@
1
- import {CommandModule, InferredOptionTypes, Options} from 'yargs';
1
+ /**
2
+ * Yargs command module for the `build` command.
3
+ * @module
4
+ */
5
+
6
+ import path from 'node:path';
7
+ import type {CommandModule, InferredOptionTypes, Options} from 'yargs';
2
8
  import {buildReferenceDocs, buildSite, deploy, updateNav} from '../../builder';
3
9
  import {NAME_BIN} from '../../constants';
4
10
  import logger from '../../logger';
5
11
  import {stopwatch} from '../../util';
12
+ import {checkMissingPaths} from '../check';
6
13
 
7
14
  const log = logger.withTag('build');
8
15
 
9
- const NAME_GROUP_BUILD = 'Build Options:';
10
- const NAME_GROUP_DEPLOY = 'Deployment Options:';
11
- const NAME_GROUP_SERVE = 'Serve Options:';
12
- const NAME_GROUP_BUILD_PATHS = 'Paths:';
16
+ enum BuildCommandGroup {
17
+ Build = 'Build Config:',
18
+ Deploy = 'Deployment Config:',
19
+ Serve = 'Dev Server Config:',
20
+ BuildPaths = 'Custom Paths:',
21
+ }
13
22
 
14
- const opts = Object.freeze({
23
+ const opts = {
15
24
  reference: {
16
25
  describe: 'Run TypeDoc command API reference build (Markdown)',
17
- group: NAME_GROUP_BUILD,
26
+ group: BuildCommandGroup.Build,
18
27
  type: 'boolean',
19
28
  default: true,
20
29
  },
21
30
  site: {
22
31
  describe: 'Run MkDocs build (HTML)',
23
- group: NAME_GROUP_BUILD,
32
+ group: BuildCommandGroup.Build,
24
33
  type: 'boolean',
25
34
  default: true,
26
35
  },
27
36
  'site-dir': {
28
37
  alias: 'd',
29
38
  describe: 'HTML output directory',
30
- group: NAME_GROUP_BUILD_PATHS,
39
+ group: BuildCommandGroup.Build,
31
40
  nargs: 1,
32
41
  requiresArg: true,
33
42
  type: 'string',
34
43
  normalize: true,
44
+ coerce: path.resolve,
35
45
  implies: 'site',
36
46
  defaultDescription: '(from mkdocs.yml)',
37
47
  },
38
48
  'package-json': {
39
49
  defaultDescription: './package.json',
40
50
  describe: 'Path to package.json',
41
- group: NAME_GROUP_BUILD_PATHS,
51
+ group: BuildCommandGroup.BuildPaths,
42
52
  nargs: 1,
43
53
  normalize: true,
54
+ coerce: path.resolve,
44
55
  requiresArg: true,
45
56
  type: 'string',
46
57
  },
47
58
  title: {
48
59
  defaultDescription: '(extension package name)',
49
60
  describe: 'Title of the API reference',
50
- group: NAME_GROUP_BUILD,
61
+ group: BuildCommandGroup.Build,
51
62
  nargs: 1,
52
63
  requiresArg: true,
53
64
  type: 'string',
@@ -55,45 +66,48 @@ const opts = Object.freeze({
55
66
  'tsconfig-json': {
56
67
  defaultDescription: './tsconfig.json',
57
68
  describe: 'Path to tsconfig.json',
58
- group: NAME_GROUP_BUILD_PATHS,
69
+ group: BuildCommandGroup.BuildPaths,
59
70
  nargs: 1,
60
71
  normalize: true,
61
72
  requiresArg: true,
73
+ coerce: path.resolve,
62
74
  type: 'string',
63
75
  },
64
76
  'mkdocs-yml': {
65
77
  defaultDescription: './mkdocs.yml',
66
78
  description: 'Path to mkdocs.yml',
67
- group: NAME_GROUP_BUILD_PATHS,
79
+ group: BuildCommandGroup.BuildPaths,
68
80
  nargs: 1,
69
81
  normalize: true,
70
82
  requiresArg: true,
83
+ coerce: path.resolve,
71
84
  type: 'string',
72
85
  },
73
86
  'typedoc-json': {
74
87
  defaultDescription: './typedoc.json',
75
88
  describe: 'Path to typedoc.json',
76
- group: NAME_GROUP_BUILD_PATHS,
89
+ group: BuildCommandGroup.BuildPaths,
77
90
  nargs: 1,
78
91
  normalize: true,
79
92
  requiresArg: true,
93
+ coerce: path.resolve,
80
94
  type: 'string',
81
95
  },
82
96
  all: {
83
97
  describe: 'Output all reference docs (not just Appium comands)',
84
- group: NAME_GROUP_BUILD,
98
+ group: BuildCommandGroup.Build,
85
99
  implies: 'site',
86
100
  type: 'boolean',
87
101
  },
88
102
  deploy: {
89
- describe: 'Commit HTML output',
90
- group: NAME_GROUP_DEPLOY,
103
+ describe: 'Commit HTML output to a branch using mike',
104
+ group: BuildCommandGroup.Deploy,
91
105
  type: 'boolean',
92
106
  implies: 'site',
93
107
  },
94
108
  push: {
95
109
  describe: 'Push after deploy',
96
- group: NAME_GROUP_DEPLOY,
110
+ group: BuildCommandGroup.Deploy,
97
111
  type: 'boolean',
98
112
  implies: 'deploy',
99
113
  },
@@ -101,7 +115,7 @@ const opts = Object.freeze({
101
115
  alias: 'b',
102
116
  describe: 'Branch to commit to',
103
117
  implies: 'deploy',
104
- group: NAME_GROUP_DEPLOY,
118
+ group: BuildCommandGroup.Deploy,
105
119
  type: 'string',
106
120
  requiresArg: true,
107
121
  nargs: 1,
@@ -111,7 +125,7 @@ const opts = Object.freeze({
111
125
  alias: 'r',
112
126
  describe: 'Remote to push to',
113
127
  implies: ['deploy', 'push'],
114
- group: NAME_GROUP_DEPLOY,
128
+ group: BuildCommandGroup.Deploy,
115
129
  type: 'string',
116
130
  requiresArg: true,
117
131
  nargs: 1,
@@ -120,16 +134,16 @@ const opts = Object.freeze({
120
134
  prefix: {
121
135
  describe: 'Subdirectory within <branch> to commit to',
122
136
  implies: ['deploy', 'branch'],
123
- group: NAME_GROUP_DEPLOY,
137
+ group: BuildCommandGroup.Deploy,
124
138
  type: 'string',
125
139
  nargs: 1,
126
140
  requiresArg: true,
127
141
  },
128
142
  message: {
129
143
  alias: 'm',
130
- describe: 'Commit message',
144
+ describe: 'Commit message. Use "%s" for version placeholder',
131
145
  implies: 'deploy',
132
- group: NAME_GROUP_DEPLOY,
146
+ group: BuildCommandGroup.Deploy,
133
147
  type: 'string',
134
148
  nargs: 1,
135
149
  requiresArg: true,
@@ -137,7 +151,7 @@ const opts = Object.freeze({
137
151
  'deploy-version': {
138
152
  describe: 'Version (directory) to deploy build to',
139
153
  implies: 'deploy',
140
- group: NAME_GROUP_DEPLOY,
154
+ group: BuildCommandGroup.Deploy,
141
155
  type: 'string',
142
156
  nargs: 1,
143
157
  requiresArg: true,
@@ -146,7 +160,7 @@ const opts = Object.freeze({
146
160
  alias: {
147
161
  describe: 'Alias for the build (e.g., "latest"); triggers alias update',
148
162
  implies: 'deploy',
149
- group: NAME_GROUP_DEPLOY,
163
+ group: BuildCommandGroup.Deploy,
150
164
  type: 'string',
151
165
  nargs: 1,
152
166
  requiresArg: true,
@@ -155,18 +169,18 @@ const opts = Object.freeze({
155
169
  rebase: {
156
170
  describe: 'Rebase <branch> with remote before deploy',
157
171
  implies: ['deploy', 'branch', 'remote'],
158
- group: NAME_GROUP_DEPLOY,
172
+ group: BuildCommandGroup.Deploy,
159
173
  type: 'boolean',
160
174
  },
161
175
  serve: {
162
176
  describe: 'Start development server',
163
- group: NAME_GROUP_SERVE,
177
+ group: BuildCommandGroup.Serve,
164
178
  type: 'boolean',
165
179
  },
166
180
  port: {
167
181
  alias: 'p',
168
182
  describe: 'Development server port',
169
- group: NAME_GROUP_SERVE,
183
+ group: BuildCommandGroup.Serve,
170
184
  type: 'number',
171
185
  defaultDescription: '8000',
172
186
  implies: 'serve',
@@ -176,31 +190,35 @@ const opts = Object.freeze({
176
190
  host: {
177
191
  alias: 'h',
178
192
  describe: 'Development server host',
179
- group: NAME_GROUP_SERVE,
193
+ group: BuildCommandGroup.Serve,
180
194
  type: 'string',
181
195
  nargs: 1,
182
196
  requiresArg: true,
183
197
  implies: 'serve',
184
198
  defaultDescription: 'localhost',
185
199
  },
186
- }) satisfies Record<string, Options>;
200
+ } as const satisfies Record<string, Options>;
187
201
 
188
202
  type BuildOptions = InferredOptionTypes<typeof opts>;
189
203
 
190
204
  export default {
191
205
  command: 'build',
192
- describe: 'Build Appium extension documentation',
193
- builder: (yargs) =>
194
- yargs.options(opts).check((argv) => {
195
- // either this method doesn't provide camel-cased props, or the types are wrong.
196
- if (argv.deploy === true && argv['site-dir']) {
197
- log.error(
198
- `--site-dir is unsupported when running "${NAME_BIN} deploy"; use --prefix if needd, but remember that the default behavior is to deploy to the root of the branch (${argv.branch}) instead of a subdirectory`
199
- );
200
- return false;
201
- }
202
- return true;
203
- }),
206
+ describe: 'Build Appium extension documentation using TypeDoc & MkDocs',
207
+ builder(yargs) {
208
+ return yargs
209
+ .options(opts)
210
+ .check(async (argv) => {
211
+ // either this method doesn't provide camel-cased props, or the types are wrong.
212
+ if (argv.deploy === true && argv['site-dir']) {
213
+ return `--site-dir is unsupported when running "${NAME_BIN} deploy"; use --prefix if needed, but remember that the default behavior is to deploy to the root of the branch (${argv.branch}) instead of a subdirectory`;
214
+ }
215
+
216
+ return await checkMissingPaths(opts, BuildCommandGroup.BuildPaths, argv);
217
+ })
218
+ .epilog(
219
+ 'For help with further configuration, see:\n - MkDocs: https://www.mkdocs.org\n - TypeDoc: https://typedoc.org\n - Mike: https://github.com/jimporter/mike'
220
+ );
221
+ },
204
222
  async handler(args) {
205
223
  const stop = stopwatch('build');
206
224
  log.debug('Build command called with args: %O', args);
@@ -223,4 +241,4 @@ export default {
223
241
  }
224
242
  log.success('Done! (total: %dms)', stop());
225
243
  },
226
- } as CommandModule<{}, BuildOptions>;
244
+ } as CommandModule<object, BuildOptions>;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Exports all command modules
3
+ * @module
4
+ */
5
+
1
6
  export {default as init} from './init';
2
7
  export {default as validate} from './validate';
3
8
  export {default as build} from './build';
@@ -1,19 +1,32 @@
1
+ /**
2
+ * Yargs command module for the `init` command.
3
+ * @module
4
+ */
5
+
1
6
  import _ from 'lodash';
2
- import {CommandModule, InferredOptionTypes, Options} from 'yargs';
7
+ import type {CommandModule, InferredOptionTypes, Options} from 'yargs';
3
8
  import {init} from '../../init';
4
9
  import logger from '../../logger';
5
10
  import {stopwatch} from '../../util';
11
+ import {checkMissingPaths} from '../check';
6
12
 
7
13
  const log = logger.withTag('init');
8
14
 
9
- const NAME_GROUP_INIT_MKDOCS = 'MkDocs Config:';
10
- const NAME_GROUP_INIT_PATHS = 'Paths:';
11
- const NAME_GROUP_INIT_BEHAVIOR = 'Initialization Behavior:';
15
+ enum InitCommandGroup {
16
+ MkDocs = 'MkDocs Config:',
17
+ Paths = 'Custom Paths:',
18
+ Behavior = 'Initialization Behavior:',
19
+ }
12
20
 
13
- const opts = Object.freeze({
21
+ /**
22
+ * Note the groups here; _some_ opts are paths and would usually be checked via
23
+ * {@linkcode checkMissingPaths}, but in this case we do not care if the path exists or not, because
24
+ * we may create it.
25
+ */
26
+ const opts = {
14
27
  copyright: {
15
28
  description: 'Copyright notice',
16
- group: NAME_GROUP_INIT_MKDOCS,
29
+ group: InitCommandGroup.MkDocs,
17
30
  nargs: 1,
18
31
  requiresArg: true,
19
32
  type: 'string',
@@ -22,19 +35,19 @@ const opts = Object.freeze({
22
35
  default: '.',
23
36
  defaultDescription: '(current directory)',
24
37
  description: 'Directory of package',
25
- group: NAME_GROUP_INIT_PATHS,
38
+ group: InitCommandGroup.Paths,
26
39
  normalize: true,
27
40
  type: 'string',
28
41
  },
29
42
  'dry-run': {
30
43
  describe: 'Do not write any files; show what would be done',
31
- group: NAME_GROUP_INIT_BEHAVIOR,
44
+ group: InitCommandGroup.Behavior,
32
45
  type: 'boolean',
33
46
  },
34
47
  force: {
35
48
  alias: 'f',
36
49
  describe: 'Overwrite existing configurations',
37
- group: NAME_GROUP_INIT_BEHAVIOR,
50
+ group: InitCommandGroup.Behavior,
38
51
  type: 'boolean',
39
52
  },
40
53
  include: {
@@ -43,19 +56,20 @@ const opts = Object.freeze({
43
56
  coerce: (value: string | string[]) => _.castArray(value),
44
57
  description: 'Files to include in compilation (globs OK)',
45
58
  nargs: 1,
59
+ group: InitCommandGroup.MkDocs,
46
60
  requiresArg: true,
47
61
  type: 'string',
48
62
  },
49
63
  mkdocs: {
50
64
  default: true,
51
65
  description: 'Create mkdocs.yml if needed',
52
- group: NAME_GROUP_INIT_BEHAVIOR,
66
+ group: InitCommandGroup.Behavior,
53
67
  type: 'boolean',
54
68
  },
55
69
  'mkdocs-yml': {
56
70
  defaultDescription: './mkdocs.yml',
57
- description: 'Path to mkdocs.yml',
58
- group: NAME_GROUP_INIT_PATHS,
71
+ description: 'Path to new or existing mkdocs.yml',
72
+ group: InitCommandGroup.MkDocs,
59
73
  nargs: 1,
60
74
  normalize: true,
61
75
  requiresArg: true,
@@ -63,8 +77,8 @@ const opts = Object.freeze({
63
77
  },
64
78
  'package-json': {
65
79
  defaultDescription: './package.json',
66
- describe: 'Path to package.json',
67
- group: NAME_GROUP_INIT_PATHS,
80
+ describe: 'Path to existing package.json',
81
+ group: InitCommandGroup.Paths,
68
82
  nargs: 1,
69
83
  normalize: true,
70
84
  requiresArg: true,
@@ -73,13 +87,13 @@ const opts = Object.freeze({
73
87
  python: {
74
88
  default: true,
75
89
  description: 'Install Python dependencies if needed',
76
- group: NAME_GROUP_INIT_BEHAVIOR,
90
+ group: InitCommandGroup.Behavior,
77
91
  type: 'boolean',
78
92
  },
79
93
  'python-path': {
80
94
  defaultDescription: '(derived from shell)',
81
95
  description: 'Path to python 3 executable',
82
- group: NAME_GROUP_INIT_PATHS,
96
+ group: InitCommandGroup.Paths,
83
97
  nargs: 1,
84
98
  normalize: true,
85
99
  requiresArg: true,
@@ -88,7 +102,7 @@ const opts = Object.freeze({
88
102
  'repo-name': {
89
103
  defaultDescription: '(derived from --repo-url)',
90
104
  description: 'Name of extension repository',
91
- group: NAME_GROUP_INIT_MKDOCS,
105
+ group: InitCommandGroup.MkDocs,
92
106
  nargs: 1,
93
107
  requiresArg: true,
94
108
  type: 'string',
@@ -96,7 +110,7 @@ const opts = Object.freeze({
96
110
  'repo-url': {
97
111
  defaultDescription: '(from package.json)',
98
112
  description: 'URL of extension repository',
99
- group: NAME_GROUP_INIT_MKDOCS,
113
+ group: InitCommandGroup.MkDocs,
100
114
  nargs: 1,
101
115
  requiresArg: true,
102
116
  type: 'string',
@@ -104,7 +118,7 @@ const opts = Object.freeze({
104
118
  'site-description': {
105
119
  defaultDescription: '(from package.json)',
106
120
  description: 'Site description',
107
- group: NAME_GROUP_INIT_MKDOCS,
121
+ group: InitCommandGroup.MkDocs,
108
122
  nargs: 1,
109
123
  requiresArg: true,
110
124
  type: 'string',
@@ -112,15 +126,15 @@ const opts = Object.freeze({
112
126
  'site-name': {
113
127
  defaultDescription: '(extension package name)',
114
128
  description: 'Name of site',
115
- group: NAME_GROUP_INIT_MKDOCS,
129
+ group: InitCommandGroup.MkDocs,
116
130
  nargs: 1,
117
131
  requiresArg: true,
118
132
  type: 'string',
119
133
  },
120
134
  'tsconfig-json': {
121
135
  defaultDescription: './tsconfig.json',
122
- describe: 'Path to tsconfig.json',
123
- group: NAME_GROUP_INIT_PATHS,
136
+ describe: 'Path to new or existing tsconfig.json',
137
+ group: InitCommandGroup.Behavior,
124
138
  nargs: 1,
125
139
  normalize: true,
126
140
  requiresArg: true,
@@ -129,13 +143,13 @@ const opts = Object.freeze({
129
143
  typedoc: {
130
144
  default: true,
131
145
  description: 'Create typedoc.json if needed',
132
- group: NAME_GROUP_INIT_BEHAVIOR,
146
+ group: InitCommandGroup.Behavior,
133
147
  type: 'boolean',
134
148
  },
135
149
  'typedoc-json': {
136
150
  defaultDescription: './typedoc.json',
137
- describe: 'Path to typedoc.json',
138
- group: NAME_GROUP_INIT_PATHS,
151
+ describe: 'Path to new or existing typedoc.json',
152
+ group: InitCommandGroup.Behavior,
139
153
  nargs: 1,
140
154
  normalize: true,
141
155
  requiresArg: true,
@@ -144,20 +158,31 @@ const opts = Object.freeze({
144
158
  typescript: {
145
159
  default: true,
146
160
  description: 'Create tsconfig.json if needed',
147
- group: NAME_GROUP_INIT_BEHAVIOR,
161
+ group: InitCommandGroup.Behavior,
162
+ type: 'boolean',
163
+ },
164
+ upgrade: {
165
+ alias: 'up',
166
+ describe: 'Only upgrade Python dependencies if out-of-date',
167
+ group: InitCommandGroup.Behavior,
148
168
  type: 'boolean',
169
+ conflicts: 'force',
149
170
  },
150
- }) satisfies Record<string, Options>;
171
+ } as const satisfies Record<string, Options>;
151
172
 
152
173
  type InitOptions = InferredOptionTypes<typeof opts>;
153
174
 
154
175
  export default {
155
176
  command: 'init',
156
177
  describe: 'Initialize package for doc generation',
157
- builder: opts,
178
+ builder(yargs) {
179
+ return yargs
180
+ .options(opts)
181
+ .check(async (argv) => checkMissingPaths(opts, InitCommandGroup.Paths, argv));
182
+ },
158
183
  async handler(args) {
159
184
  const done = stopwatch('init');
160
185
  await init({...args, overwrite: args.force, cwd: args.dir});
161
186
  log.success('Done (%dms)', done());
162
187
  },
163
- } as CommandModule<{}, InitOptions>;
188
+ } as CommandModule<object, InitOptions>;