i18ntk
Version:
i18n Tool Kit - Zero-dependency internationalization toolkit for setup, scanning, analysis, validation, auto translation, fixing, reporting, and runtime translation loading.
154 lines (135 loc) • 4.76 kB
JavaScript
/**
* Centralized CLI Helper - Shared readline interface management
*
* This module provides a single readline interface instance to prevent
* multiple instances and simplify cleanup across the application.
*
* @version 1.10.0
* @since 2025-08-08
*/
const { getGlobalReadline, closeGlobalReadline, ask, askHidden } = require('./cli');
const { parseConfirmation } = require('./localized-confirm');
class CliHelper {
constructor() {
// Use the global readline interface from cli.js instead of creating our own
this.rl = null;
this.isInitialized = false;
}
/**
* Initialize the shared readline interface
* @returns {readline.Interface} The readline interface
*/
initialize() {
if (!this.isInitialized) {
this.rl = getGlobalReadline();
this.isInitialized = true;
}
return this.rl;
}
/**
* Get the shared readline interface
* @returns {readline.Interface} The readline interface
*/
getInterface() {
return this.initialize();
}
/**
* Prompt user for input with optional masking
* @param {string} question - The prompt question
* @param {boolean} maskInput - Whether to mask the input (for passwords)
* @returns {Promise<string>} The user's input
*/
async prompt(question, maskInput = false) {
if (maskInput) {
return askHidden(question);
} else {
return ask(question);
}
}
/**
* Prompt for PIN with secure masking
* @param {string} message - Custom message for PIN prompt
* @returns {Promise<string>} The PIN entered by user
*/
async promptPin(message = 'Enter PIN: ') {
return askHidden(message);
}
/**
* Close the readline interface and clean up resources
*/
close() {
if (this.isInitialized) {
const { closeGlobalReadline } = require('./cli');
closeGlobalReadline();
this.rl = null;
this.isInitialized = false;
}
}
/**
* Check if the interface is initialized
* @returns {boolean} Whether the interface is initialized
*/
isActive() {
return this.isInitialized && this.rl !== null;
}
/**
* Get a yes/no confirmation from user
* @param {string} question - The confirmation question
* @param {boolean} defaultValue - Default value if user just presses enter
* @returns {Promise<boolean>} The user's confirmation
*/
async confirm(question, defaultValue = false, language = 'en') {
const promptText = `${question} (${defaultValue ? 'Y/n' : 'y/N'}): `;
const answer = await ask(promptText);
return parseConfirmation(answer, { language, defaultValue });
}
/**
* Display a menu and get user selection
* @param {Array<string>} options - Array of menu options
* @param {string} title - Optional menu title
* @returns {Promise<number>} The selected option index (0-based)
*/
async selectMenu(options, title = 'Please select an option:') {
console.log(`\n${title}`);
options.forEach((option, index) => {
console.log(` ${index + 1}. ${option}`);
});
while (true) {
const answer = await ask('\nEnter your choice: ');
const choice = parseInt(answer.trim(), 10);
if (isNaN(choice) || choice < 1 || choice > options.length) {
console.log('Invalid choice. Please try again.');
continue;
} else {
return choice - 1;
}
}
}
}
// Utility: Show framework suggestion warning only once per process
let frameworkWarningShown = false;
function showFrameworkWarningOnce(ui) {
if (frameworkWarningShown) return;
frameworkWarningShown = true;
const translate = ui && typeof ui.t === 'function'
? ui.t.bind(ui)
: require('./i18n-helper').t;
const fallback = {
noFramework: 'No i18n framework detected. Consider using one of the following:',
react: ' - React i18next (react-i18next)',
vue: ' - Vue i18n (vue-i18next)',
i18next: ' - i18next (i18next)',
nuxt: ' - Nuxt i18n (@nuxtjs/i18n)',
svelte: ' - Svelte i18n (svelte-i18n)'
};
console.log(translate('init.suggestions.noFramework') || fallback.noFramework);
console.log(translate('init.frameworks.react') || fallback.react);
console.log(translate('init.frameworks.vue') || fallback.vue);
console.log(translate('init.frameworks.i18next') || fallback.i18next);
console.log(translate('init.frameworks.nuxt') || fallback.nuxt);
console.log(translate('init.frameworks.svelte') || fallback.svelte);
}
// Export a singleton instance and attach utility for backward compatibility
const cliHelper = new CliHelper();
cliHelper.showFrameworkWarningOnce = showFrameworkWarningOnce;
module.exports = cliHelper;