claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
340 lines (283 loc) • 7.66 kB
text/typescript
/**
* Claude Flow Multilang Framework - DDD Base Domain Models
* Domain-Driven Design foundation for multilingual applications
*/
import { SupportedLanguage } from '../polyglot/types.js';
/**
* Base Value Object
*/
export abstract class ValueObject<T> {
protected readonly props: T;
constructor(props: T) {
this.props = Object.freeze(props);
}
equals(vo?: ValueObject<T>): boolean {
if (vo === null || vo === undefined) {
return false;
}
if (vo.props === undefined) {
return false;
}
return JSON.stringify(this.props) === JSON.stringify(vo.props);
}
}
/**
* Multilingual Value Object
*/
export class MultilingualString extends ValueObject<Record<SupportedLanguage, string>> {
constructor(values: Partial<Record<SupportedLanguage, string>>) {
// Ensure at least English is provided
if (!values[SupportedLanguage.EN]) {
throw new Error('English translation is required for multilingual strings');
}
super(values as Record<SupportedLanguage, string>);
}
get(language: SupportedLanguage): string {
return this.props[language] || this.props[SupportedLanguage.EN];
}
getAll(): Record<SupportedLanguage, string> {
return { ...this.props };
}
translate(language: SupportedLanguage, value: string): MultilingualString {
return new MultilingualString({
...this.props,
[language]: value,
});
}
}
/**
* Entity ID
*/
export class EntityId extends ValueObject<{ value: string }> {
constructor(value: string) {
super({ value });
}
get value(): string {
return this.props.value;
}
toString(): string {
return this.value;
}
static generate(): EntityId {
return new EntityId(
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
);
}
}
/**
* Base Entity
*/
export abstract class Entity<T> {
protected readonly _id: EntityId;
protected props: T;
protected readonly _createdAt: Date;
protected _updatedAt: Date;
constructor(props: T, id?: EntityId) {
this._id = id || EntityId.generate();
this.props = props;
this._createdAt = new Date();
this._updatedAt = new Date();
}
get id(): EntityId {
return this._id;
}
get createdAt(): Date {
return this._createdAt;
}
get updatedAt(): Date {
return this._updatedAt;
}
equals(entity?: Entity<T>): boolean {
if (entity === null || entity === undefined) {
return false;
}
if (this === entity) {
return true;
}
return this._id.equals(entity._id);
}
protected updateTimestamp(): void {
this._updatedAt = new Date();
}
}
/**
* Multilingual Entity
*/
export abstract class MultilingualEntity<T> extends Entity<T> {
protected translations: Map<string, MultilingualString>;
constructor(props: T, id?: EntityId) {
super(props, id);
this.translations = new Map();
}
setTranslation(key: string, value: MultilingualString): void {
this.translations.set(key, value);
this.updateTimestamp();
}
getTranslation(key: string, language: SupportedLanguage): string | undefined {
const multiString = this.translations.get(key);
return multiString?.get(language);
}
getAllTranslations(): Map<string, MultilingualString> {
return new Map(this.translations);
}
}
/**
* Aggregate Root
*/
export abstract class AggregateRoot<T> extends MultilingualEntity<T> {
private _domainEvents: DomainEvent[] = [];
private _version: number = 0;
get domainEvents(): DomainEvent[] {
return this._domainEvents;
}
get version(): number {
return this._version;
}
protected addDomainEvent(event: DomainEvent): void {
this._domainEvents.push(event);
}
clearEvents(): void {
this._domainEvents = [];
}
incrementVersion(): void {
this._version++;
this.updateTimestamp();
}
markChangesAsCommitted(): void {
this._domainEvents = [];
}
}
/**
* Domain Event
*/
export abstract class DomainEvent {
readonly occurredOn: Date;
readonly aggregateId: string;
readonly eventVersion: number;
readonly eventType: string;
constructor(aggregateId: string, eventType: string) {
this.occurredOn = new Date();
this.aggregateId = aggregateId;
this.eventVersion = 1;
this.eventType = eventType;
}
abstract toJSON(): Record<string, any>;
}
/**
* Multilingual Domain Event
*/
export abstract class MultilingualDomainEvent extends DomainEvent {
protected descriptions: MultilingualString;
constructor(
aggregateId: string,
eventType: string,
descriptions: Partial<Record<SupportedLanguage, string>>,
) {
super(aggregateId, eventType);
this.descriptions = new MultilingualString(descriptions);
}
getDescription(language: SupportedLanguage): string {
return this.descriptions.get(language);
}
toJSON(): Record<string, any> {
return {
occurredOn: this.occurredOn,
aggregateId: this.aggregateId,
eventVersion: this.eventVersion,
eventType: this.eventType,
descriptions: this.descriptions.getAll(),
};
}
}
/**
* Repository Interface
*/
export interface IRepository<T extends AggregateRoot<any>> {
save(entity: T): Promise<void>;
findById(id: EntityId): Promise<T | null>;
findAll(): Promise<T[]>;
delete(id: EntityId): Promise<void>;
exists(id: EntityId): Promise<boolean>;
}
/**
* Multilingual Repository Interface
*/
export interface IMultilingualRepository<T extends AggregateRoot<any>> extends IRepository<T> {
findByLanguage(language: SupportedLanguage): Promise<T[]>;
searchTranslations(query: string, language: SupportedLanguage): Promise<T[]>;
}
/**
* Specification Pattern
*/
export abstract class Specification<T> {
abstract isSatisfiedBy(candidate: T): boolean;
and(other: Specification<T>): Specification<T> {
return new AndSpecification(this, other);
}
or(other: Specification<T>): Specification<T> {
return new OrSpecification(this, other);
}
not(): Specification<T> {
return new NotSpecification(this);
}
}
class AndSpecification<T> extends Specification<T> {
constructor(
private left: Specification<T>,
private right: Specification<T>,
) {
super();
}
isSatisfiedBy(candidate: T): boolean {
return this.left.isSatisfiedBy(candidate) && this.right.isSatisfiedBy(candidate);
}
}
class OrSpecification<T> extends Specification<T> {
constructor(
private left: Specification<T>,
private right: Specification<T>,
) {
super();
}
isSatisfiedBy(candidate: T): boolean {
return this.left.isSatisfiedBy(candidate) || this.right.isSatisfiedBy(candidate);
}
}
class NotSpecification<T> extends Specification<T> {
constructor(private spec: Specification<T>) {
super();
}
isSatisfiedBy(candidate: T): boolean {
return !this.spec.isSatisfiedBy(candidate);
}
}
/**
* Domain Service
*/
export abstract class DomainService {
protected readonly name: string;
constructor(name: string) {
this.name = name;
}
getName(): string {
return this.name;
}
}
/**
* Multilingual Domain Service
*/
export abstract class MultilingualDomainService extends DomainService {
protected supportedLanguages: Set<SupportedLanguage>;
constructor(name: string, supportedLanguages?: SupportedLanguage[]) {
super(name);
this.supportedLanguages = new Set(
supportedLanguages || Object.values(SupportedLanguage),
);
}
isLanguageSupported(language: SupportedLanguage): boolean {
return this.supportedLanguages.has(language);
}
getSupportedLanguages(): SupportedLanguage[] {
return Array.from(this.supportedLanguages);
}
}