155 lines
4.2 KiB
TypeScript
155 lines
4.2 KiB
TypeScript
|
import { createDefaultMetadata } from "./nextjs/default-metadata";
|
||
|
import { resolveAsArrayOrUndefined } from "./nextjs/generate/utils";
|
||
|
import {
|
||
|
resolveAlternates,
|
||
|
resolveAppleWebApp,
|
||
|
resolveAppLinks,
|
||
|
resolveRobots,
|
||
|
resolveThemeColor,
|
||
|
resolveVerification,
|
||
|
resolveViewport,
|
||
|
} from "./nextjs/resolvers/resolve-basics";
|
||
|
import { resolveIcons } from "./nextjs/resolvers/resolve-icons";
|
||
|
import {
|
||
|
resolveOpenGraph,
|
||
|
resolveTwitter,
|
||
|
} from "./nextjs/resolvers/resolve-opengraph";
|
||
|
import { resolveTitle } from "./nextjs/resolvers/resolve-title";
|
||
|
import type {
|
||
|
Metadata,
|
||
|
ResolvedMetadata,
|
||
|
} from "./nextjs/types/metadata-interface";
|
||
|
|
||
|
type MetadataAccumulationOptions = {
|
||
|
pathname: string;
|
||
|
};
|
||
|
|
||
|
// Merge the source metadata into the resolved target metadata.
|
||
|
function merge(
|
||
|
target: ResolvedMetadata,
|
||
|
source: Metadata | null,
|
||
|
titleTemplates: {
|
||
|
title?: string | null;
|
||
|
twitter?: string | null;
|
||
|
openGraph?: string | null;
|
||
|
} = {},
|
||
|
) {
|
||
|
const metadataBase = source?.metadataBase || target.metadataBase;
|
||
|
for (const key_ in source) {
|
||
|
const key = key_ as keyof Metadata;
|
||
|
|
||
|
switch (key) {
|
||
|
case "title": {
|
||
|
target.title = resolveTitle(source.title, titleTemplates.title);
|
||
|
break;
|
||
|
}
|
||
|
case "alternates": {
|
||
|
target.alternates = resolveAlternates(source.alternates, metadataBase, {
|
||
|
pathname: (source as any)._pathname ?? "/",
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
case "openGraph": {
|
||
|
target.openGraph = resolveOpenGraph(source.openGraph, metadataBase);
|
||
|
if (target.openGraph) {
|
||
|
target.openGraph.title = resolveTitle(
|
||
|
target.openGraph.title,
|
||
|
titleTemplates.openGraph,
|
||
|
);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case "twitter": {
|
||
|
target.twitter = resolveTwitter(source.twitter, metadataBase);
|
||
|
if (target.twitter) {
|
||
|
target.twitter.title = resolveTitle(
|
||
|
target.twitter.title,
|
||
|
titleTemplates.twitter,
|
||
|
);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case "verification":
|
||
|
target.verification = resolveVerification(source.verification);
|
||
|
break;
|
||
|
case "viewport": {
|
||
|
target.viewport = resolveViewport(source.viewport);
|
||
|
break;
|
||
|
}
|
||
|
case "icons": {
|
||
|
target.icons = resolveIcons(source.icons);
|
||
|
break;
|
||
|
}
|
||
|
case "appleWebApp":
|
||
|
target.appleWebApp = resolveAppleWebApp(source.appleWebApp);
|
||
|
break;
|
||
|
case "appLinks":
|
||
|
target.appLinks = resolveAppLinks(source.appLinks);
|
||
|
break;
|
||
|
case "robots": {
|
||
|
target.robots = resolveRobots(source.robots);
|
||
|
break;
|
||
|
}
|
||
|
case "themeColor": {
|
||
|
target.themeColor = resolveThemeColor(source.themeColor);
|
||
|
break;
|
||
|
}
|
||
|
case "archives":
|
||
|
case "assets":
|
||
|
case "bookmarks":
|
||
|
case "keywords":
|
||
|
case "authors": {
|
||
|
// FIXME: type inferring
|
||
|
// @ts-ignore
|
||
|
target[key] = resolveAsArrayOrUndefined(source[key]) || null;
|
||
|
break;
|
||
|
}
|
||
|
// directly assign fields that fallback to null
|
||
|
case "applicationName":
|
||
|
case "description":
|
||
|
case "generator":
|
||
|
case "creator":
|
||
|
case "publisher":
|
||
|
case "category":
|
||
|
case "classification":
|
||
|
case "referrer":
|
||
|
case "colorScheme":
|
||
|
case "itunes":
|
||
|
case "formatDetection":
|
||
|
case "manifest":
|
||
|
// @ts-ignore TODO: support inferring
|
||
|
target[key] = source[key] || null;
|
||
|
break;
|
||
|
case "other":
|
||
|
target.other = Object.assign({}, target.other, source.other);
|
||
|
break;
|
||
|
case "metadataBase":
|
||
|
target.metadataBase = metadataBase;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
export interface MetadataWithPathname extends Metadata {
|
||
|
/** Set by framework author to the pathname of the page defining this metadata. */
|
||
|
_pathname?: string;
|
||
|
}
|
||
|
|
||
|
export function resolveMetadata(
|
||
|
...metadata: [MetadataWithPathname, ...MetadataWithPathname[]]
|
||
|
) {
|
||
|
const base = createDefaultMetadata();
|
||
|
for (const item of metadata) {
|
||
|
merge(base, item, {
|
||
|
title: base.title?.template,
|
||
|
twitter: base.twitter?.title?.template,
|
||
|
openGraph: base.openGraph?.title?.template,
|
||
|
});
|
||
|
}
|
||
|
return base;
|
||
|
}
|