@oclif/core 3.0.4 → 3.0.5-dev.0

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.
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Plugin = void 0;
4
+ /* eslint-disable no-await-in-loop */
4
5
  const globby_1 = require("globby");
5
6
  const node_path_1 = require("node:path");
6
7
  const node_util_1 = require("node:util");
@@ -33,45 +34,56 @@ function* up(from) {
33
34
  }
34
35
  yield from;
35
36
  }
36
- async function findSourcesRoot(root) {
37
+ async function findSourcesRoot(root, name) {
38
+ // If we know the plugin name then we just need to traverse the file
39
+ // system until we find the directory that matches the plugin name.
40
+ if (name) {
41
+ for (const next of up(root)) {
42
+ if (next.endsWith((0, node_path_1.basename)(name)))
43
+ return next;
44
+ }
45
+ }
46
+ // If there's no plugin name (typically just the root plugin), then we need
47
+ // to traverse the file system until we find a directory with a package.json
37
48
  for (const next of up(root)) {
38
- const cur = (0, node_path_1.join)(next, 'package.json');
39
- // eslint-disable-next-line no-await-in-loop
40
- if (await (0, fs_1.exists)(cur))
41
- return (0, node_path_1.dirname)(cur);
49
+ // Skip the bin directory
50
+ if ((0, node_path_1.basename)((0, node_path_1.dirname)(next)) === 'bin' &&
51
+ ['dev', 'dev.cmd', 'dev.js', 'run', 'run.cmd', 'run.js'].includes((0, node_path_1.basename)(next))) {
52
+ continue;
53
+ }
54
+ try {
55
+ const cur = (0, node_path_1.join)(next, 'package.json');
56
+ if (await (0, fs_1.safeReadJson)(cur))
57
+ return (0, node_path_1.dirname)(cur);
58
+ }
59
+ catch { }
42
60
  }
43
61
  }
44
62
  /**
45
- * @returns string
46
- * @param name string
47
- * @param root string
48
- * find package root
49
- * for packages installed into node_modules this will go up directories until
50
- * it finds a node_modules directory with the plugin installed into it
63
+ * Find package root for packages installed into node_modules. This will go up directories
64
+ * until it finds a node_modules directory with the plugin installed into it
51
65
  *
52
66
  * This is needed because some oclif plugins do not declare the `main` field in their package.json
53
67
  * https://github.com/oclif/config/pull/289#issuecomment-983904051
68
+ *
69
+ * @returns string
70
+ * @param name string
71
+ * @param root string
54
72
  */
55
73
  async function findRootLegacy(name, root) {
56
74
  for (const next of up(root)) {
57
75
  let cur;
58
76
  if (name) {
59
77
  cur = (0, node_path_1.join)(next, 'node_modules', name, 'package.json');
60
- // eslint-disable-next-line no-await-in-loop
61
- if (await (0, fs_1.exists)(cur))
78
+ if (await (0, fs_1.safeReadJson)(cur))
62
79
  return (0, node_path_1.dirname)(cur);
63
- try {
64
- // eslint-disable-next-line no-await-in-loop
65
- const pkg = await (0, fs_1.readJson)((0, node_path_1.join)(next, 'package.json'));
66
- if (pkg.name === name)
67
- return next;
68
- }
69
- catch { }
80
+ const pkg = await (0, fs_1.safeReadJson)((0, node_path_1.join)(next, 'package.json'));
81
+ if (pkg?.name === name)
82
+ return next;
70
83
  }
71
84
  else {
72
85
  cur = (0, node_path_1.join)(next, 'package.json');
73
- // eslint-disable-next-line no-await-in-loop
74
- if (await (0, fs_1.exists)(cur))
86
+ if (await (0, fs_1.safeReadJson)(cur))
75
87
  return (0, node_path_1.dirname)(cur);
76
88
  }
77
89
  }
@@ -83,7 +95,7 @@ async function findRoot(name, root) {
83
95
  pkgPath = (0, util_2.resolvePackage)(name, { paths: [root] });
84
96
  }
85
97
  catch { }
86
- return pkgPath ? findSourcesRoot((0, node_path_1.dirname)(pkgPath)) : findRootLegacy(name, root);
98
+ return pkgPath ? findSourcesRoot((0, node_path_1.dirname)(pkgPath), name) : findRootLegacy(name, root);
87
99
  }
88
100
  return findSourcesRoot(root);
89
101
  }
@@ -97,11 +109,6 @@ const search = (cmd) => {
97
109
  };
98
110
  class Plugin {
99
111
  options;
100
- _base = `${_pjson.name}@${_pjson.version}`;
101
- _commandsDir;
102
- // eslint-disable-next-line new-cap
103
- _debug = (0, util_2.Debug)();
104
- flexibleTaxonomy;
105
112
  alias;
106
113
  alreadyLoaded = false;
107
114
  children = [];
@@ -120,94 +127,40 @@ class Plugin {
120
127
  valid = false;
121
128
  version;
122
129
  warned = false;
130
+ _base = `${_pjson.name}@${_pjson.version}`;
131
+ _commandsDir;
132
+ // eslint-disable-next-line new-cap
133
+ _debug = (0, util_2.Debug)();
134
+ flexibleTaxonomy;
123
135
  constructor(options) {
124
136
  this.options = options;
125
137
  }
126
- async _manifest() {
127
- const ignoreManifest = Boolean(this.options.ignoreManifest);
128
- const errorOnManifestCreate = Boolean(this.options.errorOnManifestCreate);
129
- const respectNoCacheDefault = Boolean(this.options.respectNoCacheDefault);
130
- const readManifest = async (dotfile = false) => {
131
- try {
132
- const p = (0, node_path_1.join)(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
133
- const manifest = await (0, fs_1.readJson)(p);
134
- if (!process.env.OCLIF_NEXT_VERSION && manifest.version.split('-')[0] !== this.version.split('-')[0]) {
135
- process.emitWarning(`Mismatched version in ${this.name} plugin manifest. Expected: ${this.version} Received: ${manifest.version}\nThis usually means you have an oclif.manifest.json file that should be deleted in development. This file should be automatically generated when publishing.`);
136
- }
137
- else {
138
- this._debug('using manifest from', p);
139
- this.hasManifest = true;
140
- return manifest;
141
- }
142
- }
143
- catch (error) {
144
- if (error.code === 'ENOENT') {
145
- if (!dotfile)
146
- return readManifest(true);
147
- }
148
- else {
149
- this.warn(error, 'readManifest');
150
- }
151
- }
152
- };
153
- const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.manifest#${this.name}`, { plugin: this.name });
154
- if (!ignoreManifest) {
155
- const manifest = await readManifest();
156
- if (manifest) {
157
- marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: true });
158
- marker?.stop();
159
- return manifest;
160
- }
161
- }
162
- const manifest = {
163
- commands: (await Promise.all(this.commandIDs.map(async (id) => {
164
- try {
165
- const cached = await (0, cache_command_1.cacheCommand)(await this.findCommand(id, { must: true }), this, respectNoCacheDefault);
166
- if (this.flexibleTaxonomy) {
167
- const permutations = (0, util_2.getCommandIdPermutations)(id);
168
- const aliasPermutations = cached.aliases.flatMap((a) => (0, util_2.getCommandIdPermutations)(a));
169
- return [id, { ...cached, aliasPermutations, permutations }];
170
- }
171
- return [id, cached];
172
- }
173
- catch (error) {
174
- const scope = 'cacheCommand';
175
- if (Boolean(errorOnManifestCreate) === false)
176
- this.warn(error, scope);
177
- else
178
- throw this.addErrorScope(error, scope);
179
- }
180
- })))
181
- // eslint-disable-next-line unicorn/no-await-expression-member, unicorn/prefer-native-coercion-functions
182
- .filter((f) => Boolean(f))
183
- .reduce((commands, [id, c]) => {
184
- commands[id] = c;
185
- return commands;
186
- }, {}),
187
- version: this.version,
188
- };
189
- marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: false });
138
+ get commandIDs() {
139
+ if (!this.commandsDir)
140
+ return [];
141
+ const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.commandIDs#${this.name}`, { plugin: this.name });
142
+ this._debug(`loading IDs from ${this.commandsDir}`);
143
+ const patterns = ['**/*.+(js|cjs|mjs|ts|tsx)', '!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js)?(x)'];
144
+ const ids = (0, globby_1.sync)(patterns, { cwd: this.commandsDir }).map((file) => {
145
+ const p = (0, node_path_1.parse)(file);
146
+ const topics = p.dir.split('/');
147
+ const command = p.name !== 'index' && p.name;
148
+ const id = [...topics, command].filter(Boolean).join(':');
149
+ return id === '' ? '.' : id;
150
+ });
151
+ this._debug('found commands', ids);
152
+ marker?.addDetails({ count: ids.length });
190
153
  marker?.stop();
191
- return manifest;
154
+ return ids;
192
155
  }
193
- addErrorScope(err, scope) {
194
- err.name = `${err.name} Plugin: ${this.name}`;
195
- err.detail = (0, util_1.compact)([
196
- err.detail,
197
- `module: ${this._base}`,
198
- scope && `task: ${scope}`,
199
- `plugin: ${this.name}`,
200
- `root: ${this.root}`,
201
- 'See more details with DEBUG=*',
202
- ]).join('\n');
203
- return err;
156
+ get commandsDir() {
157
+ if (this._commandsDir)
158
+ return this._commandsDir;
159
+ this._commandsDir = (0, ts_node_1.tsPath)(this.root, this.pjson.oclif.commands, this);
160
+ return this._commandsDir;
204
161
  }
205
- warn(err, scope) {
206
- if (this.warned)
207
- return;
208
- if (typeof err === 'string')
209
- err = new Error(err);
210
- process.emitWarning(this.addErrorScope(err, scope));
162
+ get topics() {
163
+ return topicsToArray(this.pjson.oclif.topics || {});
211
164
  }
212
165
  async findCommand(id, opts = {}) {
213
166
  const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.findCommand#${this.name}.${id}`, {
@@ -291,32 +244,91 @@ class Plugin {
291
244
  }))
292
245
  .sort((a, b) => a.id.localeCompare(b.id));
293
246
  }
294
- get commandIDs() {
295
- if (!this.commandsDir)
296
- return [];
297
- const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.commandIDs#${this.name}`, { plugin: this.name });
298
- this._debug(`loading IDs from ${this.commandsDir}`);
299
- const patterns = ['**/*.+(js|cjs|mjs|ts|tsx)', '!**/*.+(d.ts|test.ts|test.js|spec.ts|spec.js)?(x)'];
300
- const ids = (0, globby_1.sync)(patterns, { cwd: this.commandsDir }).map((file) => {
301
- const p = (0, node_path_1.parse)(file);
302
- const topics = p.dir.split('/');
303
- const command = p.name !== 'index' && p.name;
304
- const id = [...topics, command].filter(Boolean).join(':');
305
- return id === '' ? '.' : id;
306
- });
307
- this._debug('found commands', ids);
308
- marker?.addDetails({ count: ids.length });
247
+ async _manifest() {
248
+ const ignoreManifest = Boolean(this.options.ignoreManifest);
249
+ const errorOnManifestCreate = Boolean(this.options.errorOnManifestCreate);
250
+ const respectNoCacheDefault = Boolean(this.options.respectNoCacheDefault);
251
+ const readManifest = async (dotfile = false) => {
252
+ try {
253
+ const p = (0, node_path_1.join)(this.root, `${dotfile ? '.' : ''}oclif.manifest.json`);
254
+ const manifest = await (0, fs_1.readJson)(p);
255
+ if (!process.env.OCLIF_NEXT_VERSION && manifest.version.split('-')[0] !== this.version.split('-')[0]) {
256
+ process.emitWarning(`Mismatched version in ${this.name} plugin manifest. Expected: ${this.version} Received: ${manifest.version}\nThis usually means you have an oclif.manifest.json file that should be deleted in development. This file should be automatically generated when publishing.`);
257
+ }
258
+ else {
259
+ this._debug('using manifest from', p);
260
+ this.hasManifest = true;
261
+ return manifest;
262
+ }
263
+ }
264
+ catch (error) {
265
+ if (error.code === 'ENOENT') {
266
+ if (!dotfile)
267
+ return readManifest(true);
268
+ }
269
+ else {
270
+ this.warn(error, 'readManifest');
271
+ }
272
+ }
273
+ };
274
+ const marker = performance_1.Performance.mark(performance_1.OCLIF_MARKER_OWNER, `plugin.manifest#${this.name}`, { plugin: this.name });
275
+ if (!ignoreManifest) {
276
+ const manifest = await readManifest();
277
+ if (manifest) {
278
+ marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: true });
279
+ marker?.stop();
280
+ return manifest;
281
+ }
282
+ }
283
+ const manifest = {
284
+ commands: (await Promise.all(this.commandIDs.map(async (id) => {
285
+ try {
286
+ const cached = await (0, cache_command_1.cacheCommand)(await this.findCommand(id, { must: true }), this, respectNoCacheDefault);
287
+ if (this.flexibleTaxonomy) {
288
+ const permutations = (0, util_2.getCommandIdPermutations)(id);
289
+ const aliasPermutations = cached.aliases.flatMap((a) => (0, util_2.getCommandIdPermutations)(a));
290
+ return [id, { ...cached, aliasPermutations, permutations }];
291
+ }
292
+ return [id, cached];
293
+ }
294
+ catch (error) {
295
+ const scope = 'cacheCommand';
296
+ if (Boolean(errorOnManifestCreate) === false)
297
+ this.warn(error, scope);
298
+ else
299
+ throw this.addErrorScope(error, scope);
300
+ }
301
+ })))
302
+ // eslint-disable-next-line unicorn/no-await-expression-member, unicorn/prefer-native-coercion-functions
303
+ .filter((f) => Boolean(f))
304
+ .reduce((commands, [id, c]) => {
305
+ commands[id] = c;
306
+ return commands;
307
+ }, {}),
308
+ version: this.version,
309
+ };
310
+ marker?.addDetails({ commandCount: Object.keys(manifest.commands).length, fromCache: false });
309
311
  marker?.stop();
310
- return ids;
312
+ return manifest;
311
313
  }
312
- get commandsDir() {
313
- if (this._commandsDir)
314
- return this._commandsDir;
315
- this._commandsDir = (0, ts_node_1.tsPath)(this.root, this.pjson.oclif.commands, this);
316
- return this._commandsDir;
314
+ addErrorScope(err, scope) {
315
+ err.name = `${err.name} Plugin: ${this.name}`;
316
+ err.detail = (0, util_1.compact)([
317
+ err.detail,
318
+ `module: ${this._base}`,
319
+ scope && `task: ${scope}`,
320
+ `plugin: ${this.name}`,
321
+ `root: ${this.root}`,
322
+ 'See more details with DEBUG=*',
323
+ ]).join('\n');
324
+ return err;
317
325
  }
318
- get topics() {
319
- return topicsToArray(this.pjson.oclif.topics || {});
326
+ warn(err, scope) {
327
+ if (this.warned)
328
+ return;
329
+ if (typeof err === 'string')
330
+ err = new Error(err);
331
+ process.emitWarning(this.addErrorScope(err, scope));
320
332
  }
321
333
  }
322
334
  exports.Plugin = Plugin;
@@ -12,13 +12,13 @@ export declare class CLIError extends Error implements OclifError {
12
12
  constructor(error: Error | string, options?: {
13
13
  exit?: false | number;
14
14
  } & PrettyPrintableError);
15
+ get bang(): string | undefined;
16
+ get stack(): string;
15
17
  /**
16
18
  * @deprecated `render` Errors display should be handled by display function, like pretty-print
17
19
  * @return {string} returns a string representing the dispay of the error
18
20
  */
19
21
  render(): string;
20
- get bang(): string | undefined;
21
- get stack(): string;
22
22
  }
23
23
  export declare namespace CLIError {
24
24
  class Warn extends CLIError {
@@ -30,6 +30,15 @@ class CLIError extends Error {
30
30
  this.code = options.code;
31
31
  this.suggestions = options.suggestions;
32
32
  }
33
+ get bang() {
34
+ try {
35
+ return chalk_1.default.red(process.platform === 'win32' ? '»' : '›');
36
+ }
37
+ catch { }
38
+ }
39
+ get stack() {
40
+ return (0, clean_stack_1.default)(super.stack, { pretty: true });
41
+ }
33
42
  /**
34
43
  * @deprecated `render` Errors display should be handled by display function, like pretty-print
35
44
  * @return {string} returns a string representing the dispay of the error
@@ -45,15 +54,6 @@ class CLIError extends Error {
45
54
  output = (0, indent_string_1.default)(output, 1);
46
55
  return output;
47
56
  }
48
- get bang() {
49
- try {
50
- return chalk_1.default.red(process.platform === 'win32' ? '»' : '›');
51
- }
52
- catch { }
53
- }
54
- get stack() {
55
- return (0, clean_stack_1.default)(super.stack, { pretty: true });
56
- }
57
57
  }
58
58
  exports.CLIError = CLIError;
59
59
  (function (CLIError) {
@@ -6,8 +6,6 @@ export declare class CommandHelp extends HelpFormatter {
6
6
  config: Interfaces.Config;
7
7
  opts: Interfaces.HelpOptions;
8
8
  constructor(command: Command.Loadable, config: Interfaces.Config, opts: Interfaces.HelpOptions);
9
- private formatIfCommand;
10
- private isCommand;
11
9
  protected aliases(aliases: string[] | undefined): string | undefined;
12
10
  protected arg(arg: Command.Arg.Any): string;
13
11
  protected args(args: Command.Arg.Any[]): [string, string | undefined][] | undefined;
@@ -29,5 +27,7 @@ export declare class CommandHelp extends HelpFormatter {
29
27
  header: string;
30
28
  }>;
31
29
  protected usage(): string;
30
+ private formatIfCommand;
31
+ private isCommand;
32
32
  }
33
33
  export default CommandHelp;
@@ -27,17 +27,6 @@ class CommandHelp extends formatter_1.HelpFormatter {
27
27
  this.config = config;
28
28
  this.opts = opts;
29
29
  }
30
- formatIfCommand(example) {
31
- example = this.render(example);
32
- if (example.startsWith(this.config.bin))
33
- return dim(`$ ${example}`);
34
- if (example.startsWith(`$ ${this.config.bin}`))
35
- return dim(example);
36
- return example;
37
- }
38
- isCommand(example) {
39
- return (0, strip_ansi_1.default)(this.formatIfCommand(example)).startsWith(`$ ${this.config.bin}`);
40
- }
41
30
  aliases(aliases) {
42
31
  if (!aliases || aliases.length === 0)
43
32
  return;
@@ -295,6 +284,17 @@ class CommandHelp extends formatter_1.HelpFormatter {
295
284
  .join('\n');
296
285
  return body;
297
286
  }
287
+ formatIfCommand(example) {
288
+ example = this.render(example);
289
+ if (example.startsWith(this.config.bin))
290
+ return dim(`$ ${example}`);
291
+ if (example.startsWith(`$ ${this.config.bin}`))
292
+ return dim(example);
293
+ return example;
294
+ }
295
+ isCommand(example) {
296
+ return (0, strip_ansi_1.default)(this.formatIfCommand(example)).startsWith(`$ ${this.config.bin}`);
297
+ }
298
298
  }
299
299
  exports.CommandHelp = CommandHelp;
300
300
  exports.default = CommandHelp;
@@ -61,8 +61,8 @@ export declare class DocOpts {
61
61
  private flagMap;
62
62
  constructor(cmd: Command.Cached | Command.Class | Command.Loadable);
63
63
  static generate(cmd: Command.Cached | Command.Class | Command.Loadable): string;
64
+ toString(): string;
64
65
  private combineElementsToFlag;
65
66
  private generateElements;
66
67
  private groupFlagElements;
67
- toString(): string;
68
68
  }
@@ -76,6 +76,26 @@ class DocOpts {
76
76
  static generate(cmd) {
77
77
  return new DocOpts(cmd).toString();
78
78
  }
79
+ toString() {
80
+ const opts = this.cmd.id === '.' || this.cmd.id === '' ? [] : ['<%= command.id %>'];
81
+ if (this.cmd.args) {
82
+ const a = Object.values((0, ensure_arg_object_1.ensureArgObject)(this.cmd.args)).map((arg) => arg.required ? arg.name.toUpperCase() : `[${arg.name.toUpperCase()}]`) || [];
83
+ opts.push(...a);
84
+ }
85
+ try {
86
+ opts.push(...Object.values(this.groupFlagElements()));
87
+ }
88
+ catch {
89
+ // If there is an error, just return no usage so we don't fail command help.
90
+ opts.push(...this.flagList.map((flag) => {
91
+ const name = flag.char ? `-${flag.char}` : `--${flag.name}`;
92
+ if (flag.type === 'boolean')
93
+ return name;
94
+ return `${name}=<value>`;
95
+ }));
96
+ }
97
+ return opts.join(' ');
98
+ }
79
99
  combineElementsToFlag(elementMap, flagName, flagNames, unionString) {
80
100
  if (!this.flagMap[flagName]) {
81
101
  return;
@@ -134,25 +154,5 @@ class DocOpts {
134
154
  }
135
155
  return elementMap;
136
156
  }
137
- toString() {
138
- const opts = this.cmd.id === '.' || this.cmd.id === '' ? [] : ['<%= command.id %>'];
139
- if (this.cmd.args) {
140
- const a = Object.values((0, ensure_arg_object_1.ensureArgObject)(this.cmd.args)).map((arg) => arg.required ? arg.name.toUpperCase() : `[${arg.name.toUpperCase()}]`) || [];
141
- opts.push(...a);
142
- }
143
- try {
144
- opts.push(...Object.values(this.groupFlagElements()));
145
- }
146
- catch {
147
- // If there is an error, just return no usage so we don't fail command help.
148
- opts.push(...this.flagList.map((flag) => {
149
- const name = flag.char ? `-${flag.char}` : `--${flag.name}`;
150
- if (flag.type === 'boolean')
151
- return name;
152
- return `${name}=<value>`;
153
- }));
154
- }
155
- return opts.join(' ');
156
- }
157
157
  }
158
158
  exports.DocOpts = DocOpts;
@@ -21,7 +21,8 @@ export declare abstract class HelpBase extends HelpFormatter {
21
21
  export declare class Help extends HelpBase {
22
22
  protected CommandHelpClass: typeof CommandHelp;
23
23
  constructor(config: Interfaces.Config, opts?: Partial<Interfaces.HelpOptions>);
24
- private get _topics();
24
+ protected get sortedCommands(): Command.Loadable[];
25
+ protected get sortedTopics(): Interfaces.Topic[];
25
26
  protected command(command: Command.Loadable): string;
26
27
  protected description(c: Command.Loadable): string;
27
28
  protected formatCommand(command: Command.Loadable): string;
@@ -36,8 +37,7 @@ export declare class Help extends HelpBase {
36
37
  protected showRootHelp(): Promise<void>;
37
38
  protected showTopicHelp(topic: Interfaces.Topic): Promise<void>;
38
39
  protected summary(c: Command.Loadable): string | undefined;
39
- protected get sortedCommands(): Command.Loadable[];
40
- protected get sortedTopics(): Interfaces.Topic[];
40
+ private get _topics();
41
41
  }
42
42
  interface HelpBaseDerived {
43
43
  new (config: Interfaces.Config, opts?: Partial<Interfaces.HelpOptions>): HelpBase;
package/lib/help/index.js CHANGED
@@ -45,18 +45,19 @@ class Help extends HelpBase {
45
45
  constructor(config, opts = {}) {
46
46
  super(config, opts);
47
47
  }
48
- /*
49
- * _topics is to work around Interfaces.topics mistakenly including commands that do
50
- * not have children, as well as topics. A topic has children, either commands or other topics. When
51
- * this is fixed upstream config.topics should return *only* topics with children,
52
- * and this can be removed.
53
- */
54
- get _topics() {
55
- return this.config.topics.filter((topic) => {
56
- // it is assumed a topic has a child if it has children
57
- const hasChild = this.config.topics.some((subTopic) => subTopic.name.includes(`${topic.name}:`));
58
- return hasChild;
59
- });
48
+ get sortedCommands() {
49
+ let { commands } = this.config;
50
+ commands = commands.filter((c) => this.opts.all || !c.hidden);
51
+ commands = (0, util_1.sortBy)(commands, (c) => c.id);
52
+ commands = (0, util_1.uniqBy)(commands, (c) => c.id);
53
+ return commands;
54
+ }
55
+ get sortedTopics() {
56
+ let topics = this._topics;
57
+ topics = topics.filter((t) => this.opts.all || !t.hidden);
58
+ topics = (0, util_1.sortBy)(topics, (t) => t.name);
59
+ topics = (0, util_1.uniqBy)(topics, (t) => t.name);
60
+ return topics;
60
61
  }
61
62
  command(command) {
62
63
  return this.formatCommand(command);
@@ -266,19 +267,18 @@ class Help extends HelpBase {
266
267
  return this.render(c.summary.split('\n')[0]);
267
268
  return c.description && this.render(c.description).split('\n')[0];
268
269
  }
269
- get sortedCommands() {
270
- let { commands } = this.config;
271
- commands = commands.filter((c) => this.opts.all || !c.hidden);
272
- commands = (0, util_1.sortBy)(commands, (c) => c.id);
273
- commands = (0, util_1.uniqBy)(commands, (c) => c.id);
274
- return commands;
275
- }
276
- get sortedTopics() {
277
- let topics = this._topics;
278
- topics = topics.filter((t) => this.opts.all || !t.hidden);
279
- topics = (0, util_1.sortBy)(topics, (t) => t.name);
280
- topics = (0, util_1.uniqBy)(topics, (t) => t.name);
281
- return topics;
270
+ /*
271
+ * _topics is to work around Interfaces.topics mistakenly including commands that do
272
+ * not have children, as well as topics. A topic has children, either commands or other topics. When
273
+ * this is fixed upstream config.topics should return *only* topics with children,
274
+ * and this can be removed.
275
+ */
276
+ get _topics() {
277
+ return this.config.topics.filter((topic) => {
278
+ // it is assumed a topic has a child if it has children
279
+ const hasChild = this.config.topics.some((subTopic) => subTopic.name.includes(`${topic.name}:`));
280
+ return hasChild;
281
+ });
282
282
  }
283
283
  }
284
284
  exports.Help = Help;
@@ -8,8 +8,9 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
8
8
  private readonly flagAliases;
9
9
  private readonly raw;
10
10
  constructor(input: T);
11
- private get _argTokens();
11
+ parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
12
12
  private _args;
13
+ private get _argTokens();
13
14
  private _debugInput;
14
15
  private _debugOutput;
15
16
  private _flags;
@@ -18,5 +19,4 @@ export declare class Parser<T extends ParserInput, TFlags extends OutputFlags<T[
18
19
  private findLongFlag;
19
20
  private findShortFlag;
20
21
  private mapAndValidateFlags;
21
- parse(): Promise<ParserOutput<TFlags, BFlags, TArgs>>;
22
22
  }