All files / src/lib get-command-info.js

95.45% Statements 84/88
78.37% Branches 29/37
100% Functions 1/1
95.45% Lines 84/88

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 89193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 25x 25x 25x 110x     110x 25x 25x 19x 18x 18x 18x     18x 19x 25x 21x 21x 25x 25x 25x 25x 25x 18x 18x 18x 18x 18x 18x 12x 25x 25x 25x 25x 25x 25x 21x 192x 192x 192x 192x 21x 21x 110x 110x 110x 110x 110x 110x 110x 110x 110x 110x 110x 110x 110x 110x 106x 110x 110x 110x 110x 110x 21x 25x 25x 25x 25x  
import { getDefault, getEnumValues, isBoolean, isRequired } from './zod-utils.js';
 
/**
 * @typedef {import('./get-command-info.types.d.ts').ArgumentInfo} ArgumentInfo
 * @typedef {import('./get-command-info.types.d.ts').OptionInfo} OptionInfo
 * @typedef {import('./get-command-info.types.d.ts').CommandInfo} CommandInfo
 * @typedef {import('./define-command.types.d.ts').CommandDefinition} CommandDefinition
 * @typedef {import('./define-option.types.d.ts').OptionDefinition} OptionDefinition
 */
 
/**
 * Extracts normalized command information for display purposes.
 * This function provides a shared source of truth for CLI help, reference docs, and LLM docs.
 * @param {string[]} path - Command path (e.g., ['env', 'set'])
 * @param {CommandDefinition} definition
 * @return {CommandInfo}
 */
export function getCommandInfo(path, definition) {
  const usageParts = ['clever', ...path];
  if (definition.options != null) {
    for (const option of Object.values(definition.options)) {
      if (isRequired(option.schema)) {
        usageParts.push(`--${option.name} <${option.placeholder ?? option.name}>`);
      }
    }
  }
  if (definition.args != null) {
    for (const arg of definition.args) {
      if (isRequired(arg.schema)) {
        usageParts.push(`<${arg.placeholder}>`);
      } else {
        usageParts.push(`[<${arg.placeholder}>]`);
      }
    }
  }
  if (definition.options != null && Object.keys(definition.options).length > 0) {
    usageParts.push('[options]');
  }
  const usage = usageParts.join(' ');
 
  // Build args info (sorted by position, i.e., as defined)
  const args = definition.args?.length
    ? definition.args.map((arg) => {
        return {
          name: arg.placeholder,
          description: arg.description,
          optional: isRequired(arg.schema) ? null : '(optional)',
          enumValues: getEnumValues(arg.schema) ?? null,
        };
      })
    : null;
 
  // Build options info (sorted: required first, then alphabetically)
  const optionValues = Object.values(definition.options ?? {});
  const options = optionValues.length
    ? optionValues
        .sort((optA, optB) => {
          const aRequired = isRequired(optA.schema);
          const bRequired = isRequired(optB.schema);
          if (aRequired !== bRequired) return aRequired ? -1 : 1;
          return optA.name.localeCompare(optB.name);
        })
        .map((option) => {
          const shortAliases = (option.aliases?.filter((a) => a.length === 1) ?? []).map((a) => `-${a}`);
          const longAliases = (option.aliases?.filter((a) => a.length > 1) ?? []).map((a) => `--${a}`);
          const allAliases = [...shortAliases, `--${option.name}`, ...longAliases];
          const defaultValue = getDefault(option.schema);
 
          return {
            name: option.name,
            aliases: allAliases,
            placeholder: isBoolean(option.schema) ? null : `<${option.placeholder ?? option.name}>`,
            description: option.description,
            deprecated:
              typeof option.deprecated === 'string'
                ? `(deprecated, ${option.deprecated})`
                : option.deprecated === true
                  ? '(deprecated)'
                  : null,
            required: isRequired(option.schema) ? '(required)' : null,
            default: defaultValue ? `(default: ${defaultValue})` : null,
            enumValues: getEnumValues(option.schema) ?? null,
          };
        })
    : null;
 
  return { usage, args, options };
}