-
Notifications
You must be signed in to change notification settings - Fork 73
/
util.ts
97 lines (78 loc) · 3.38 KB
/
util.ts
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
import * as ejs from 'ejs'
import {Config as IConfig, HelpOptions} from '../interfaces'
import {Help, HelpBase} from '.'
import ModuleLoader from '../module-loader'
interface HelpBaseDerived {
new(config: IConfig, opts?: Partial<HelpOptions>): HelpBase;
}
function extractClass(exported: any): HelpBaseDerived {
return exported && exported.default ? exported.default : exported
}
export async function loadHelpClass(config: IConfig): Promise<HelpBaseDerived> {
const pjson = config.pjson
const configuredClass = pjson && pjson.oclif && pjson.oclif.helpClass
if (configuredClass) {
try {
const exported = await ModuleLoader.load(config, configuredClass) as HelpBaseDerived
return extractClass(exported) as HelpBaseDerived
} catch (error: any) {
throw new Error(`Unable to load configured help class "${configuredClass}", failed with message:\n${error.message}`)
}
}
return Help
}
export function template(context: any): (t: string) => string {
function render(t: string): string {
return ejs.render(t, context)
}
return render
}
function collateSpacedCmdIDFromArgs(argv: string[], config: IConfig): string[] {
if (argv.length === 1) return argv
const ids = new Set(config.commandIDs.concat(config.topics.map(t => t.name)))
const findId = (argv: string[]): string | undefined => {
const final: string[] = []
const idPresent = (id: string) => ids.has(id)
const isFlag = (s: string) => s.startsWith('-')
const isArgWithValue = (s: string) => s.includes('=')
const finalizeId = (s?: string) => s ? [...final, s].join(':') : final.join(':')
const hasSubCommandsWithArgs = () => {
const id = finalizeId()
/**
* Get a list of sub commands for the current command id. A command is returned as a subcommand under either
* of these conditions:
* 1. the `id` start with the current command id.
* 2. any of the aliases start with the current command id.
*/
const subCommands = config.commands.filter(c => (c.id).startsWith(id) || c.aliases.some(a => a.startsWith(id)))
return Boolean(subCommands.find(cmd => cmd.strict === false || cmd.args?.length > 0))
}
for (const arg of argv) {
if (idPresent(finalizeId(arg))) final.push(arg)
// If the parent topic has a command that expects positional arguments, then we cannot
// assume that any subsequent string could be part of the command name
else if (isArgWithValue(arg) || isFlag(arg) || hasSubCommandsWithArgs()) break
else final.push(arg)
}
return finalizeId()
}
const id = findId(argv)
if (id) {
const argvSlice = argv.slice(id.split(':').length)
return [id, ...argvSlice]
}
return argv // ID is argv[0]
}
export function toStandardizedId(commandID: string, config: IConfig): string {
return commandID.replace(new RegExp(config.topicSeparator, 'g'), ':')
}
export function toConfiguredId(commandID: string, config: IConfig): string {
const defaultTopicSeperator = ':'
return commandID.replace(new RegExp(defaultTopicSeperator, 'g'), config.topicSeparator || defaultTopicSeperator)
}
export function standardizeIDFromArgv(argv: string[], config: IConfig): string[] {
if (argv.length === 0) return argv
if (config.topicSeparator === ' ') argv = collateSpacedCmdIDFromArgs(argv, config)
else if (config.topicSeparator !== ':') argv[0] = toStandardizedId(argv[0], config)
return argv
}