full site update
This commit is contained in:
351
node_modules/astro/dist/content/runtime.js
generated
vendored
351
node_modules/astro/dist/content/runtime.js
generated
vendored
@@ -1,8 +1,9 @@
|
||||
import { escape } from "html-escaper";
|
||||
import { Traverse } from "neotraverse/modern";
|
||||
import pLimit from "p-limit";
|
||||
import { ZodIssueCode, z } from "zod";
|
||||
import { imageSrcToImportId } from "../assets/utils/resolveImports.js";
|
||||
import { AstroError, AstroErrorData, AstroUserError } from "../core/errors/index.js";
|
||||
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
||||
import { prependForwardSlash } from "../core/path.js";
|
||||
import {
|
||||
createComponent,
|
||||
@@ -14,21 +15,15 @@ import {
|
||||
render as serverRender,
|
||||
unescapeHTML
|
||||
} from "../runtime/server/index.js";
|
||||
import { CONTENT_LAYER_TYPE, IMAGE_IMPORT_PREFIX } from "./consts.js";
|
||||
import { defineCollection as defineCollectionOrig } from "./config.js";
|
||||
import { IMAGE_IMPORT_PREFIX } from "./consts.js";
|
||||
import { globalDataStore } from "./data-store.js";
|
||||
function defineCollection(config) {
|
||||
if ("loader" in config) {
|
||||
if (config.type && config.type !== CONTENT_LAYER_TYPE) {
|
||||
throw new AstroUserError(
|
||||
"Collections that use the Content Layer API must have a `loader` defined and no `type` set.",
|
||||
"Check your collection definitions in `src/content/config.*`.'"
|
||||
);
|
||||
}
|
||||
config.type = CONTENT_LAYER_TYPE;
|
||||
}
|
||||
if (!config.type) config.type = "content";
|
||||
return config;
|
||||
}
|
||||
import {
|
||||
LiveCollectionCacheHintError,
|
||||
LiveCollectionError,
|
||||
LiveCollectionValidationError,
|
||||
LiveEntryNotFoundError
|
||||
} from "./loaders/errors.js";
|
||||
function createCollectionToGlobResultMap({
|
||||
globResult,
|
||||
contentDir
|
||||
@@ -44,13 +39,58 @@ function createCollectionToGlobResultMap({
|
||||
}
|
||||
return collectionToGlobResultMap;
|
||||
}
|
||||
const cacheHintSchema = z.object({
|
||||
tags: z.array(z.string()).optional(),
|
||||
maxAge: z.number().optional(),
|
||||
lastModified: z.date().optional()
|
||||
});
|
||||
async function parseLiveEntry(entry, schema, collection) {
|
||||
try {
|
||||
const parsed = await schema.safeParseAsync(entry.data);
|
||||
if (!parsed.success) {
|
||||
return {
|
||||
error: new LiveCollectionValidationError(collection, entry.id, parsed.error)
|
||||
};
|
||||
}
|
||||
if (entry.cacheHint) {
|
||||
const cacheHint = cacheHintSchema.safeParse(entry.cacheHint);
|
||||
if (!cacheHint.success) {
|
||||
return {
|
||||
error: new LiveCollectionCacheHintError(collection, entry.id, cacheHint.error)
|
||||
};
|
||||
}
|
||||
entry.cacheHint = cacheHint.data;
|
||||
}
|
||||
return {
|
||||
entry: {
|
||||
...entry,
|
||||
data: parsed.data
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: new LiveCollectionError(
|
||||
collection,
|
||||
`Unexpected error parsing entry ${entry.id} in collection ${collection}`,
|
||||
error
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
function createGetCollection({
|
||||
contentCollectionToEntryMap,
|
||||
dataCollectionToEntryMap,
|
||||
getRenderEntryImport,
|
||||
cacheEntriesByCollection
|
||||
cacheEntriesByCollection,
|
||||
liveCollections
|
||||
}) {
|
||||
return async function getCollection(collection, filter) {
|
||||
if (collection in liveCollections) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: `Collection "${collection}" is a live collection. Use getLiveCollection() instead of getCollection().`
|
||||
});
|
||||
}
|
||||
const hasFilter = typeof filter === "function";
|
||||
const store = await globalDataStore.get();
|
||||
let type;
|
||||
@@ -63,11 +103,14 @@ function createGetCollection({
|
||||
const result = [];
|
||||
for (const rawEntry of store.values(collection)) {
|
||||
const data = updateImageReferencesInData(rawEntry.data, rawEntry.filePath, imageAssetMap);
|
||||
const entry = {
|
||||
let entry = {
|
||||
...rawEntry,
|
||||
data,
|
||||
collection
|
||||
};
|
||||
if (entry.legacyId) {
|
||||
entry = emulateLegacyEntry(entry);
|
||||
}
|
||||
if (hasFilter && !filter(entry)) {
|
||||
continue;
|
||||
}
|
||||
@@ -78,7 +121,7 @@ function createGetCollection({
|
||||
console.warn(
|
||||
`The collection ${JSON.stringify(
|
||||
collection
|
||||
)} does not exist or is empty. Ensure a collection directory with this name exists.`
|
||||
)} does not exist or is empty. Please check your content config file for errors.`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
@@ -127,18 +170,25 @@ function createGetCollection({
|
||||
function createGetEntryBySlug({
|
||||
getEntryImport,
|
||||
getRenderEntryImport,
|
||||
collectionNames
|
||||
collectionNames,
|
||||
getEntry
|
||||
}) {
|
||||
return async function getEntryBySlug(collection, slug) {
|
||||
const store = await globalDataStore.get();
|
||||
if (!collectionNames.has(collection)) {
|
||||
if (store.hasCollection(collection)) {
|
||||
const entry2 = await getEntry(collection, slug);
|
||||
if (entry2 && "slug" in entry2) {
|
||||
return entry2;
|
||||
}
|
||||
throw new AstroError({
|
||||
...AstroErrorData.GetEntryDeprecationError,
|
||||
message: AstroErrorData.GetEntryDeprecationError.message(collection, "getEntryBySlug")
|
||||
});
|
||||
}
|
||||
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
||||
console.warn(
|
||||
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const entryImport = await getEntryImport(collection, slug);
|
||||
@@ -162,18 +212,18 @@ function createGetEntryBySlug({
|
||||
}
|
||||
function createGetDataEntryById({
|
||||
getEntryImport,
|
||||
collectionNames
|
||||
collectionNames,
|
||||
getEntry
|
||||
}) {
|
||||
return async function getDataEntryById(collection, id) {
|
||||
const store = await globalDataStore.get();
|
||||
if (!collectionNames.has(collection)) {
|
||||
if (store.hasCollection(collection)) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.GetEntryDeprecationError,
|
||||
message: AstroErrorData.GetEntryDeprecationError.message(collection, "getDataEntryById")
|
||||
});
|
||||
return getEntry(collection, id);
|
||||
}
|
||||
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
||||
console.warn(
|
||||
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const lazyImport = await getEntryImport(collection, id);
|
||||
@@ -186,25 +236,50 @@ function createGetDataEntryById({
|
||||
};
|
||||
};
|
||||
}
|
||||
function emulateLegacyEntry({ legacyId, ...entry }) {
|
||||
const legacyEntry = {
|
||||
...entry,
|
||||
id: legacyId,
|
||||
slug: entry.id
|
||||
};
|
||||
return {
|
||||
...legacyEntry,
|
||||
// Define separately so the render function isn't included in the object passed to `renderEntry()`
|
||||
render: () => renderEntry(legacyEntry)
|
||||
};
|
||||
}
|
||||
function createGetEntry({
|
||||
getEntryImport,
|
||||
getRenderEntryImport,
|
||||
collectionNames
|
||||
collectionNames,
|
||||
liveCollections
|
||||
}) {
|
||||
return async function getEntry(collectionOrLookupObject, _lookupId) {
|
||||
return async function getEntry(collectionOrLookupObject, lookup) {
|
||||
let collection, lookupId;
|
||||
if (typeof collectionOrLookupObject === "string") {
|
||||
collection = collectionOrLookupObject;
|
||||
if (!_lookupId)
|
||||
if (!lookup)
|
||||
throw new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: "`getEntry()` requires an entry identifier as the second argument."
|
||||
});
|
||||
lookupId = _lookupId;
|
||||
lookupId = lookup;
|
||||
} else {
|
||||
collection = collectionOrLookupObject.collection;
|
||||
lookupId = "id" in collectionOrLookupObject ? collectionOrLookupObject.id : collectionOrLookupObject.slug;
|
||||
}
|
||||
if (collection in liveCollections) {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: `Collection "${collection}" is a live collection. Use getLiveEntry() instead of getEntry().`
|
||||
});
|
||||
}
|
||||
if (typeof lookupId === "object") {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.UnknownContentCollectionError,
|
||||
message: `The entry identifier must be a string. Received object.`
|
||||
});
|
||||
}
|
||||
const store = await globalDataStore.get();
|
||||
if (store.hasCollection(collection)) {
|
||||
const entry2 = store.get(collection, lookupId);
|
||||
@@ -214,13 +289,18 @@ function createGetEntry({
|
||||
}
|
||||
const { default: imageAssetMap } = await import("astro:asset-imports");
|
||||
entry2.data = updateImageReferencesInData(entry2.data, entry2.filePath, imageAssetMap);
|
||||
if (entry2.legacyId) {
|
||||
return emulateLegacyEntry({ ...entry2, collection });
|
||||
}
|
||||
return {
|
||||
...entry2,
|
||||
collection
|
||||
};
|
||||
}
|
||||
if (!collectionNames.has(collection)) {
|
||||
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
||||
console.warn(
|
||||
`The collection ${JSON.stringify(collection)} does not exist. Please ensure it is defined in your content config.`
|
||||
);
|
||||
return void 0;
|
||||
}
|
||||
const entryImport = await getEntryImport(collection, lookupId);
|
||||
@@ -256,6 +336,149 @@ function createGetEntries(getEntry) {
|
||||
return Promise.all(entries.map((e) => getEntry(e)));
|
||||
};
|
||||
}
|
||||
function createGetLiveCollection({
|
||||
liveCollections
|
||||
}) {
|
||||
return async function getLiveCollection(collection, filter) {
|
||||
if (!(collection in liveCollections)) {
|
||||
return {
|
||||
error: new LiveCollectionError(
|
||||
collection,
|
||||
`Collection "${collection}" is not a live collection. Use getCollection() instead of getLiveCollection() to load regular content collections.`
|
||||
)
|
||||
};
|
||||
}
|
||||
try {
|
||||
const context = {
|
||||
filter
|
||||
};
|
||||
const response = await liveCollections[collection].loader?.loadCollection?.(context);
|
||||
if (response && "error" in response) {
|
||||
return { error: response.error };
|
||||
}
|
||||
const { schema } = liveCollections[collection];
|
||||
let processedEntries = response.entries;
|
||||
if (schema) {
|
||||
const entryResults = await Promise.all(
|
||||
response.entries.map((entry) => parseLiveEntry(entry, schema, collection))
|
||||
);
|
||||
for (const result of entryResults) {
|
||||
if (result.error) {
|
||||
return { error: result.error };
|
||||
}
|
||||
}
|
||||
processedEntries = entryResults.map((result) => result.entry);
|
||||
}
|
||||
let cacheHint = response.cacheHint;
|
||||
if (cacheHint) {
|
||||
const cacheHintResult = cacheHintSchema.safeParse(cacheHint);
|
||||
if (!cacheHintResult.success) {
|
||||
return {
|
||||
error: new LiveCollectionCacheHintError(collection, void 0, cacheHintResult.error)
|
||||
};
|
||||
}
|
||||
cacheHint = cacheHintResult.data;
|
||||
}
|
||||
if (processedEntries.length > 0) {
|
||||
const entryTags = /* @__PURE__ */ new Set();
|
||||
let minMaxAge;
|
||||
let latestModified;
|
||||
for (const entry of processedEntries) {
|
||||
if (entry.cacheHint) {
|
||||
if (entry.cacheHint.tags) {
|
||||
entry.cacheHint.tags.forEach((tag) => entryTags.add(tag));
|
||||
}
|
||||
if (typeof entry.cacheHint.maxAge === "number") {
|
||||
if (minMaxAge === void 0 || entry.cacheHint.maxAge < minMaxAge) {
|
||||
minMaxAge = entry.cacheHint.maxAge;
|
||||
}
|
||||
}
|
||||
if (entry.cacheHint.lastModified instanceof Date) {
|
||||
if (latestModified === void 0 || entry.cacheHint.lastModified > latestModified) {
|
||||
latestModified = entry.cacheHint.lastModified;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entryTags.size > 0 || minMaxAge !== void 0 || latestModified || cacheHint) {
|
||||
const mergedCacheHint = {};
|
||||
if (cacheHint?.tags || entryTags.size > 0) {
|
||||
mergedCacheHint.tags = [.../* @__PURE__ */ new Set([...cacheHint?.tags || [], ...entryTags])];
|
||||
}
|
||||
if (cacheHint?.maxAge !== void 0 || minMaxAge !== void 0) {
|
||||
mergedCacheHint.maxAge = cacheHint?.maxAge !== void 0 && minMaxAge !== void 0 ? Math.min(cacheHint.maxAge, minMaxAge) : cacheHint?.maxAge ?? minMaxAge;
|
||||
}
|
||||
if (cacheHint?.lastModified && latestModified) {
|
||||
mergedCacheHint.lastModified = cacheHint.lastModified > latestModified ? cacheHint.lastModified : latestModified;
|
||||
} else if (cacheHint?.lastModified || latestModified) {
|
||||
mergedCacheHint.lastModified = cacheHint?.lastModified ?? latestModified;
|
||||
}
|
||||
cacheHint = mergedCacheHint;
|
||||
}
|
||||
}
|
||||
return {
|
||||
entries: processedEntries,
|
||||
cacheHint
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: new LiveCollectionError(
|
||||
collection,
|
||||
`Unexpected error loading collection ${collection}${error instanceof Error ? `: ${error.message}` : ""}`,
|
||||
error
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
function createGetLiveEntry({
|
||||
liveCollections
|
||||
}) {
|
||||
return async function getLiveEntry(collection, lookup) {
|
||||
if (!(collection in liveCollections)) {
|
||||
return {
|
||||
error: new LiveCollectionError(
|
||||
collection,
|
||||
`Collection "${collection}" is not a live collection. Use getCollection() instead of getLiveEntry() to load regular content collections.`
|
||||
)
|
||||
};
|
||||
}
|
||||
try {
|
||||
const lookupObject = {
|
||||
filter: typeof lookup === "string" ? { id: lookup } : lookup
|
||||
};
|
||||
let entry = await liveCollections[collection].loader?.loadEntry?.(lookupObject);
|
||||
if (entry && "error" in entry) {
|
||||
return { error: entry.error };
|
||||
}
|
||||
if (!entry) {
|
||||
return {
|
||||
error: new LiveEntryNotFoundError(collection, lookup)
|
||||
};
|
||||
}
|
||||
const { schema } = liveCollections[collection];
|
||||
if (schema) {
|
||||
const result = await parseLiveEntry(entry, schema, collection);
|
||||
if (result.error) {
|
||||
return { error: result.error };
|
||||
}
|
||||
entry = result.entry;
|
||||
}
|
||||
return {
|
||||
entry,
|
||||
cacheHint: entry.cacheHint
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
error: new LiveCollectionError(
|
||||
collection,
|
||||
`Unexpected error loading entry ${collection} \u2192 ${typeof lookup === "string" ? lookup : JSON.stringify(lookup)}`,
|
||||
error
|
||||
)
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
const CONTENT_LAYER_IMAGE_REGEX = /__ASTRO_IMAGE_="([^"]+)"/g;
|
||||
async function updateImageReferencesInBody(html, fileName) {
|
||||
const { default: imageAssetMap } = await import("astro:asset-imports");
|
||||
@@ -264,12 +487,17 @@ async function updateImageReferencesInBody(html, fileName) {
|
||||
for (const [_full, imagePath] of html.matchAll(CONTENT_LAYER_IMAGE_REGEX)) {
|
||||
try {
|
||||
const decodedImagePath = JSON.parse(imagePath.replaceAll(""", '"'));
|
||||
const id = imageSrcToImportId(decodedImagePath.src, fileName);
|
||||
const imported = imageAssetMap.get(id);
|
||||
if (!id || imageObjects.has(id) || !imported) {
|
||||
continue;
|
||||
let image;
|
||||
if (URL.canParse(decodedImagePath.src)) {
|
||||
image = await getImage(decodedImagePath);
|
||||
} else {
|
||||
const id = imageSrcToImportId(decodedImagePath.src, fileName);
|
||||
const imported = imageAssetMap.get(id);
|
||||
if (!id || imageObjects.has(id) || !imported) {
|
||||
continue;
|
||||
}
|
||||
image = await getImage({ ...decodedImagePath, src: imported });
|
||||
}
|
||||
const image = await getImage({ ...decodedImagePath, src: imported });
|
||||
imageObjects.set(imagePath, image);
|
||||
} catch {
|
||||
throw new Error(`Failed to parse image reference: ${imagePath}`);
|
||||
@@ -284,8 +512,10 @@ async function updateImageReferencesInBody(html, fileName) {
|
||||
return Object.entries({
|
||||
...attributes,
|
||||
src: image.src,
|
||||
srcset: image.srcSet.attribute
|
||||
}).map(([key, value]) => value ? `${key}=${JSON.stringify(String(value))}` : "").join(" ");
|
||||
srcset: image.srcSet.attribute,
|
||||
// This attribute is used by the toolbar audit
|
||||
...import.meta.env.DEV ? { "data-image-component": "true" } : {}
|
||||
}).map(([key, value]) => value ? `${key}="${escape(value)}"` : "").join(" ");
|
||||
});
|
||||
}
|
||||
function updateImageReferencesInData(data, fileName, imageAssetMap) {
|
||||
@@ -310,7 +540,7 @@ async function renderEntry(entry) {
|
||||
if (!entry) {
|
||||
throw new AstroError(AstroErrorData.RenderUndefinedEntryError);
|
||||
}
|
||||
if ("render" in entry) {
|
||||
if ("render" in entry && !("legacyId" in entry)) {
|
||||
return entry.render();
|
||||
}
|
||||
if (entry.deferredRender) {
|
||||
@@ -422,10 +652,8 @@ function createReference({ lookupMap }) {
|
||||
collection: z.string()
|
||||
})
|
||||
]).transform(
|
||||
async (lookup, ctx) => {
|
||||
(lookup, ctx) => {
|
||||
const flattenedErrorPath = ctx.path.join(".");
|
||||
const store = await globalDataStore.get();
|
||||
const collectionIsInStore = store.hasCollection(collection);
|
||||
if (typeof lookup === "object") {
|
||||
if (lookup.collection !== collection) {
|
||||
ctx.addIssue({
|
||||
@@ -436,18 +664,7 @@ function createReference({ lookupMap }) {
|
||||
}
|
||||
return lookup;
|
||||
}
|
||||
if (collectionIsInStore) {
|
||||
const entry2 = store.get(collection, lookup);
|
||||
if (!entry2) {
|
||||
ctx.addIssue({
|
||||
code: ZodIssueCode.custom,
|
||||
message: `**${flattenedErrorPath}**: Reference to ${collection} invalid. Entry ${lookup} does not exist.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
return { id: lookup, collection };
|
||||
}
|
||||
if (!lookupMap[collection] && store.collections().size <= 1) {
|
||||
if (!lookupMap[collection]) {
|
||||
return { id: lookup, collection };
|
||||
}
|
||||
const { type, entries } = lookupMap[collection];
|
||||
@@ -472,14 +689,40 @@ function createReference({ lookupMap }) {
|
||||
function isPropagatedAssetsModule(module) {
|
||||
return typeof module === "object" && module != null && "__astroPropagation" in module;
|
||||
}
|
||||
function defineCollection(config) {
|
||||
if (config.type === "live") {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.LiveContentConfigError,
|
||||
message: AstroErrorData.LiveContentConfigError.message(
|
||||
"Collections with type `live` must be defined in a `src/live.config.ts` file."
|
||||
)
|
||||
});
|
||||
}
|
||||
return defineCollectionOrig(config);
|
||||
}
|
||||
function defineLiveCollection() {
|
||||
throw new AstroError({
|
||||
...AstroErrorData.LiveContentConfigError,
|
||||
message: AstroErrorData.LiveContentConfigError.message(
|
||||
"Live collections must be defined in a `src/live.config.ts` file."
|
||||
)
|
||||
});
|
||||
}
|
||||
export {
|
||||
LiveCollectionCacheHintError,
|
||||
LiveCollectionError,
|
||||
LiveCollectionValidationError,
|
||||
LiveEntryNotFoundError,
|
||||
createCollectionToGlobResultMap,
|
||||
createGetCollection,
|
||||
createGetDataEntryById,
|
||||
createGetEntries,
|
||||
createGetEntry,
|
||||
createGetEntryBySlug,
|
||||
createGetLiveCollection,
|
||||
createGetLiveEntry,
|
||||
createReference,
|
||||
defineCollection,
|
||||
defineLiveCollection,
|
||||
renderEntry
|
||||
};
|
||||
|
Reference in New Issue
Block a user