import type {
NamespaceProviders,
ProviderFunction,
QuartoAPI,
} from "./types.ts";
export class UnregisteredNamespaceError extends Error {
constructor(namespace: string) {
super(
`QuartoAPI namespace '${namespace}' has not been registered. ` +
`Ensure that 'src/core/api/register.ts' is imported before using the API.`,
);
this.name = "UnregisteredNamespaceError";
}
}
export class RegistryFinalizedError extends Error {
constructor(namespace: string) {
super(
`Cannot register namespace '${namespace}': Registry has been finalized. ` +
`All registrations must occur before createAPI() is called.`,
);
this.name = "RegistryFinalizedError";
}
}
export class QuartoAPIRegistry {
private providers: NamespaceProviders = {};
private implementations: Partial<QuartoAPI> = {};
private finalized = false;
private apiInstance: QuartoAPI | null = null;
register<K extends keyof QuartoAPI>(
namespace: K,
provider: ProviderFunction<QuartoAPI[K]>,
): void {
if (this.finalized) {
throw new RegistryFinalizedError(namespace);
}
if (this.providers[namespace]) {
throw new Error(
`QuartoAPI namespace '${namespace}' is already registered`,
);
}
(this.providers as any)[namespace] = provider;
}
createAPI(): QuartoAPI {
if (this.apiInstance) {
return this.apiInstance;
}
const requiredNamespaces: Array<keyof QuartoAPI> = [
"markdownRegex",
"mappedString",
"jupyter",
"format",
"path",
"system",
"text",
"console",
"crypto",
];
const missingNamespaces = requiredNamespaces.filter(
(ns) => !this.providers[ns],
);
if (missingNamespaces.length > 0) {
throw new UnregisteredNamespaceError(
`Missing required namespaces: ${missingNamespaces.join(", ")}`,
);
}
for (const namespace of requiredNamespaces) {
const provider = this.providers[namespace];
if (provider) {
(this.implementations as any)[namespace] = provider();
}
}
this.finalized = true;
this.apiInstance = this.implementations as QuartoAPI;
return this.apiInstance;
}
isRegistered(namespace: keyof QuartoAPI): boolean {
return !!this.providers[namespace];
}
clearCache(): void {
this.implementations = {};
this.apiInstance = null;
this.finalized = false;
}
}
export const globalRegistry = new QuartoAPIRegistry();