EdgeAIG's picture
download
raw
5.88 kB
/**
* Help Documentation
* ================
*
* Internal helpers for generating help documentation.
* Extracted from command.ts to avoid circular dependencies.
*/
import * as Effect from "../../../Effect.ts"
import type { Command } from "../Command.ts"
import type * as GlobalFlag from "../GlobalFlag.ts"
import type { FlagDoc, HelpDoc } from "../HelpDoc.ts"
import * as Param from "../Param.ts"
import { toFlagDoc, toImpl } from "./command.ts"
const dedupeGlobalFlags = (
flags: ReadonlyArray<GlobalFlag.GlobalFlag<any>>
): ReadonlyArray<GlobalFlag.GlobalFlag<any>> => {
const seen = new Set<GlobalFlag.GlobalFlag<any>>()
const deduped: Array<GlobalFlag.GlobalFlag<any>> = []
for (const flag of flags) {
if (seen.has(flag)) {
continue
}
seen.add(flag)
deduped.push(flag)
}
return deduped
}
/**
* Returns the resolved command lineage for the provided path.
* Includes the root command as the first element.
*/
export const getCommandsForCommandPath = <Name extends string, Input, E, R, ContextInput>(
command: Command<Name, Input, ContextInput, E, R>,
commandPath: ReadonlyArray<string>
): ReadonlyArray<Command.Any> => {
const commands: Array<Command.Any> = [command]
let currentCommand: Command.Any = command
for (let i = 1; i < commandPath.length; i++) {
const subcommandName = commandPath[i]
let subcommand: Command.Any | undefined = undefined
for (const group of currentCommand.subcommands) {
subcommand = group.commands.find((sub) => sub.name === subcommandName)
if (subcommand) {
break
}
}
if (!subcommand) {
break
}
commands.push(subcommand)
currentCommand = subcommand
}
return commands
}
/**
* Returns active global flags for a command path.
* Built-ins are prepended and declarations are collected root -> leaf.
*/
export const getGlobalFlagsForCommandPath = <Name extends string, Input, E, R, ContextInput>(
command: Command<Name, Input, ContextInput, E, R>,
commandPath: ReadonlyArray<string>,
builtIns: ReadonlyArray<GlobalFlag.GlobalFlag<any>>
): ReadonlyArray<GlobalFlag.GlobalFlag<any>> => {
const commands = getCommandsForCommandPath(command, commandPath)
const declared = commands.flatMap((current) => toImpl(current).globalFlags)
return dedupeGlobalFlags([
...builtIns,
...declared
])
}
const collectDeclaredGlobalFlags = (command: Command.Any): ReadonlyArray<GlobalFlag.GlobalFlag<any>> => {
const collected: Array<GlobalFlag.GlobalFlag<any>> = []
const visit = (current: Command.Any): void => {
const impl = toImpl(current)
for (const flag of impl.globalFlags) {
collected.push(flag)
}
for (const group of current.subcommands) {
for (const subcommand of group.commands) {
visit(subcommand)
}
}
}
visit(command)
return dedupeGlobalFlags(collected)
}
const getSharedFlagsForCommandPath = (
commands: ReadonlyArray<Command.Any>,
currentFlags: ReadonlyArray<FlagDoc>
): ReadonlyArray<FlagDoc> => {
if (commands.length <= 1) {
return []
}
const seen = new Set(currentFlags.map((flag) => flag.name))
const sharedFlags: Array<FlagDoc> = []
for (const ancestor of commands.slice(0, -1)) {
const ancestorImpl = toImpl(ancestor)
for (const flag of ancestorImpl.contextConfig.flags) {
const singles = Param.extractSingleParams(flag)
for (const single of singles) {
if (seen.has(single.name)) {
continue
}
// Hidden ancestor flags are excluded from the shared-flags section
// of subcommand help, the same way they're excluded from the owning
// command's own help output.
if (single.hidden) {
continue
}
seen.add(single.name)
sharedFlags.push(toFlagDoc(single))
}
}
}
return sharedFlags
}
/**
* Returns all global flags declared in a command tree.
* Built-ins are prepended and command declarations are deduplicated by identity.
*/
export const getGlobalFlagsForCommandTree = <Name extends string, Input, E, R, ContextInput>(
command: Command<Name, Input, ContextInput, E, R>,
builtIns: ReadonlyArray<GlobalFlag.GlobalFlag<any>>
): ReadonlyArray<GlobalFlag.GlobalFlag<any>> =>
dedupeGlobalFlags([
...builtIns,
...collectDeclaredGlobalFlags(command)
])
/**
* Helper function to get help documentation for a specific command path.
* Navigates through the command hierarchy to find the right command.
* Reads active global flags for the path and includes them in the help doc.
*/
export const getHelpForCommandPath = <Name extends string, Input, E, R, ContextInput>(
command: Command<Name, Input, ContextInput, E, R>,
commandPath: ReadonlyArray<string>,
builtIns: ReadonlyArray<GlobalFlag.GlobalFlag<any>>
): Effect.Effect<HelpDoc, never, never> =>
Effect.gen(function*() {
const commands = getCommandsForCommandPath(command, commandPath)
const currentCommand = commands.length > 0 ? commands[commands.length - 1] : command
const baseDoc = toImpl(currentCommand).buildHelpDoc(commandPath)
const sharedFlags = getSharedFlagsForCommandPath(commands, baseDoc.flags)
const flags = getGlobalFlagsForCommandPath(command, commandPath, builtIns)
const globalFlagDocs: Array<FlagDoc> = []
for (const flag of flags) {
const singles = Param.extractSingleParams(flag.flag)
for (const single of singles) {
// Same rule as command-local flags: hidden globals are still parsed
// and still trigger their handlers, they just don't appear under
// "GLOBAL FLAGS" in --help.
if (single.hidden) continue
globalFlagDocs.push({
...toFlagDoc(single),
required: false
})
}
}
return { ...baseDoc, flags: [...sharedFlags, ...baseDoc.flags], globalFlags: globalFlagDocs }
})

Xet Storage Details

Size:
5.88 kB
·
Xet hash:
7a481c34f024be49ec2c07fc5429c661318194b2e9cccf554c426150d79ba0d3

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.