@optique/discover 1.2.0-dev.2298 → 1.2.0-dev.2301

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.
package/README.md CHANGED
@@ -69,6 +69,7 @@ await runProgram({
69
69
  version: "1.0.0",
70
70
  brief: message`Administrative command-line tools.`,
71
71
  },
72
+ commandList: "top-level",
72
73
  });
73
74
  ~~~~
74
75
 
@@ -156,6 +157,9 @@ Entry files named `index` map to their containing command path, so
156
157
  defines `user`. Use `entryFileName` to choose another entry name or disable
157
158
  this rule. `commandsFromModules()` applies the same path rules to module map
158
159
  keys after stripping its `base` option.
160
+ For large command trees, pass `commandList: "top-level"` to keep root help
161
+ focused on first-level command groups while subcommand help remains available
162
+ through `<command> --help`.
159
163
 
160
164
  For more resources, see the [docs] and the [*examples/*](/examples/)
161
165
  directory.
package/dist/cli.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  const require_chunk = require('./chunk-CUT6urMc.cjs');
3
3
  require('./command-C-NgG0KJ.cjs');
4
- require('./src-B4qtzrut.cjs');
5
- const require_generator = require('./generator-DNRlBDyF.cjs');
4
+ require('./src-CPtrcNkd.cjs');
5
+ const require_generator = require('./generator-Dc9I4tTs.cjs');
6
6
  const require_main_check = require('./main-check-CwunSNpK.cjs');
7
7
  const __optique_core_constructs = require_chunk.__toESM(require("@optique/core/constructs"));
8
8
  const __optique_core_message = require_chunk.__toESM(require("@optique/core/message"));
@@ -15,7 +15,7 @@ const node_process = require_chunk.__toESM(require("node:process"));
15
15
 
16
16
  //#region deno.json
17
17
  var name = "@optique/discover";
18
- var version = "1.2.0-dev.2298+a0394b06";
18
+ var version = "1.2.0-dev.2301+7cd22796";
19
19
  var license = "MIT";
20
20
  var exports$1 = {
21
21
  ".": "./src/index.ts",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import "./command-9sgrJtwh.js";
3
- import "./src-CKPihqEZ.js";
4
- import { watchCommandsModule, writeCommandsModule } from "./generator-B-dPfnHz.js";
3
+ import "./src-CCeOMJRj.js";
4
+ import { watchCommandsModule, writeCommandsModule } from "./generator-wZHULCZH.js";
5
5
  import { isMainModuleUrl } from "./main-check-mMnKfUZs.js";
6
6
  import { object } from "@optique/core/constructs";
7
7
  import { message } from "@optique/core/message";
@@ -14,7 +14,7 @@ import process from "node:process";
14
14
 
15
15
  //#region deno.json
16
16
  var name = "@optique/discover";
17
- var version = "1.2.0-dev.2298+a0394b06";
17
+ var version = "1.2.0-dev.2301+7cd22796";
18
18
  var license = "MIT";
19
19
  var exports = {
20
20
  ".": "./src/index.ts",
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_src = require('./src-B4qtzrut.cjs');
2
+ const require_src = require('./src-CPtrcNkd.cjs');
3
3
  const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
4
4
  const node_path = require_chunk.__toESM(require("node:path"));
5
5
  const node_url = require_chunk.__toESM(require("node:url"));
@@ -1,4 +1,4 @@
1
- import { getDefaultExtensions } from "./src-CKPihqEZ.js";
1
+ import { getDefaultExtensions } from "./src-CCeOMJRj.js";
2
2
  import { mkdir, readdir, realpath, stat, writeFile } from "node:fs/promises";
3
3
  import { dirname, posix, relative, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
@@ -1,6 +1,6 @@
1
1
  require('./command-C-NgG0KJ.cjs');
2
- require('./src-B4qtzrut.cjs');
3
- const require_generator = require('./generator-DNRlBDyF.cjs');
2
+ require('./src-CPtrcNkd.cjs');
3
+ const require_generator = require('./generator-Dc9I4tTs.cjs');
4
4
 
5
5
  exports.generateCommandsModule = require_generator.generateCommandsModule;
6
6
  exports.watchCommandsModule = require_generator.watchCommandsModule;
package/dist/generator.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./command-9sgrJtwh.js";
2
- import "./src-CKPihqEZ.js";
3
- import { generateCommandsModule, watchCommandsModule, writeCommandsModule } from "./generator-B-dPfnHz.js";
2
+ import "./src-CCeOMJRj.js";
3
+ import { generateCommandsModule, watchCommandsModule, writeCommandsModule } from "./generator-wZHULCZH.js";
4
4
 
5
5
  export { generateCommandsModule, watchCommandsModule, writeCommandsModule };
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  const require_command = require('./command-C-NgG0KJ.cjs');
2
- const require_src = require('./src-B4qtzrut.cjs');
2
+ const require_src = require('./src-CPtrcNkd.cjs');
3
3
 
4
4
  exports.commandsFromModules = require_src.commandsFromModules;
5
5
  exports.createProgramParser = require_src.createProgramParser;
package/dist/index.d.cts CHANGED
@@ -294,7 +294,7 @@ declare function commandsFromModules(modules: ModuleMap, options?: CommandsFromM
294
294
  * duplicated.
295
295
  * @since 1.1.0
296
296
  */
297
- declare function createProgramParser(commands: readonly CommandEntry[], metadata?: ProgramHelpMetadata): FluentParser<Mode, ProgramInvocation, unknown>;
297
+ declare function createProgramParser(commands: readonly CommandEntry[], options?: CreateProgramParserOptions): FluentParser<Mode, ProgramInvocation, unknown>;
298
298
  /**
299
299
  * Discovers and runs a command program.
300
300
  *
@@ -325,5 +325,18 @@ interface ProgramHelpMetadata {
325
325
  */
326
326
  readonly footer?: Message;
327
327
  }
328
+ /**
329
+ * Options for {@link createProgramParser}.
330
+ *
331
+ * @since 1.2.0
332
+ */
333
+ interface CreateProgramParserOptions extends ProgramHelpMetadata {
334
+ /**
335
+ * How to render command lists in top-level help pages.
336
+ *
337
+ * @default `"recursive"`
338
+ */
339
+ readonly commandList?: RunOptions["commandList"];
340
+ }
328
341
  //#endregion
329
- export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
342
+ export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, CreateProgramParserOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
package/dist/index.d.ts CHANGED
@@ -294,7 +294,7 @@ declare function commandsFromModules(modules: ModuleMap, options?: CommandsFromM
294
294
  * duplicated.
295
295
  * @since 1.1.0
296
296
  */
297
- declare function createProgramParser(commands: readonly CommandEntry[], metadata?: ProgramHelpMetadata): FluentParser<Mode, ProgramInvocation, unknown>;
297
+ declare function createProgramParser(commands: readonly CommandEntry[], options?: CreateProgramParserOptions): FluentParser<Mode, ProgramInvocation, unknown>;
298
298
  /**
299
299
  * Discovers and runs a command program.
300
300
  *
@@ -325,5 +325,18 @@ interface ProgramHelpMetadata {
325
325
  */
326
326
  readonly footer?: Message;
327
327
  }
328
+ /**
329
+ * Options for {@link createProgramParser}.
330
+ *
331
+ * @since 1.2.0
332
+ */
333
+ interface CreateProgramParserOptions extends ProgramHelpMetadata {
334
+ /**
335
+ * How to render command lists in top-level help pages.
336
+ *
337
+ * @default `"recursive"`
338
+ */
339
+ readonly commandList?: RunOptions["commandList"];
340
+ }
328
341
  //#endregion
329
- export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
342
+ export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, CreateProgramParserOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { defineCommand, isCommand } from "./command-9sgrJtwh.js";
2
- import { commandsFromModules, createProgramParser, discoverCommands, getDefaultExtensions, runProgram } from "./src-CKPihqEZ.js";
2
+ import { commandsFromModules, createProgramParser, discoverCommands, getDefaultExtensions, runProgram } from "./src-CCeOMJRj.js";
3
3
 
4
4
  export { commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
@@ -9,7 +9,7 @@ import { posix, relative, resolve, sep } from "node:path";
9
9
  import { fileURLToPath, pathToFileURL } from "node:url";
10
10
  import { dispatchByMode, inheritAnnotations, mapModeValue, wrapForMode } from "@optique/core/extension";
11
11
  import { fluent } from "@optique/core/fluent";
12
- import { mergeHidden } from "@optique/core/usage";
12
+ import { isDocHidden, mergeHidden } from "@optique/core/usage";
13
13
 
14
14
  //#region src/index.ts
15
15
  /**
@@ -129,7 +129,7 @@ function commandsFromModules(modules, options = {}) {
129
129
  * duplicated.
130
130
  * @since 1.1.0
131
131
  */
132
- function createProgramParser(commands, metadata = {}) {
132
+ function createProgramParser(commands, options = {}) {
133
133
  if (commands.length < 1) throw new TypeError("createProgramParser() requires at least one command.");
134
134
  const sortedCommands = sortCommands(commands);
135
135
  rejectDuplicatePaths(sortedCommands.map((entry) => ({
@@ -138,7 +138,7 @@ function createProgramParser(commands, metadata = {}) {
138
138
  })));
139
139
  const rootNode = buildCommandTree(sortedCommands);
140
140
  const parser = buildNodeParser(rootNode);
141
- return fluent(withRootDocs(parser, sortedCommands, metadata));
141
+ return fluent(withRootDocs(parser, sortedCommands, options));
142
142
  }
143
143
  /**
144
144
  * Discovers and runs a command program.
@@ -159,7 +159,10 @@ async function runProgram(options) {
159
159
  extensions: options.extensions,
160
160
  entryFileName: options.entryFileName
161
161
  });
162
- const parser = createProgramParser(commands, options.metadata);
162
+ const parser = createProgramParser(commands, {
163
+ ...options.metadata,
164
+ commandList: options.commandList
165
+ });
163
166
  const invocation = await runAsync(parser, buildRunOptions(options));
164
167
  await dispatchInvocation(invocation, options.hooks);
165
168
  }
@@ -724,8 +727,8 @@ function createLeafParser(commandDefinition, path, includeMetadata = false) {
724
727
  function withRootDocs(parser, commands, metadata) {
725
728
  const rootState = parser.initialState;
726
729
  const rootCommand = commands.find((entry) => entry.path.length < 1);
727
- const listedCommands = commands.filter((entry) => entry.path.length > 0);
728
730
  const commandsByPath = new Map(commands.map((entry) => [commandPathKey(entry.path), entry.command]));
731
+ const listedCommands = rootListedCommands(commands, commandsByPath, metadata.commandList ?? "recursive");
729
732
  const rootDocs = () => {
730
733
  const fragments = [...rootCommand?.command.parser.getDocFragments({ kind: "unavailable" }).fragments ?? []];
731
734
  if (listedCommands.length > 0) fragments.push({
@@ -754,6 +757,36 @@ function withRootDocs(parser, commands, metadata) {
754
757
  }
755
758
  };
756
759
  }
760
+ function rootListedCommands(commands, commandsByPath, commandList) {
761
+ const listedCommands = commands.filter((entry) => entry.path.length > 0);
762
+ if (commandList !== "top-level" || listedCommands.length < 1) return listedCommands;
763
+ const topLevelEntries = /* @__PURE__ */ new Map();
764
+ for (const entry of listedCommands) {
765
+ const segment = entry.path[0];
766
+ if (segment == null) continue;
767
+ const path = [segment];
768
+ const key = commandPathKey(path);
769
+ if (topLevelEntries.has(key)) continue;
770
+ const command$1 = commandsByPath.get(key);
771
+ if (command$1 != null) topLevelEntries.set(key, {
772
+ path,
773
+ command: command$1
774
+ });
775
+ else if (!isDocHidden(commandPathHidden(entry.path, commandsByPath))) topLevelEntries.set(key, {
776
+ path,
777
+ command: withoutCommandDocs(entry.command)
778
+ });
779
+ }
780
+ return [...topLevelEntries.values()];
781
+ }
782
+ function withoutCommandDocs(commandDefinition) {
783
+ if (commandDefinition.metadata == null) return commandDefinition;
784
+ const { brief: _brief, description: _description,...metadata } = commandDefinition.metadata;
785
+ return {
786
+ ...commandDefinition,
787
+ metadata
788
+ };
789
+ }
757
790
  function commandPathHidden(path, commandsByPath) {
758
791
  let hidden;
759
792
  for (let length = 1; length <= path.length; length++) hidden = mergeHidden(hidden, commandsByPath.get(commandPathKey(path.slice(0, length)))?.metadata?.hidden);
@@ -130,7 +130,7 @@ function commandsFromModules(modules, options = {}) {
130
130
  * duplicated.
131
131
  * @since 1.1.0
132
132
  */
133
- function createProgramParser(commands, metadata = {}) {
133
+ function createProgramParser(commands, options = {}) {
134
134
  if (commands.length < 1) throw new TypeError("createProgramParser() requires at least one command.");
135
135
  const sortedCommands = sortCommands(commands);
136
136
  rejectDuplicatePaths(sortedCommands.map((entry) => ({
@@ -139,7 +139,7 @@ function createProgramParser(commands, metadata = {}) {
139
139
  })));
140
140
  const rootNode = buildCommandTree(sortedCommands);
141
141
  const parser = buildNodeParser(rootNode);
142
- return (0, __optique_core_fluent.fluent)(withRootDocs(parser, sortedCommands, metadata));
142
+ return (0, __optique_core_fluent.fluent)(withRootDocs(parser, sortedCommands, options));
143
143
  }
144
144
  /**
145
145
  * Discovers and runs a command program.
@@ -160,7 +160,10 @@ async function runProgram(options) {
160
160
  extensions: options.extensions,
161
161
  entryFileName: options.entryFileName
162
162
  });
163
- const parser = createProgramParser(commands, options.metadata);
163
+ const parser = createProgramParser(commands, {
164
+ ...options.metadata,
165
+ commandList: options.commandList
166
+ });
164
167
  const invocation = await (0, __optique_run.runAsync)(parser, buildRunOptions(options));
165
168
  await dispatchInvocation(invocation, options.hooks);
166
169
  }
@@ -725,8 +728,8 @@ function createLeafParser(commandDefinition, path, includeMetadata = false) {
725
728
  function withRootDocs(parser, commands, metadata) {
726
729
  const rootState = parser.initialState;
727
730
  const rootCommand = commands.find((entry) => entry.path.length < 1);
728
- const listedCommands = commands.filter((entry) => entry.path.length > 0);
729
731
  const commandsByPath = new Map(commands.map((entry) => [commandPathKey(entry.path), entry.command]));
732
+ const listedCommands = rootListedCommands(commands, commandsByPath, metadata.commandList ?? "recursive");
730
733
  const rootDocs = () => {
731
734
  const fragments = [...rootCommand?.command.parser.getDocFragments({ kind: "unavailable" }).fragments ?? []];
732
735
  if (listedCommands.length > 0) fragments.push({
@@ -755,6 +758,36 @@ function withRootDocs(parser, commands, metadata) {
755
758
  }
756
759
  };
757
760
  }
761
+ function rootListedCommands(commands, commandsByPath, commandList) {
762
+ const listedCommands = commands.filter((entry) => entry.path.length > 0);
763
+ if (commandList !== "top-level" || listedCommands.length < 1) return listedCommands;
764
+ const topLevelEntries = /* @__PURE__ */ new Map();
765
+ for (const entry of listedCommands) {
766
+ const segment = entry.path[0];
767
+ if (segment == null) continue;
768
+ const path = [segment];
769
+ const key = commandPathKey(path);
770
+ if (topLevelEntries.has(key)) continue;
771
+ const command$1 = commandsByPath.get(key);
772
+ if (command$1 != null) topLevelEntries.set(key, {
773
+ path,
774
+ command: command$1
775
+ });
776
+ else if (!(0, __optique_core_usage.isDocHidden)(commandPathHidden(entry.path, commandsByPath))) topLevelEntries.set(key, {
777
+ path,
778
+ command: withoutCommandDocs(entry.command)
779
+ });
780
+ }
781
+ return [...topLevelEntries.values()];
782
+ }
783
+ function withoutCommandDocs(commandDefinition) {
784
+ if (commandDefinition.metadata == null) return commandDefinition;
785
+ const { brief: _brief, description: _description,...metadata } = commandDefinition.metadata;
786
+ return {
787
+ ...commandDefinition,
788
+ metadata
789
+ };
790
+ }
758
791
  function commandPathHidden(path, commandsByPath) {
759
792
  let hidden;
760
793
  for (let length = 1; length <= path.length; length++) hidden = (0, __optique_core_usage.mergeHidden)(hidden, commandsByPath.get(commandPathKey(path.slice(0, length)))?.metadata?.hidden);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/discover",
3
- "version": "1.2.0-dev.2298",
3
+ "version": "1.2.0-dev.2301",
4
4
  "description": "Runtime-aware command discovery for Optique CLI programs",
5
5
  "keywords": [
6
6
  "CLI",
@@ -83,8 +83,8 @@
83
83
  "optique-discover": "./dist/cli.js"
84
84
  },
85
85
  "dependencies": {
86
- "@optique/core": "1.2.0-dev.2298+a0394b06",
87
- "@optique/run": "1.2.0-dev.2298+a0394b06"
86
+ "@optique/core": "1.2.0-dev.2301+7cd22796",
87
+ "@optique/run": "1.2.0-dev.2301+7cd22796"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@types/node": "^24.0.0",