Files
openapi-clean-arch-gen/src/utils/prompt.ts

184 lines
5.6 KiB
TypeScript

import prompts from 'prompts';
import { ApiKeyInfo } from './environment-finder';
import { colors } from './logger';
import type { TagSummary, SelectionFilter } from '../types';
function clearScreen(): void {
process.stdout.write('\x1Bc');
}
function printHeader(current?: number, total?: number): void {
const stepText =
current !== undefined && total !== undefined
? ` [${colors.cyan}${current}${colors.reset} de ${colors.cyan}${total}${colors.reset}]`
: '';
console.log(`\n ${colors.bright}🔑 Configuración de URLs base${colors.reset}${stepText}`);
console.log(` ${'─'.repeat(54)}\n`);
}
function printSummary(tags: string[], result: Record<string, string>): void {
clearScreen();
console.log(`\n ${colors.bright}✅ Configuración completada${colors.reset}`);
console.log(` ${'─'.repeat(54)}\n`);
tags.forEach((tag) => {
console.log(` ${colors.bright}${tag}${colors.reset}`);
console.log(` ${colors.cyan}environment.${result[tag]}.url${colors.reset}\n`);
});
console.log(` ${'─'.repeat(54)}\n`);
}
/**
* Interactively asks the user which tags and endpoints to generate.
* Returns a SelectionFilter map of tag → selected operation nicknames.
*/
export async function askSelectionFilter(tagSummaries: TagSummary[]): Promise<SelectionFilter> {
if (tagSummaries.length === 0) return {};
clearScreen();
console.log(`\n ${colors.bright}📋 Selección de tags y endpoints${colors.reset}`);
console.log(` ${'─'.repeat(54)}\n`);
// Step 1: select tags
const tagResponse = await prompts({
type: 'multiselect',
name: 'tags',
message: 'Tags a generar',
choices: tagSummaries.map((t) => ({
title: `${colors.bright}${t.tag}${colors.reset} ${colors.cyan}(${t.operations.length} endpoint${t.operations.length !== 1 ? 's' : ''})${colors.reset}`,
value: t.tag,
selected: true
})),
min: 1,
hint: 'Espacio para marcar/desmarcar, Enter para confirmar'
});
if (!tagResponse.tags?.length) process.exit(0);
const selectedTags: string[] = tagResponse.tags;
const filter: SelectionFilter = {};
// Step 2: for each selected tag, select endpoints
for (let i = 0; i < selectedTags.length; i++) {
const tag = selectedTags[i];
const summary = tagSummaries.find((t) => t.tag === tag)!;
clearScreen();
console.log(
`\n ${colors.bright}📋 Endpoints a generar${colors.reset} [${colors.cyan}${i + 1}${colors.reset} de ${colors.cyan}${selectedTags.length}${colors.reset}]`
);
console.log(` ${'─'.repeat(54)}\n`);
const opResponse = await prompts({
type: 'multiselect',
name: 'ops',
message: `Tag ${colors.bright}${tag}${colors.reset}`,
choices: summary.operations.map((op) => ({
title:
`${colors.bright}${op.method.padEnd(6)}${colors.reset} ${op.path}` +
(op.summary ? ` ${colors.cyan}${op.summary}${colors.reset}` : ''),
value: op.nickname,
selected: true
})),
min: 1,
hint: 'Espacio para marcar/desmarcar, Enter para confirmar'
});
if (!opResponse.ops?.length) process.exit(0);
filter[tag] = opResponse.ops;
}
return filter;
}
/**
* Interactively asks the user which environment API key to use for each tag,
* using arrow-key selection. The last option always allows typing manually.
* Returns a map of tag → environment key (e.g. { "SupplyingMaintenances": "suppliyingMaintenancesApi" }).
*/
export async function askApiKeysForTags(
tags: string[],
apiKeys: ApiKeyInfo[]
): Promise<Record<string, string>> {
if (tags.length === 0) return {};
clearScreen();
printHeader();
const modeResponse = await prompts({
type: 'select',
name: 'mode',
message: 'URL base para los repositorios',
choices: [
{ title: `${colors.bright}La misma para todos${colors.reset}`, value: 'all' },
{ title: `${colors.bright}Configurar individualmente${colors.reset}`, value: 'individual' }
],
hint: ' '
});
if (modeResponse.mode === undefined) process.exit(0);
const result: Record<string, string> = {};
if (modeResponse.mode === 'all') {
clearScreen();
printHeader();
const sharedKey = await askApiKeyForTag('todos los repositorios', apiKeys);
tags.forEach((tag) => (result[tag] = sharedKey));
} else {
for (let i = 0; i < tags.length; i++) {
clearScreen();
printHeader(i + 1, tags.length);
result[tags[i]] = await askApiKeyForTag(tags[i], apiKeys);
}
}
printSummary(tags, result);
return result;
}
async function askApiKeyForTag(tagName: string, apiKeys: ApiKeyInfo[]): Promise<string> {
const MANUAL_VALUE = '__manual__';
const choices = [
...apiKeys.map((k) => ({
title: k.url
? `${colors.bright}${k.key}${colors.reset}\n ${colors.cyan}${k.url}${colors.reset}`
: `${colors.bright}${k.key}${colors.reset}`,
value: k.key
})),
{
title: `${colors.bright}Escribir manualmente${colors.reset}`,
value: MANUAL_VALUE
}
];
const selectResponse = await prompts({
type: 'select',
name: 'key',
message: `Repositorio ${colors.bright}${tagName}${colors.reset}`,
choices,
hint: ' '
});
if (selectResponse.key === undefined) process.exit(0);
if (selectResponse.key !== MANUAL_VALUE) {
return selectResponse.key as string;
}
console.log();
const textResponse = await prompts({
type: 'text',
name: 'key',
message: `Clave de environment`,
hint: 'ej: aprovalmApi',
validate: (v: string) => v.trim().length > 0 || 'La clave no puede estar vacía'
});
if (textResponse.key === undefined) process.exit(0);
return (textResponse.key as string).trim();
}