303 lines
9.4 KiB
JavaScript
303 lines
9.4 KiB
JavaScript
![]() |
import { string as zodString, ZodIssueCode } from "zod";
|
||
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
||
|
import { prependForwardSlash } from "../core/path.js";
|
||
|
import {
|
||
|
createComponent,
|
||
|
createHeadAndContent,
|
||
|
renderComponent,
|
||
|
renderScriptElement,
|
||
|
renderTemplate,
|
||
|
renderUniqueStylesheet,
|
||
|
unescapeHTML
|
||
|
} from "../runtime/server/index.js";
|
||
|
function createCollectionToGlobResultMap({
|
||
|
globResult,
|
||
|
contentDir
|
||
|
}) {
|
||
|
const collectionToGlobResultMap = {};
|
||
|
for (const key in globResult) {
|
||
|
const keyRelativeToContentDir = key.replace(new RegExp(`^${contentDir}`), "");
|
||
|
const segments = keyRelativeToContentDir.split("/");
|
||
|
if (segments.length <= 1)
|
||
|
continue;
|
||
|
const collection = segments[0];
|
||
|
collectionToGlobResultMap[collection] ??= {};
|
||
|
collectionToGlobResultMap[collection][key] = globResult[key];
|
||
|
}
|
||
|
return collectionToGlobResultMap;
|
||
|
}
|
||
|
const cacheEntriesByCollection = /* @__PURE__ */ new Map();
|
||
|
function createGetCollection({
|
||
|
contentCollectionToEntryMap,
|
||
|
dataCollectionToEntryMap,
|
||
|
getRenderEntryImport
|
||
|
}) {
|
||
|
return async function getCollection(collection, filter) {
|
||
|
let type;
|
||
|
if (collection in contentCollectionToEntryMap) {
|
||
|
type = "content";
|
||
|
} else if (collection in dataCollectionToEntryMap) {
|
||
|
type = "data";
|
||
|
} else {
|
||
|
throw new AstroError({
|
||
|
...AstroErrorData.CollectionDoesNotExistError,
|
||
|
message: AstroErrorData.CollectionDoesNotExistError.message(collection)
|
||
|
});
|
||
|
}
|
||
|
const lazyImports = Object.values(
|
||
|
type === "content" ? contentCollectionToEntryMap[collection] : dataCollectionToEntryMap[collection]
|
||
|
);
|
||
|
let entries = [];
|
||
|
if (import.meta.env.PROD && cacheEntriesByCollection.has(collection)) {
|
||
|
entries = cacheEntriesByCollection.get(collection);
|
||
|
} else {
|
||
|
entries = await Promise.all(
|
||
|
lazyImports.map(async (lazyImport) => {
|
||
|
const entry = await lazyImport();
|
||
|
return type === "content" ? {
|
||
|
id: entry.id,
|
||
|
slug: entry.slug,
|
||
|
body: entry.body,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data,
|
||
|
async render() {
|
||
|
return render({
|
||
|
collection: entry.collection,
|
||
|
id: entry.id,
|
||
|
renderEntryImport: await getRenderEntryImport(collection, entry.slug)
|
||
|
});
|
||
|
}
|
||
|
} : {
|
||
|
id: entry.id,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data
|
||
|
};
|
||
|
})
|
||
|
);
|
||
|
cacheEntriesByCollection.set(collection, entries);
|
||
|
}
|
||
|
if (typeof filter === "function") {
|
||
|
return entries.filter(filter);
|
||
|
} else {
|
||
|
return entries;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
function createGetEntryBySlug({
|
||
|
getEntryImport,
|
||
|
getRenderEntryImport
|
||
|
}) {
|
||
|
return async function getEntryBySlug(collection, slug) {
|
||
|
const entryImport = await getEntryImport(collection, slug);
|
||
|
if (typeof entryImport !== "function")
|
||
|
return void 0;
|
||
|
const entry = await entryImport();
|
||
|
return {
|
||
|
id: entry.id,
|
||
|
slug: entry.slug,
|
||
|
body: entry.body,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data,
|
||
|
async render() {
|
||
|
return render({
|
||
|
collection: entry.collection,
|
||
|
id: entry.id,
|
||
|
renderEntryImport: await getRenderEntryImport(collection, slug)
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
function createGetDataEntryById({
|
||
|
dataCollectionToEntryMap
|
||
|
}) {
|
||
|
return async function getDataEntryById(collection, id) {
|
||
|
var _a;
|
||
|
const lazyImport = (_a = dataCollectionToEntryMap[collection]) == null ? void 0 : _a[
|
||
|
/*TODO: filePathToIdMap*/
|
||
|
id + ".json"
|
||
|
];
|
||
|
if (!lazyImport)
|
||
|
throw new Error(`Entry ${collection} \u2192 ${id} was not found.`);
|
||
|
const entry = await lazyImport();
|
||
|
return {
|
||
|
id: entry.id,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
function createGetEntry({
|
||
|
getEntryImport,
|
||
|
getRenderEntryImport
|
||
|
}) {
|
||
|
return async function getEntry(collectionOrLookupObject, _lookupId) {
|
||
|
let collection, lookupId;
|
||
|
if (typeof collectionOrLookupObject === "string") {
|
||
|
collection = collectionOrLookupObject;
|
||
|
if (!_lookupId)
|
||
|
throw new AstroError({
|
||
|
...AstroErrorData.UnknownContentCollectionError,
|
||
|
message: "`getEntry()` requires an entry identifier as the second argument."
|
||
|
});
|
||
|
lookupId = _lookupId;
|
||
|
} else {
|
||
|
collection = collectionOrLookupObject.collection;
|
||
|
lookupId = "id" in collectionOrLookupObject ? collectionOrLookupObject.id : collectionOrLookupObject.slug;
|
||
|
}
|
||
|
const entryImport = await getEntryImport(collection, lookupId);
|
||
|
if (typeof entryImport !== "function")
|
||
|
return void 0;
|
||
|
const entry = await entryImport();
|
||
|
if (entry._internal.type === "content") {
|
||
|
return {
|
||
|
id: entry.id,
|
||
|
slug: entry.slug,
|
||
|
body: entry.body,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data,
|
||
|
async render() {
|
||
|
return render({
|
||
|
collection: entry.collection,
|
||
|
id: entry.id,
|
||
|
renderEntryImport: await getRenderEntryImport(collection, lookupId)
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
} else if (entry._internal.type === "data") {
|
||
|
return {
|
||
|
id: entry.id,
|
||
|
collection: entry.collection,
|
||
|
data: entry.data
|
||
|
};
|
||
|
}
|
||
|
return void 0;
|
||
|
};
|
||
|
}
|
||
|
function createGetEntries(getEntry) {
|
||
|
return async function getEntries(entries) {
|
||
|
return Promise.all(entries.map((e) => getEntry(e)));
|
||
|
};
|
||
|
}
|
||
|
async function render({
|
||
|
collection,
|
||
|
id,
|
||
|
renderEntryImport
|
||
|
}) {
|
||
|
var _a, _b;
|
||
|
const UnexpectedRenderError = new AstroError({
|
||
|
...AstroErrorData.UnknownContentCollectionError,
|
||
|
message: `Unexpected error while rendering ${String(collection)} \u2192 ${String(id)}.`
|
||
|
});
|
||
|
if (typeof renderEntryImport !== "function")
|
||
|
throw UnexpectedRenderError;
|
||
|
const baseMod = await renderEntryImport();
|
||
|
if (baseMod == null || typeof baseMod !== "object")
|
||
|
throw UnexpectedRenderError;
|
||
|
const { default: defaultMod } = baseMod;
|
||
|
if (isPropagatedAssetsModule(defaultMod)) {
|
||
|
const { collectedStyles, collectedLinks, collectedScripts, getMod } = defaultMod;
|
||
|
if (typeof getMod !== "function")
|
||
|
throw UnexpectedRenderError;
|
||
|
const propagationMod = await getMod();
|
||
|
if (propagationMod == null || typeof propagationMod !== "object")
|
||
|
throw UnexpectedRenderError;
|
||
|
const Content = createComponent({
|
||
|
factory(result, baseProps, slots) {
|
||
|
let styles = "", links = "", scripts = "";
|
||
|
if (Array.isArray(collectedStyles)) {
|
||
|
styles = collectedStyles.map((style) => {
|
||
|
return renderUniqueStylesheet(result, {
|
||
|
type: "inline",
|
||
|
content: style
|
||
|
});
|
||
|
}).join("");
|
||
|
}
|
||
|
if (Array.isArray(collectedLinks)) {
|
||
|
links = collectedLinks.map((link) => {
|
||
|
return renderUniqueStylesheet(result, {
|
||
|
type: "external",
|
||
|
src: prependForwardSlash(link)
|
||
|
});
|
||
|
}).join("");
|
||
|
}
|
||
|
if (Array.isArray(collectedScripts)) {
|
||
|
scripts = collectedScripts.map((script) => renderScriptElement(script)).join("");
|
||
|
}
|
||
|
let props = baseProps;
|
||
|
if (id.endsWith("mdx")) {
|
||
|
props = {
|
||
|
components: propagationMod.components ?? {},
|
||
|
...baseProps
|
||
|
};
|
||
|
}
|
||
|
return createHeadAndContent(
|
||
|
unescapeHTML(styles + links + scripts),
|
||
|
renderTemplate`${renderComponent(
|
||
|
result,
|
||
|
"Content",
|
||
|
propagationMod.Content,
|
||
|
props,
|
||
|
slots
|
||
|
)}`
|
||
|
);
|
||
|
},
|
||
|
propagation: "self"
|
||
|
});
|
||
|
return {
|
||
|
Content,
|
||
|
headings: ((_a = propagationMod.getHeadings) == null ? void 0 : _a.call(propagationMod)) ?? [],
|
||
|
remarkPluginFrontmatter: propagationMod.frontmatter ?? {}
|
||
|
};
|
||
|
} else if (baseMod.Content && typeof baseMod.Content === "function") {
|
||
|
return {
|
||
|
Content: baseMod.Content,
|
||
|
headings: ((_b = baseMod.getHeadings) == null ? void 0 : _b.call(baseMod)) ?? [],
|
||
|
remarkPluginFrontmatter: baseMod.frontmatter ?? {}
|
||
|
};
|
||
|
} else {
|
||
|
throw UnexpectedRenderError;
|
||
|
}
|
||
|
}
|
||
|
function createReference({ lookupMap }) {
|
||
|
return function reference(collection) {
|
||
|
return zodString().transform((lookupId, ctx) => {
|
||
|
const flattenedErrorPath = ctx.path.join(".");
|
||
|
if (!lookupMap[collection]) {
|
||
|
ctx.addIssue({
|
||
|
code: ZodIssueCode.custom,
|
||
|
message: `**${flattenedErrorPath}:** Reference to ${collection} invalid. Collection does not exist or is empty.`
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
const { type, entries } = lookupMap[collection];
|
||
|
const entry = entries[lookupId];
|
||
|
if (!entry) {
|
||
|
ctx.addIssue({
|
||
|
code: ZodIssueCode.custom,
|
||
|
message: `**${flattenedErrorPath}**: Reference to ${collection} invalid. Expected ${Object.keys(
|
||
|
entries
|
||
|
).map((c) => JSON.stringify(c)).join(" | ")}. Received ${JSON.stringify(lookupId)}.`
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
if (type === "content") {
|
||
|
return { slug: lookupId, collection };
|
||
|
}
|
||
|
return { id: lookupId, collection };
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
function isPropagatedAssetsModule(module) {
|
||
|
return typeof module === "object" && module != null && "__astroPropagation" in module;
|
||
|
}
|
||
|
export {
|
||
|
createCollectionToGlobResultMap,
|
||
|
createGetCollection,
|
||
|
createGetDataEntryById,
|
||
|
createGetEntries,
|
||
|
createGetEntry,
|
||
|
createGetEntryBySlug,
|
||
|
createReference
|
||
|
};
|