forked from SmartThingsCommunity/smartthings-cli
-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathutil-util.ts
More file actions
103 lines (90 loc) · 3.37 KB
/
util-util.ts
File metadata and controls
103 lines (90 loc) · 3.37 KB
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
import { type APICommand } from '../api-command.js'
import { stringTranslateToId } from '../command-util.js'
import { type SelectFromListConfig, type SelectFromListFlags, SelectOptions, selectFromList } from '../select.js'
export type ListItemPredicate<T extends object> = (value: T, index: number, array: T[]) => boolean
/**
* Note that a few functions using this interface don't support all options. Check the
* `chooseThing` (e.g. `chooseDevice`) method itself. (If the `chooseThing` is implemented using
* `createChooseFn`, it will support all of them, with the exception of `useConfigDefault`
* which will work only if the call to `createChooseFn` includes configuration for it via the
* `defaultValue` option.)
*/
export type ChooseOptions<T extends object> = {
allowIndex: boolean
verbose: boolean
useConfigDefault: boolean
listItems?: (command: APICommand) => Promise<T[]>
autoChoose?: boolean
listFilter?: ListItemPredicate<T>
promptMessage?: string
}
export const chooseOptionsDefaults = <T extends object>(): ChooseOptions<T> => ({
allowIndex: false,
verbose: false,
useConfigDefault: false,
autoChoose: false,
})
export const chooseOptionsWithDefaults = <T extends object>(
options: Partial<ChooseOptions<T>> | undefined,
): ChooseOptions<T> => ({
...chooseOptionsDefaults(),
...options,
})
export type CreateChooseFunctionOptions<T extends object> = {
defaultValue?: Omit<Required<SelectOptions<T>>['defaultValue'], 'getItem'> & {
getItem: (command: APICommand, id: string) => Promise<T>
}
customNotFoundMessage?: string
}
export type ChooseFunction<T extends object> = (
command: APICommand<SelectFromListFlags>,
itemIdOrIndexFromArg?: string,
options?: Partial<ChooseOptions<T>>) => Promise<string>
export const createChooseFn = <T extends object>(
config: SelectFromListConfig<T>,
listItems: (command: APICommand) => Promise<T[]>,
createOptions?: CreateChooseFunctionOptions<T>,
): ChooseFunction<T> =>
async (
command: APICommand<SelectFromListFlags>,
itemIdOrIndexFromArg?: string,
options?: Partial<ChooseOptions<T>>,
): Promise<string> => {
const opts = chooseOptionsWithDefaults(options)
// Listing items usually makes an API call which we only want to happen once so we do it
// now and just use stub functions that return these items later as needed.
let items: T[] | undefined = undefined
const listItemsWrapper = async (): Promise<T[]> => {
if (!items) {
items = await (opts.listItems ?? listItems)(command)
}
const filteredItems = opts.listFilter ? items.filter(opts.listFilter) : items
return filteredItems
}
const preselectedId = opts.allowIndex
? await stringTranslateToId(config, itemIdOrIndexFromArg, listItemsWrapper)
: itemIdOrIndexFromArg
const selectOptions: SelectOptions<T> = {
preselectedId,
autoChoose: opts.autoChoose,
listItems: listItemsWrapper,
promptMessage: opts.promptMessage,
customNotFoundMessage: createOptions?.customNotFoundMessage,
}
if (opts.useConfigDefault) {
const defaultValue = createOptions?.defaultValue
if (!defaultValue) {
throw Error('invalid state, the choose<Thing> function was called with "useConfigDefault"' +
' but no default configured')
}
selectOptions.defaultValue = {
...defaultValue,
getItem: (id: string): Promise<T> => defaultValue.getItem(command, id),
}
}
return selectFromList(
command,
config,
selectOptions,
)
}