67 lines
1.9 KiB
TypeScript
67 lines
1.9 KiB
TypeScript
/**
|
|
* Helpers for finding an {@link XOTemplate} export in a loaded ES module.
|
|
*/
|
|
|
|
/**
|
|
* Returns true when `value` looks like an XOTemplate object (pre-schema check).
|
|
* Used only to pick the correct export before {@link parseTemplate} validates fully.
|
|
*/
|
|
export function isTemplateLike(
|
|
value: unknown,
|
|
): value is Record<string, unknown> {
|
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
return false;
|
|
}
|
|
|
|
const candidate = value as Record<string, unknown>;
|
|
return (
|
|
typeof candidate.$schema === "string" &&
|
|
typeof candidate.name === "string" &&
|
|
typeof candidate.roles === "object" &&
|
|
candidate.roles !== null
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Picks the single XOTemplate export from a dynamically loaded module.
|
|
*
|
|
* Resolution order:
|
|
* 1. `default` export, when template-like
|
|
* 2. Exactly one named template-like export
|
|
*
|
|
* @throws When no template export exists or multiple template exports are found.
|
|
*/
|
|
export function pickTemplateExport(
|
|
moduleExports: Record<string, unknown>,
|
|
): Record<string, unknown> {
|
|
const defaultExport = moduleExports.default;
|
|
if (isTemplateLike(defaultExport)) {
|
|
return defaultExport;
|
|
}
|
|
|
|
const namedTemplateExports = Object.entries(moduleExports).filter(
|
|
([exportName, exportValue]) =>
|
|
exportName !== "default" && isTemplateLike(exportValue),
|
|
);
|
|
|
|
if (namedTemplateExports.length === 1) {
|
|
const [, exportValue] = namedTemplateExports[0]!;
|
|
if (!isTemplateLike(exportValue)) {
|
|
throw new Error("No XOTemplate export found.");
|
|
}
|
|
return exportValue;
|
|
}
|
|
|
|
if (namedTemplateExports.length > 1) {
|
|
const exportNames = namedTemplateExports.map(([name]) => name).join(", ");
|
|
throw new Error(
|
|
`Multiple template exports found (${exportNames}). ` +
|
|
"Use a single named export or a default export.",
|
|
);
|
|
}
|
|
|
|
throw new Error(
|
|
"No XOTemplate export found. Export a template object as `default` or a named export.",
|
|
);
|
|
}
|