import * as plugins from './tswatch.plugins.js'; import * as paths from './tswatch.paths.js'; import * as interfaces from './interfaces/index.js'; import { ConfigHandler } from './tswatch.classes.confighandler.js'; import { logger } from './tswatch.logging.js'; const CONFIG_KEY = '@git.zone/tswatch'; /** * Interactive init wizard for creating tswatch configuration */ export class TswatchInit { private configHandler: ConfigHandler; private smartInteract: plugins.smartinteract.SmartInteract; constructor() { this.configHandler = new ConfigHandler(); this.smartInteract = new plugins.smartinteract.SmartInteract([]); } /** * Run the interactive init wizard */ public async run(): Promise { console.log('\n=== tswatch Configuration Wizard ===\n'); // Ask for template choice const templateAnswer = await this.smartInteract.askQuestion({ name: 'template', type: 'list', message: 'Select a configuration template:', default: 'npm', choices: [ { name: 'npm - Watch ts/ and test/, run npm test', value: 'npm' }, { name: 'test - Watch ts/ and test/, run npm run test2', value: 'test' }, { name: 'service - Watch ts/, restart npm run startTs', value: 'service' }, { name: 'element - Dev server + bundling for web components', value: 'element' }, { name: 'website - Full stack: backend + frontend + assets', value: 'website' }, { name: 'custom - Configure watchers manually', value: 'custom' }, ], }); const template = templateAnswer.value as string; let config: interfaces.ITswatchConfig; if (template === 'custom') { config = await this.runCustomWizard(); } else { // Get preset config const preset = this.configHandler.getPreset(template); if (!preset) { console.error(`Unknown template: ${template}`); return null; } config = { ...preset, preset: template as interfaces.ITswatchConfig['preset'] }; } // Save to npmextra.json await this.saveConfig(config); console.log('\nConfiguration saved to npmextra.json'); console.log('Run "tswatch" to start watching.\n'); return config; } /** * Run custom configuration wizard */ private async runCustomWizard(): Promise { const config: interfaces.ITswatchConfig = {}; // Ask about server const serverAnswer = await this.smartInteract.askQuestion({ name: 'enableServer', type: 'confirm', message: 'Enable development server?', default: false, }); if (serverAnswer.value) { const portAnswer = await this.smartInteract.askQuestion({ name: 'port', type: 'input', message: 'Server port:', default: '3002', }); const serveDirAnswer = await this.smartInteract.askQuestion({ name: 'serveDir', type: 'input', message: 'Directory to serve:', default: './dist_watch/', }); config.server = { enabled: true, port: parseInt(portAnswer.value as string, 10), serveDir: serveDirAnswer.value as string, liveReload: true, }; } // Add watchers config.watchers = []; let addMore = true; while (addMore) { console.log('\n--- Add a watcher ---'); const nameAnswer = await this.smartInteract.askQuestion({ name: 'name', type: 'input', message: 'Watcher name:', default: `watcher-${config.watchers.length + 1}`, }); const watchAnswer = await this.smartInteract.askQuestion({ name: 'watch', type: 'input', message: 'Glob pattern(s) to watch (comma-separated):', default: './ts/**/*', }); const commandAnswer = await this.smartInteract.askQuestion({ name: 'command', type: 'input', message: 'Command to execute:', default: 'npm run test', }); const restartAnswer = await this.smartInteract.askQuestion({ name: 'restart', type: 'confirm', message: 'Restart command on each change (vs queue)?', default: true, }); // Parse watch patterns const watchPatterns = (watchAnswer.value as string) .split(',') .map((p) => p.trim()) .filter((p) => p.length > 0); config.watchers.push({ name: nameAnswer.value as string, watch: watchPatterns.length === 1 ? watchPatterns[0] : watchPatterns, command: commandAnswer.value as string, restart: restartAnswer.value as boolean, debounce: 300, runOnStart: true, }); const moreAnswer = await this.smartInteract.askQuestion({ name: 'addMore', type: 'confirm', message: 'Add another watcher?', default: false, }); addMore = moreAnswer.value as boolean; } return config; } /** * Save configuration to npmextra.json */ private async saveConfig(config: interfaces.ITswatchConfig): Promise { const npmextraPath = plugins.path.join(paths.cwd, 'npmextra.json'); // Read existing npmextra.json if it exists let existingConfig: Record = {}; try { const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode()); const content = await smartfsInstance.file(npmextraPath).encoding('utf8').read() as string; existingConfig = JSON.parse(content); } catch { // File doesn't exist or is invalid, start fresh } // Update with new tswatch config existingConfig[CONFIG_KEY] = config; // Write back const smartfsInstance = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode()); await smartfsInstance.file(npmextraPath).encoding('utf8').write(JSON.stringify(existingConfig, null, 2)); } } /** * Run the init wizard */ export const runInit = async (): Promise => { const init = new TswatchInit(); return init.run(); };