export class EventCatalog<
SchemaType extends CatalogSchema,
Classes extends EventClass = EventClass,
> {
readonly schema: Schema.Schema<
Schema.Schema.Type<SchemaType>,
Schema.Schema.Encoded<SchemaType>
>;
readonly eventClasses: readonly EventClass[];
readonly tags: readonly VersionedEventTag[];
private readonly [eventCatalogTypeId] = eventCatalogTypeId;
private constructor(schema: SchemaType, eventClasses: readonly EventClass[]) {
this.schema = Schema.make<
Schema.Schema.Type<SchemaType>,
Schema.Schema.Encoded<SchemaType>
>(schema.ast);
this.eventClasses = Object.freeze([...eventClasses]);
this.tags = Object.freeze(
this.eventClasses.map((eventClass) => eventClass._tag),
);
Object.freeze(this);
}
static make<
const EventClasses extends readonly [
EventClass,
...(readonly EventClass[]),
],
>(
...eventClasses: EventClasses
): EventCatalog<EventClassesSchema<EventClasses>, EventClasses[number]> {
validateEventClasses(eventClasses);
return new EventCatalog(makeEventClassesSchema(eventClasses), eventClasses);
}
static empty(): EventCatalog<Schema.Schema<never>, never> {
const eventClasses: readonly never[] = [];
return new EventCatalog(Schema.make<never>(Schema.Never.ast), eventClasses);
}
static merge<
const Catalogs extends readonly [
EventCatalog<CatalogSchema>,
...ReadonlyArray<EventCatalog<CatalogSchema>>,
],
>(
...catalogs: Catalogs
): EventCatalog<
MergedCatalogSchema<Catalogs>,
CatalogClassesOf<Catalogs[number]>
> {
const eventClasses = catalogs.flatMap((catalog) => catalog.eventClasses);
validateEventClasses(eventClasses);
return new EventCatalog(mergeCatalogSchemas(catalogs), eventClasses);
}
has(eventClass: EventClass): eventClass is Classes {
return this.eventClasses.some(
(catalogEventClass) => catalogEventClass === eventClass,
);
}
hasEvent(event: unknown): event is Schema.Schema.Type<SchemaType> {
if (typeof event !== "object" || event === null) {
return false;
}
const constructor: unknown = Reflect.get(event, "constructor");
return this.eventClasses.some((eventClass) => eventClass === constructor);
}
decode(input: unknown) {
return Schema.decodeUnknown(Schema.asSchema(this.schema))(input, {
onExcessProperty: "error",
});
}
encode(event: Schema.Schema.Type<SchemaType>) {
return Schema.encode(Schema.asSchema(this.schema))(event, {
onExcessProperty: "error",
});
}
}