@sanity/cli
Version:
Sanity CLI tool for managing Sanity installations, managing plugins, schemas and datasets
92 lines (79 loc) • 2.73 kB
text/typescript
import chalk from 'chalk'
import leven from 'leven'
import {type CliCommandDefinition, type CliCommandGroupDefinition} from '../types'
const commonMistakes: Record<string, string | undefined> = {get: 'list'}
const levenThreshold = 3
const coreCommands = [
'build',
'check',
'configcheck',
'cors',
'dataset',
'deploy',
'dev',
'documents',
'exec',
'graphql',
'hook',
'migration',
'manifest',
'preview',
'schema',
'start',
'undeploy',
'uninstall',
'users',
]
// These are disabled in v3, but still present because of v2.
// We don't want to suggest them anymore, though.
const discouragedCommands = ['upgrade', 'check', 'configcheck', 'uninstall']
const helpText = `
Run the command again within a Sanity project directory, where "sanity"
is installed as a dependency.`
export function getNoSuchCommandText(
cmdName: string,
parentGroupName?: string | null,
groups?: Record<string, (CliCommandDefinition | CliCommandGroupDefinition)[]>,
): string {
if (parentGroupName && groups && groups[parentGroupName]) {
return suggestCommand(cmdName, groups[parentGroupName], parentGroupName)
}
const isCoreCommand = coreCommands.includes(cmdName)
if (isCoreCommand) {
return `Command "${cmdName}" is not available outside of a Sanity project context.${helpText}`
}
return suggestCommand(cmdName, groups ? groups.default : [])
}
function suggestCommand(
cmdName: string,
group: (CliCommandDefinition | CliCommandGroupDefinition)[],
parentGroupName: string | null = null,
) {
// Try to find something similar
const closest = group
.filter((command) => !discouragedCommands.includes(command.name))
.map((command) => leven(command.name, cmdName))
.reduce(
(current: {index: number; distance: number}, distance: number, index: number) =>
distance < current.distance ? {index, distance} : current,
{index: 0, distance: +Infinity},
)
// Given we are within our target threshold, suggest the command
let suggestCmd = ''
if (closest.distance <= levenThreshold) {
const cmdCandidate = group[closest.index]
suggestCmd = cmdCandidate.name
}
// Is this a common mistake that we can suggest an alias for?
const alternative = commonMistakes[cmdName]
if (!suggestCmd && alternative) {
suggestCmd = alternative
}
const input = chalk.cyan(`"${cmdName}"`)
const suggest = chalk.green(`"${suggestCmd}"`)
const help = chalk.cyan('"sanity --help"')
const didYouMean = suggestCmd ? `Did you mean ${suggest}? ` : ' '
return parentGroupName
? `${input} is not a subcommand of "sanity ${parentGroupName}". ${didYouMean}See ${help}`
: `${input} is not a sanity command. ${didYouMean}See ${help}`
}