UNPKG

next

Version:

The React Framework

467 lines (466 loc) • 19.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { convertUrlsToStrings: null, createSelectedMetadata: null, getDefinedMetadata: null, getDefinedViewport: null, isFavicon: null, mergeMetadata: null, mergeViewport: null, postProcessMetadata: null, resolveStaticMetadata: null }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { convertUrlsToStrings: function() { return convertUrlsToStrings; }, createSelectedMetadata: function() { return createSelectedMetadata; }, getDefinedMetadata: function() { return getDefinedMetadata; }, getDefinedViewport: function() { return getDefinedViewport; }, isFavicon: function() { return isFavicon; }, mergeMetadata: function() { return mergeMetadata; }, mergeViewport: function() { return mergeViewport; }, postProcessMetadata: function() { return postProcessMetadata; }, resolveStaticMetadata: function() { return resolveStaticMetadata; } }); require("server-only"); const _resolveopengraph = require("./resolvers/resolve-opengraph"); const _resolvetitle = require("./resolvers/resolve-title"); const _utils = require("./generate/utils"); const _resolvebasics = require("./resolvers/resolve-basics"); const _resolveicons = require("./resolvers/resolve-icons"); const _tracer = require("../../server/lib/trace/tracer"); const _constants = require("../../server/lib/trace/constants"); const _clientandserverreferences = require("../client-and-server-references"); function isFavicon(icon) { if (!icon) { return false; } // turbopack appends a hash to all images return (icon.url === '/favicon.ico' || icon.url.toString().startsWith('/favicon.ico?')) && icon.type === 'image/x-icon'; } function convertUrlsToStrings(input) { if (input instanceof URL) { return input.toString(); } else if (Array.isArray(input)) { return input.map((item)=>convertUrlsToStrings(item)); } else if (input && typeof input === 'object') { const result = {}; for (const [key, value] of Object.entries(input)){ result[key] = convertUrlsToStrings(value); } return result; } return input; } function normalizeMetadataBase(metadataBase) { if (typeof metadataBase === 'string') { try { metadataBase = new URL(metadataBase); } catch { throw new Error(`metadataBase is not a valid URL: ${metadataBase}`); } } return metadataBase; } async function mergeStaticMetadata(metadataBase, source, target, staticFilesMetadata, metadataContext, titleTemplates, leafSegmentStaticIcons, pathname) { var _source_twitter, _source_openGraph; if (!staticFilesMetadata) return target; const { icon, apple, openGraph, twitter, manifest } = staticFilesMetadata; // Keep updating the static icons in the most leaf node if (icon) { leafSegmentStaticIcons.icon = icon; } if (apple) { leafSegmentStaticIcons.apple = apple; } // file based metadata is specified and current level metadata twitter.images is not specified if (twitter && !(source == null ? void 0 : (_source_twitter = source.twitter) == null ? void 0 : _source_twitter.hasOwnProperty('images'))) { const resolvedTwitter = (0, _resolveopengraph.resolveTwitter)({ ...target.twitter, images: twitter }, metadataBase, { ...metadataContext, isStaticMetadataRouteFile: true }, titleTemplates.twitter); target.twitter = convertUrlsToStrings(resolvedTwitter); } // file based metadata is specified and current level metadata openGraph.images is not specified if (openGraph && !(source == null ? void 0 : (_source_openGraph = source.openGraph) == null ? void 0 : _source_openGraph.hasOwnProperty('images'))) { const resolvedOpenGraph = await (0, _resolveopengraph.resolveOpenGraph)({ ...target.openGraph, images: openGraph }, metadataBase, pathname, { ...metadataContext, isStaticMetadataRouteFile: true }, titleTemplates.openGraph); target.openGraph = convertUrlsToStrings(resolvedOpenGraph); } if (manifest) { target.manifest = manifest; } return target; } async function mergeMetadata(route, pathname, { metadata, resolvedMetadata, staticFilesMetadata, titleTemplates, metadataContext, buildState, leafSegmentStaticIcons, cloneResolvedMetadata = true }) { const newResolvedMetadata = cloneResolvedMetadata ? structuredClone(resolvedMetadata) : resolvedMetadata; const metadataBase = normalizeMetadataBase((metadata == null ? void 0 : metadata.metadataBase) !== undefined ? metadata.metadataBase : resolvedMetadata.metadataBase); for(const key_ in metadata){ const key = key_; switch(key){ case 'title': { newResolvedMetadata.title = (0, _resolvetitle.resolveTitle)(metadata.title, titleTemplates.title); break; } case 'alternates': { newResolvedMetadata.alternates = convertUrlsToStrings(await (0, _resolvebasics.resolveAlternates)(metadata.alternates, metadataBase, pathname, metadataContext)); break; } case 'openGraph': { newResolvedMetadata.openGraph = convertUrlsToStrings(await (0, _resolveopengraph.resolveOpenGraph)(metadata.openGraph, metadataBase, pathname, metadataContext, titleTemplates.openGraph)); break; } case 'twitter': { newResolvedMetadata.twitter = convertUrlsToStrings((0, _resolveopengraph.resolveTwitter)(metadata.twitter, metadataBase, metadataContext, titleTemplates.twitter)); break; } case 'facebook': newResolvedMetadata.facebook = (0, _resolvebasics.resolveFacebook)(metadata.facebook); break; case 'verification': newResolvedMetadata.verification = (0, _resolvebasics.resolveVerification)(metadata.verification); break; case 'icons': { newResolvedMetadata.icons = convertUrlsToStrings((0, _resolveicons.resolveIcons)(metadata.icons)); break; } case 'appleWebApp': newResolvedMetadata.appleWebApp = (0, _resolvebasics.resolveAppleWebApp)(metadata.appleWebApp); break; case 'appLinks': newResolvedMetadata.appLinks = convertUrlsToStrings((0, _resolvebasics.resolveAppLinks)(metadata.appLinks)); break; case 'robots': { newResolvedMetadata.robots = (0, _resolvebasics.resolveRobots)(metadata.robots); break; } case 'archives': case 'assets': case 'bookmarks': case 'keywords': { newResolvedMetadata[key] = (0, _utils.resolveAsArrayOrUndefined)(metadata[key]); break; } case 'authors': { newResolvedMetadata[key] = convertUrlsToStrings((0, _utils.resolveAsArrayOrUndefined)(metadata.authors)); break; } case 'itunes': { newResolvedMetadata[key] = await (0, _resolvebasics.resolveItunes)(metadata.itunes, metadataBase, pathname, metadataContext); break; } case 'pagination': { newResolvedMetadata.pagination = await (0, _resolvebasics.resolvePagination)(metadata.pagination, metadataBase, pathname, metadataContext); break; } // directly assign fields that fallback to null case 'abstract': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'applicationName': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'description': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'generator': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'creator': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'publisher': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'category': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'classification': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'referrer': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'formatDetection': newResolvedMetadata[key] = metadata[key] ?? null; break; case 'manifest': newResolvedMetadata[key] = convertUrlsToStrings(metadata[key]) ?? null; break; case 'pinterest': newResolvedMetadata[key] = convertUrlsToStrings(metadata[key]) ?? null; break; case 'other': newResolvedMetadata.other = Object.assign({}, newResolvedMetadata.other, metadata.other); if (metadata.other) { if ('apple-touch-fullscreen' in metadata.other) { buildState.warnings.add(`Use appleWebApp instead\nRead more: https://nextjs.org/docs/app/api-reference/functions/generate-metadata`); } if ('apple-touch-icon-precomposed' in metadata.other) { buildState.warnings.add(`Use icons.apple instead\nRead more: https://nextjs.org/docs/app/api-reference/functions/generate-metadata`); } } break; case 'metadataBase': newResolvedMetadata.metadataBase = metadataBase ? metadataBase.toString() : null; break; case 'apple-touch-fullscreen': { buildState.warnings.add(`Use appleWebApp instead\nRead more: https://nextjs.org/docs/app/api-reference/functions/generate-metadata`); break; } case 'apple-touch-icon-precomposed': { buildState.warnings.add(`Use icons.apple instead\nRead more: https://nextjs.org/docs/app/api-reference/functions/generate-metadata`); break; } case 'themeColor': case 'colorScheme': case 'viewport': if (metadata[key] != null) { buildState.warnings.add(`Unsupported metadata ${key} is configured in metadata export in ${route}. Please move it to viewport export instead.\nRead more: https://nextjs.org/docs/app/api-reference/functions/generate-viewport`); } break; default: { key; } } } return mergeStaticMetadata(metadataBase, metadata, newResolvedMetadata, staticFilesMetadata, metadataContext, titleTemplates, leafSegmentStaticIcons, pathname); } function mergeViewport({ resolvedViewport, viewport, cloneResolvedViewport = true }) { const newResolvedViewport = cloneResolvedViewport ? structuredClone(resolvedViewport) : resolvedViewport; if (viewport) { for(const key_ in viewport){ const key = key_; switch(key){ case 'themeColor': { newResolvedViewport.themeColor = (0, _resolvebasics.resolveThemeColor)(viewport.themeColor); break; } case 'colorScheme': newResolvedViewport.colorScheme = viewport.colorScheme || null; break; case 'width': case 'height': case 'initialScale': case 'minimumScale': case 'maximumScale': case 'userScalable': case 'viewportFit': case 'interactiveWidget': // always override the target with the source // @ts-ignore viewport properties newResolvedViewport[key] = viewport[key]; break; default: key; } } } return newResolvedViewport; } function getDefinedViewport(mod, props, tracingProps) { if (typeof mod.generateViewport === 'function') { const { route } = tracingProps; const segmentProps = createSegmentProps(mod.generateViewport, props); return Object.assign((parent)=>(0, _tracer.getTracer)().trace(_constants.ResolveMetadataSpan.generateViewport, { spanName: `generateViewport ${route}`, attributes: { 'next.page': route } }, ()=>mod.generateViewport(segmentProps, parent)), { $$original: mod.generateViewport }); } return mod.viewport || null; } function getDefinedMetadata(mod, props, tracingProps) { if (typeof mod.generateMetadata === 'function') { const { route } = tracingProps; const segmentProps = createSegmentProps(mod.generateMetadata, props); return Object.assign((parent)=>(0, _tracer.getTracer)().trace(_constants.ResolveMetadataSpan.generateMetadata, { spanName: `generateMetadata ${route}`, attributes: { 'next.page': route } }, ()=>mod.generateMetadata(segmentProps, parent)), { $$original: mod.generateMetadata }); } return mod.metadata || null; } /** * If `fn` is a `'use cache'` function, we add special markers to the props, * that the cache wrapper reads and removes, before passing the props to the * user function. */ function createSegmentProps(fn, props) { return (0, _clientandserverreferences.isUseCacheFunction)(fn) ? 'searchParams' in props ? { ...props, $$isPage: true } : { ...props, $$isLayout: true } : props; } async function collectStaticImagesFiles(metadata, props, type) { if (!(metadata == null ? void 0 : metadata[type])) return undefined; const iconPromises = metadata[type].map(async (imageModule)=>await imageModule(props)); return (iconPromises == null ? void 0 : iconPromises.length) > 0 ? (await Promise.all(iconPromises)).flat() : undefined; } async function resolveStaticMetadata(modules, props) { const { metadata } = modules; if (!metadata) return null; const [icon, apple, openGraph, twitter] = await Promise.all([ collectStaticImagesFiles(metadata, props, 'icon'), collectStaticImagesFiles(metadata, props, 'apple'), collectStaticImagesFiles(metadata, props, 'openGraph'), collectStaticImagesFiles(metadata, props, 'twitter') ]); const staticMetadata = { icon, apple, openGraph, twitter, manifest: metadata.manifest }; return staticMetadata; } const isTitleTruthy = (title)=>!!(title == null ? void 0 : title.absolute); const hasTitle = (metadata)=>isTitleTruthy(metadata == null ? void 0 : metadata.title); function inheritFromMetadata(target, metadata) { if (target) { if (!hasTitle(target) && hasTitle(metadata)) { target.title = metadata.title; } if (!target.description && metadata.description) { target.description = metadata.description; } } } // eslint-disable-next-line @typescript-eslint/no-unused-vars const commonOgKeys = [ 'title', 'description', 'images' ]; function postProcessMetadata(metadata, favicon, titleTemplates, metadataContext) { const { openGraph, twitter } = metadata; if (openGraph) { // If there's openGraph information but not configured in twitter, // inherit them from openGraph metadata. let autoFillProps = {}; const hasTwTitle = hasTitle(twitter); const hasTwDescription = twitter == null ? void 0 : twitter.description; const hasTwImages = Boolean((twitter == null ? void 0 : twitter.hasOwnProperty('images')) && twitter.images); if (!hasTwTitle) { if (isTitleTruthy(openGraph.title)) { autoFillProps.title = openGraph.title; } else if (metadata.title && isTitleTruthy(metadata.title)) { autoFillProps.title = metadata.title; } } if (!hasTwDescription) autoFillProps.description = openGraph.description || metadata.description || undefined; if (!hasTwImages) autoFillProps.images = openGraph.images; if (Object.keys(autoFillProps).length > 0) { const partialTwitter = (0, _resolveopengraph.resolveTwitter)(autoFillProps, normalizeMetadataBase(metadata.metadataBase), metadataContext, titleTemplates.twitter); if (metadata.twitter) { metadata.twitter = Object.assign({}, metadata.twitter, { ...!hasTwTitle && { title: partialTwitter == null ? void 0 : partialTwitter.title }, ...!hasTwDescription && { description: partialTwitter == null ? void 0 : partialTwitter.description }, ...!hasTwImages && { images: partialTwitter == null ? void 0 : partialTwitter.images } }); } else { metadata.twitter = convertUrlsToStrings(partialTwitter); } } } // If there's no title and description configured in openGraph or twitter, // use the title and description from metadata. inheritFromMetadata(openGraph, metadata); inheritFromMetadata(twitter, metadata); if (favicon) { if (!metadata.icons) { metadata.icons = { icon: [], apple: [] }; } metadata.icons.icon.unshift(favicon); } return metadata; } function createSelectedMetadata(metadata) { const { metadataBase, title, openGraph, twitter, themeColor, colorScheme, viewport, ...metadataTagFields } = metadata; // These fields are only used while resolving metadata, or are rendered by // the separate viewport pipeline. void metadataBase; void themeColor; void colorScheme; void viewport; return { ...metadataTagFields, title: (title == null ? void 0 : title.absolute) || null, openGraph: openGraph ? { ...openGraph, title: openGraph.title.absolute } : null, twitter: twitter ? { ...twitter, title: twitter.title.absolute } : null }; } //# sourceMappingURL=metadata-resolution-primitives.js.map