File size: 3,710 Bytes
eb3f11e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | // Lazy command-group registration: placeholder commands are replaced by real subcommand groups.
import type { Command } from "commander";
import { getCliPluginInvocationResources } from "../runtime-cleanup-scope.js";
import { removeCommandByName } from "./command-tree.js";
import { registerLazyCommand } from "./register-lazy-command.js";
/** Placeholder command shown before its lazy group is loaded. */
export type CommandGroupPlaceholder = {
name: string;
description: string;
hidden?: boolean;
options?: readonly CommandGroupPlaceholderOption[];
};
/** Commander option metadata attached to a lazy placeholder. */
type CommandGroupPlaceholderOption = {
flags: string;
description: string;
};
/** A lazily registered command group and the names it owns. */
export type CommandGroupEntry = {
placeholders: readonly CommandGroupPlaceholder[];
names?: readonly string[];
register: (program: Command) => Promise<void> | void;
};
/** Return every command name owned by a lazy command group. */
export function getCommandGroupNames(entry: CommandGroupEntry): readonly string[] {
return entry.names ?? entry.placeholders.map((placeholder) => placeholder.name);
}
/** Find the group that owns a command name. */
export function findCommandGroupEntry(
entries: readonly CommandGroupEntry[],
name: string,
): CommandGroupEntry | undefined {
return entries.find((entry) => getCommandGroupNames(entry).includes(name));
}
/** Remove all placeholder/loaded commands owned by a group before replacing it. */
export function removeCommandGroupNames(program: Command, entry: CommandGroupEntry) {
for (const name of new Set(getCommandGroupNames(entry))) {
removeCommandByName(program, name);
}
}
/** Eagerly register one lazy command group by command name. */
export async function registerCommandGroupByName(
program: Command,
entries: readonly CommandGroupEntry[],
name: string,
): Promise<boolean> {
const entry = findCommandGroupEntry(entries, name);
if (!entry) {
return false;
}
removeCommandGroupNames(program, entry);
await entry.register(program);
return true;
}
/** Register one placeholder that loads and replaces its whole command group on demand. */
export function registerLazyCommandGroup(
program: Command,
entry: CommandGroupEntry,
placeholder: CommandGroupPlaceholder,
) {
registerLazyCommand({
program,
name: placeholder.name,
description: placeholder.description,
hidden: placeholder.hidden,
options: placeholder.options,
removeNames: getCommandGroupNames(entry),
register: () => entry.register(program),
});
}
/** Register command groups either eagerly or as lazy placeholders for startup speed. */
export function registerCommandGroups(
program: Command,
entries: readonly CommandGroupEntry[],
params: {
eager: boolean;
primary: string | null;
registerPrimaryOnly: boolean;
},
) {
if (params.eager) {
const resources = getCliPluginInvocationResources();
for (const entry of entries) {
if (resources) {
resources.register(() => entry.register(program));
} else {
void entry.register(program);
}
}
return;
}
if (params.primary && params.registerPrimaryOnly) {
const entry = findCommandGroupEntry(entries, params.primary);
if (entry) {
const placeholder = entry.placeholders.find((candidate) => candidate.name === params.primary);
if (placeholder) {
registerLazyCommandGroup(program, entry, placeholder);
}
return;
}
}
for (const entry of entries) {
for (const placeholder of entry.placeholders) {
registerLazyCommandGroup(program, entry, placeholder);
}
}
}
|