CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stricli--core

Build complex CLIs with type safety and no dependencies

Overview
Eval results
Files

documentation-and-help.mddocs/

Documentation and Help

Generate help text and shell completions for commands.

Quick Reference

// Generate help for all commands
const docs = generateHelpTextForAllCommands(app);
for (const [route, helpText] of docs) {
  console.log(`${route}:\n${helpText}\n`);
}

// Shell completions
const completions = await proposeCompletions(app, ["myapp", "deploy", "--e"], { process });
// Returns: [{ kind: "argument:flag", completion: "--env", brief: "Environment" }]

Generate Help Text

function generateHelpTextForAllCommands(
  app: Application<CommandContext>,
  locale?: string
): readonly [route: string, helpText: string][]

Example:

const app = buildApplication(routeMap, { name: "myapp" });
const docs = generateHelpTextForAllCommands(app);

// docs = [
//   ["myapp deploy", "USAGE\n  myapp deploy [OPTIONS]\n\n..."],
//   ["myapp status", "USAGE\n  myapp status\n\n..."]
// ]

// Write to files
for (const [route, helpText] of docs) {
  const filename = route.replace(/ /g, "-") + ".txt";
  await writeFile(filename, helpText);
}

Propose Completions

async function proposeCompletions<CONTEXT>(
  app: Application<CONTEXT>,
  rawInputs: readonly string[],
  context: StricliDynamicCommandContext<CONTEXT>
): Promise<readonly InputCompletion[]>

InputCompletion:

type InputCompletion = ArgumentCompletion | RoutingTargetCompletion

interface ArgumentCompletion {
  kind: "argument:flag" | "argument:value"
  completion: string
  brief: string
}

interface RoutingTargetCompletion {
  kind: "routing-target:command" | "routing-target:route-map"
  completion: string
  brief: string
}

Examples:

// Complete command names
await proposeCompletions(app, ["myapp", "de"], { process })
// Returns: [{ kind: "routing-target:command", completion: "deploy", brief: "Deploy application" }]

// Complete flag names
await proposeCompletions(app, ["myapp", "deploy", "--e"], { process })
// Returns: [{ kind: "argument:flag", completion: "--env", brief: "Environment" }]

// Complete flag values
await proposeCompletions(app, ["myapp", "deploy", "--env", "st"], { process })
// Returns: [{ kind: "argument:value", completion: "staging", brief: "Environment" }]

// Complete aliases
await proposeCompletions(app, ["myapp", "deploy", "-"], { process })
// Returns: [
//   { kind: "argument:flag", completion: "-e", brief: "Environment" },
//   { kind: "argument:flag", completion: "-f", brief: "Force deployment" }
// ]

Shell Completion Command

const completeCmd = buildCommand({
  func: async function(flags, ...inputs) {
    const completions = await proposeCompletions(app, inputs, { process });
    for (const completion of completions) {
      this.process.stdout.write(completion.completion + "\n");
    }
  },
  parameters: {
    positional: {
      kind: "array",
      parameter: { brief: "Input words", parse: String }
    }
  },
  docs: { brief: "Shell completion", hideRoute: { __complete: true } }
});

const app = buildApplication(
  buildRouteMap({
    routes: {
      ...mainRoutes,
      __complete: completeCmd  // Hidden completion command
    },
    docs: { brief: "My CLI" }
  }),
  { name: "myapp" }
);

Bash Completion Script

_myapp_completions() {
  local completions=$(myapp __complete "${COMP_WORDS[@]:1}")
  COMPREPLY=($(compgen -W "$completions" -- "${COMP_WORDS[COMP_CWORD]}"))
}
complete -F _myapp_completions myapp

Zsh Completion Script

#compdef myapp

_myapp() {
  local completions=(${(f)"$(myapp __complete ${words[@]:1})"})
  _describe 'command' completions
}

_myapp

Custom Completions

Add proposeCompletions to parameter definitions for dynamic completions.

// File path completions
positional: {
  kind: "tuple",
  parameters: [
    {
      brief: "File to process",
      parse: String,
      proposeCompletions: async () => {
        const files = await readdir(".");
        return files.filter(f => f.endsWith(".txt"));
      }
    }
  ]
}

// API completions with context
interface MyContext extends CommandContext {
  api: { listUsers: () => Promise<string[]> };
}

positional: {
  kind: "tuple",
  parameters: [
    {
      brief: "User ID",
      parse: String,
      proposeCompletions: async function(this: MyContext) {
        return await this.api.listUsers();
      }
    }
  ]
}

Related

  • Configuration and Context
  • Text and Localization

Install with Tessl CLI

npx tessl i tessl/npm-stricli--core

docs

application.md

commands-and-routing.md

configuration-and-context.md

documentation-and-help.md

error-handling.md

exit-codes.md

flag-parameters.md

index.md

parameter-parsers.md

positional-parameters.md

text-and-localization.md

tile.json