alks
Version:
CLI for working with ALKS
134 lines (117 loc) • 4.12 kB
text/typescript
import { getAlksAccounts } from './getAlksAccounts';
import { getFavorites } from './getFavorites';
import { getStdErrPrompt } from './getStdErrPrompt';
import { log } from './log';
import { getAlksAccount } from './state/alksAccount';
import { getAlksRole } from './state/alksRole';
import { parseAlksAccount } from './parseAlksAccount';
import { formatAccountOutput } from './formatAccountOutput';
import { compareFavorites } from './compareFavorites';
import { getAccountDelim } from './getAccountDelim';
export interface GetAlksAccountOptions {
iamOnly: boolean;
prompt: string;
filterFavorites: boolean;
}
export interface AlksAccountPromptData {
type: string;
name: string;
message: string;
source: (
answers: Record<string, unknown>,
input: string | undefined
) => Promise<string[]>;
pageSize: number;
default?: string;
}
export async function promptForAlksAccountAndRole(
options: Partial<GetAlksAccountOptions>
): Promise<{ alksAccount: string; alksRole: string }> {
const opts: GetAlksAccountOptions = {
iamOnly: options.iamOnly || false,
prompt: options.prompt || 'Please select an ALKS account/role',
filterFavorites: options.filterFavorites || false,
};
const alksAccounts = (await getAlksAccounts({ iamOnly: opts.iamOnly })).map(
parseAlksAccount
);
const favorites = await getFavorites();
log(`Favorites: ${favorites.toString()}`);
const maxAccountAliasLength = Math.max(
...alksAccounts.map((a) => a.accountAlias.length)
);
const maxAccountIdAndRoleLength = Math.max(
...alksAccounts.map((a) => a.accountIdAndRole.length)
);
const indexedAlksAccounts = alksAccounts
.filter(
(alksAccount) =>
!opts.filterFavorites ||
favorites.includes(
[alksAccount.account, alksAccount.role].join(getAccountDelim())
)
) // Filter out non-favorites if filterFavorites flag is passed
.sort(compareFavorites(favorites)) // Sort favorites to top while maintaining alphabetical order
.map((alksAccount) => ({
...alksAccount,
formattedOutput: formatAccountOutput(
alksAccount,
maxAccountAliasLength,
maxAccountIdAndRoleLength
),
})); // Add a field to the account object containing the formatted output string
if (!indexedAlksAccounts.length) {
throw new Error('No accounts found.');
}
const allChoices = indexedAlksAccounts.map((a) => a.formattedOutput);
const promptData: AlksAccountPromptData = {
type: 'autocomplete',
name: 'alksAccount',
message: opts.prompt,
source: (
_answers: Record<string, unknown>,
input: string | undefined
): Promise<string[]> => {
if (!input) {
return Promise.resolve(allChoices);
}
return Promise.resolve(
allChoices.filter((c) => c.toLowerCase().includes(input.toLowerCase()))
);
},
pageSize: 15,
};
// Ignore failure since we're about to prompt for it
const defaultAlksAccount = await getAlksAccount();
const defaultAlksRole = await getAlksRole();
// If a default account and role are set and they match an account the user has, find the corresponding formatted output string
if (defaultAlksAccount && defaultAlksRole) {
const defaultAccount = indexedAlksAccounts.find(
(account) =>
account.account === defaultAlksAccount &&
account.role === defaultAlksRole
);
if (defaultAccount) {
promptData.default = defaultAccount.formattedOutput;
}
}
// ask user which account/role
const prompt = getStdErrPrompt();
const answers = await prompt([promptData]);
const selectedString = answers.alksAccount as string;
const selectedAccount = indexedAlksAccounts.find(
(account) => account.formattedOutput === selectedString
);
if (!selectedAccount) {
log(
`Selected account "${selectedString}" not found in the list of accounts.`
);
throw new Error(
'Account selection failed. The selected account was not found.'
);
}
return {
alksAccount: selectedAccount.account,
alksRole: selectedAccount.role,
};
}