ruch
Version:
Revolutionary React TypeScript CLI with hexagonal architecture & AI-powered development assistance. Create maintainable, scalable applications with domain-driven design and integrated AI tooling.
91 lines (75 loc) • 3.35 kB
text/typescript
import fs from 'fs-extra';
import path from 'path';
import type { Logger } from './console-logger';
import type { PathUtils } from './path-utils';
import type { DomainGenerationOptions } from '../templates/domains';
import { getDomainFiles } from '../templates/domains';
export interface DomainFactoryDependencies {
logger: Logger;
pathUtils: PathUtils;
generateDomainFiles: (domainName: string, options: DomainGenerationOptions) => Promise<void>;
}
export class DomainFactory {
constructor(private dependencies: DomainFactoryDependencies) {}
async createDomain(domainName: string, options: DomainGenerationOptions): Promise<void> {
const { logger, pathUtils } = this.dependencies;
// Domain name validation
if (!this.validateDomainName(domainName)) {
logger.error(`❌ Invalid domain name: "${domainName}"`);
logger.error('💡 Domain names must be valid TypeScript identifiers:');
logger.error(' - Start with a letter');
logger.error(' - Contain only letters, numbers, and underscores');
logger.error(' - No hyphens, spaces, or special characters');
logger.error('📝 Examples: "user", "userProfile", "user_profile", "orderManagement"');
return;
}
const domainPath = pathUtils.getDomainPath(domainName);
const domainsBasePath = pathUtils.getDomainsPath();
// Check if domain already exists
if (await fs.pathExists(domainPath)) {
logger.error(`Domain "${domainName}" already exists in ${domainPath}`);
return;
}
try {
// Create src/domains folder if it doesn't exist
await fs.ensureDir(domainsBasePath);
// Create domain structure
logger.info(`Creating domain "${domainName}"...`);
// Create all folders
const folders = ['entities', 'ports', 'services', 'adapters', 'hooks'];
if (options.withUi) folders.push('ui');
for (const folder of folders) {
await fs.ensureDir(path.join(domainPath, folder));
}
// Generate and write all files
const files = getDomainFiles(domainName, options);
for (const file of files) {
await fs.writeFile(path.join(domainPath, file.path), file.content, 'utf8');
}
// Display summary
logger.success(`Domain "${domainName}" created successfully!`);
logger.info(`Location: ${domainPath}`);
logger.info('Generated structure:');
console.log(`├── entities/`);
console.log(`├── ports/`);
console.log(`├── services/`);
console.log(`├── adapters/`);
console.log(`├── hooks/`);
if (options.withUi) console.log(`├── ui/`);
console.log(`└── index.ts`);
logger.info(`💡 You can now import the domain with: import { ... } from './src/domains/${domainName}'`);
} catch (error) {
logger.error(`Error creating domain: ${error instanceof Error ? error.message : 'Unknown error'}`);
// Cleanup on error
if (await fs.pathExists(domainPath)) {
await fs.remove(domainPath);
logger.info('Cleanup completed after error.');
}
}
}
private validateDomainName(domainName: string): boolean {
// Allow only valid TypeScript identifiers (no hyphens)
const validNameRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
return validNameRegex.test(domainName);
}
}