Files
tswatch/ts/tswatch.init.ts

200 lines
5.9 KiB
TypeScript

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<interfaces.ITswatchConfig | null> {
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<interfaces.ITswatchConfig> {
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<void> {
const npmextraPath = plugins.path.join(paths.cwd, 'npmextra.json');
// Read existing npmextra.json if it exists
let existingConfig: Record<string, any> = {};
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<interfaces.ITswatchConfig | null> => {
const init = new TswatchInit();
return init.run();
};