initial commit
This commit is contained in:
764
node_modules/unhead/dist/index.cjs
generated
vendored
Normal file
764
node_modules/unhead/dist/index.cjs
generated
vendored
Normal file
@@ -0,0 +1,764 @@
|
||||
'use strict';
|
||||
|
||||
const hookable = require('hookable');
|
||||
const dom = require('@unhead/dom');
|
||||
|
||||
const ValidHeadTags = [
|
||||
"title",
|
||||
"titleTemplate",
|
||||
"base",
|
||||
"htmlAttrs",
|
||||
"bodyAttrs",
|
||||
"meta",
|
||||
"link",
|
||||
"style",
|
||||
"script",
|
||||
"noscript"
|
||||
];
|
||||
const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
|
||||
|
||||
async function normaliseTag(tagName, input) {
|
||||
const tag = { tag: tagName, props: {} };
|
||||
if (tagName === "title" || tagName === "titleTemplate") {
|
||||
tag.children = input instanceof Promise ? await input : input;
|
||||
return tag;
|
||||
}
|
||||
tag.props = await normaliseProps({ ...input });
|
||||
["children", "innerHtml", "innerHTML"].forEach((key) => {
|
||||
if (typeof tag.props[key] !== "undefined") {
|
||||
tag.children = tag.props[key];
|
||||
if (typeof tag.children === "object")
|
||||
tag.children = JSON.stringify(tag.children);
|
||||
delete tag.props[key];
|
||||
}
|
||||
});
|
||||
Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
|
||||
tag[k] = tag.props[k];
|
||||
delete tag.props[k];
|
||||
});
|
||||
if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
|
||||
tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
|
||||
}
|
||||
if (Array.isArray(tag.props.class))
|
||||
tag.props.class = tag.props.class.join(" ");
|
||||
if (tag.props.content && Array.isArray(tag.props.content)) {
|
||||
return tag.props.content.map((v, i) => {
|
||||
const newTag = { ...tag, props: { ...tag.props } };
|
||||
newTag.props.content = v;
|
||||
newTag.key = `${tag.props.name || tag.props.property}:${i}`;
|
||||
return newTag;
|
||||
});
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
async function normaliseProps(props) {
|
||||
for (const k of Object.keys(props)) {
|
||||
if (props[k] instanceof Promise) {
|
||||
props[k] = await props[k];
|
||||
}
|
||||
if (String(props[k]) === "true") {
|
||||
props[k] = "";
|
||||
} else if (String(props[k]) === "false") {
|
||||
delete props[k];
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
function unpackToArray(input, options) {
|
||||
const unpacked = [];
|
||||
const kFn = options.resolveKeyData || ((ctx) => ctx.key);
|
||||
const vFn = options.resolveValueData || ((ctx) => ctx.value);
|
||||
for (const [k, v] of Object.entries(input)) {
|
||||
unpacked.push(...(Array.isArray(v) ? v : [v]).map((i) => {
|
||||
const ctx = { key: k, value: i };
|
||||
const val = vFn(ctx);
|
||||
if (typeof val === "object")
|
||||
return unpackToArray(val, options);
|
||||
if (Array.isArray(val))
|
||||
return val;
|
||||
return {
|
||||
[typeof options.key === "function" ? options.key(ctx) : options.key]: kFn(ctx),
|
||||
[typeof options.value === "function" ? options.value(ctx) : options.value]: val
|
||||
};
|
||||
}).flat());
|
||||
}
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
function unpackToString(value, options) {
|
||||
return Object.entries(value).map(([key, value2]) => {
|
||||
if (typeof value2 === "object")
|
||||
value2 = unpackToString(value2, options);
|
||||
if (options.resolve) {
|
||||
const resolved = options.resolve({ key, value: value2 });
|
||||
if (resolved)
|
||||
return resolved;
|
||||
}
|
||||
if (typeof value2 === "number")
|
||||
value2 = value2.toString();
|
||||
if (typeof value2 === "string" && options.wrapValue) {
|
||||
value2 = value2.replace(new RegExp(options.wrapValue, "g"), `\\${options.wrapValue}`);
|
||||
value2 = `${options.wrapValue}${value2}${options.wrapValue}`;
|
||||
}
|
||||
return `${key}${options.keyValueSeparator || ""}${value2}`;
|
||||
}).join(options.entrySeparator || "");
|
||||
}
|
||||
|
||||
const MetaPackingSchema = {
|
||||
robots: {
|
||||
unpack: {
|
||||
keyValueSeparator: ":"
|
||||
}
|
||||
},
|
||||
contentSecurityPolicy: {
|
||||
unpack: {
|
||||
keyValueSeparator: " ",
|
||||
entrySeparator: "; "
|
||||
},
|
||||
metaKey: "http-equiv"
|
||||
},
|
||||
fbAppId: {
|
||||
keyValue: "fb:app_id",
|
||||
metaKey: "property"
|
||||
},
|
||||
msapplicationTileImage: {
|
||||
keyValue: "msapplication-TileImage"
|
||||
},
|
||||
msapplicationTileColor: {
|
||||
keyValue: "msapplication-TileColor"
|
||||
},
|
||||
msapplicationConfig: {
|
||||
keyValue: "msapplication-Config"
|
||||
},
|
||||
charset: {
|
||||
metaKey: "charset"
|
||||
},
|
||||
contentType: {
|
||||
metaKey: "http-equiv"
|
||||
},
|
||||
defaultStyle: {
|
||||
metaKey: "http-equiv"
|
||||
},
|
||||
xUaCompatible: {
|
||||
metaKey: "http-equiv"
|
||||
},
|
||||
refresh: {
|
||||
metaKey: "http-equiv"
|
||||
}
|
||||
};
|
||||
function resolveMetaKeyType(key) {
|
||||
return PropertyPrefixKeys.test(key) ? "property" : MetaPackingSchema[key]?.metaKey || "name";
|
||||
}
|
||||
|
||||
function unpackMeta(input) {
|
||||
const meta = unpackToArray(input, {
|
||||
key({ key }) {
|
||||
return resolveMetaKeyType(key);
|
||||
},
|
||||
value({ key }) {
|
||||
return key === "charset" ? "charset" : "content";
|
||||
},
|
||||
resolveKeyData({ key }) {
|
||||
return MetaPackingSchema[key]?.keyValue || fixKeyCase(key);
|
||||
},
|
||||
resolveValueData({ value, key }) {
|
||||
if (value === null)
|
||||
return "_null";
|
||||
if (typeof value === "object") {
|
||||
const definition = MetaPackingSchema[key];
|
||||
if (key === "refresh")
|
||||
return `${value.seconds};url=${value.url}`;
|
||||
return unpackToString(
|
||||
changeKeyCasingDeep(value),
|
||||
{
|
||||
entrySeparator: ", ",
|
||||
keyValueSeparator: "=",
|
||||
resolve({ value: value2, key: key2 }) {
|
||||
if (value2 === null)
|
||||
return "";
|
||||
if (typeof value2 === "boolean")
|
||||
return `${key2}`;
|
||||
},
|
||||
...definition?.unpack
|
||||
}
|
||||
);
|
||||
}
|
||||
return typeof value === "number" ? value.toString() : value;
|
||||
}
|
||||
});
|
||||
return meta.filter((v) => typeof v.content === "undefined" || v.content !== "_null");
|
||||
}
|
||||
|
||||
const PropertyPrefixKeys = /^(og|twitter|fb)/;
|
||||
function fixKeyCase(key) {
|
||||
key = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
||||
if (PropertyPrefixKeys.test(key)) {
|
||||
key = key.replace("secure-url", "secure_url").replace(/-/g, ":");
|
||||
}
|
||||
return key;
|
||||
}
|
||||
function changeKeyCasingDeep(input) {
|
||||
if (Array.isArray(input)) {
|
||||
return input.map((entry) => changeKeyCasingDeep(entry));
|
||||
}
|
||||
if (typeof input !== "object" || Array.isArray(input))
|
||||
return input;
|
||||
const output = {};
|
||||
for (const [key, value] of Object.entries(input))
|
||||
output[fixKeyCase(key)] = changeKeyCasingDeep(value);
|
||||
return output;
|
||||
}
|
||||
|
||||
const tagWeight = (tag) => {
|
||||
if (typeof tag.tagPriority === "number")
|
||||
return tag.tagPriority;
|
||||
switch (tag.tagPriority) {
|
||||
case "critical":
|
||||
return 2;
|
||||
case "high":
|
||||
return 9;
|
||||
case "low":
|
||||
return 12;
|
||||
}
|
||||
switch (tag.tag) {
|
||||
case "base":
|
||||
return -1;
|
||||
case "title":
|
||||
return 1;
|
||||
case "meta":
|
||||
if (tag.props.charset)
|
||||
return -2;
|
||||
if (tag.props["http-equiv"] === "content-security-policy")
|
||||
return 0;
|
||||
return 10;
|
||||
default:
|
||||
return 10;
|
||||
}
|
||||
};
|
||||
const sortTags = (aTag, bTag) => {
|
||||
return tagWeight(aTag) - tagWeight(bTag);
|
||||
};
|
||||
|
||||
const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
|
||||
function tagDedupeKey(tag, fn) {
|
||||
const { props, tag: tagName } = tag;
|
||||
if (UniqueTags.includes(tagName))
|
||||
return tagName;
|
||||
if (tagName === "link" && props.rel === "canonical")
|
||||
return "canonical";
|
||||
if (props.charset)
|
||||
return "charset";
|
||||
const name = ["id"];
|
||||
if (tagName === "meta")
|
||||
name.push(...["name", "property", "http-equiv"]);
|
||||
for (const n of name) {
|
||||
if (typeof props[n] !== "undefined") {
|
||||
const val = String(props[n]);
|
||||
if (fn && !fn(val))
|
||||
return false;
|
||||
return `${tagName}:${n}:${val}`;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const renderTitleTemplate = (template, title) => {
|
||||
if (template == null)
|
||||
return title || null;
|
||||
if (typeof template === "function")
|
||||
return template(title);
|
||||
return template.replace("%s", title ?? "");
|
||||
};
|
||||
function resolveTitleTemplateFromTags(tags) {
|
||||
let titleTemplateIdx = tags.findIndex((i) => i.tag === "titleTemplate");
|
||||
const titleIdx = tags.findIndex((i) => i.tag === "title");
|
||||
if (titleIdx !== -1 && titleTemplateIdx !== -1) {
|
||||
const newTitle = renderTitleTemplate(
|
||||
tags[titleTemplateIdx].children,
|
||||
tags[titleIdx].children
|
||||
);
|
||||
if (newTitle !== null) {
|
||||
tags[titleIdx].children = newTitle || tags[titleIdx].children;
|
||||
} else {
|
||||
delete tags[titleIdx];
|
||||
}
|
||||
} else if (titleTemplateIdx !== -1) {
|
||||
const newTitle = renderTitleTemplate(
|
||||
tags[titleTemplateIdx].children
|
||||
);
|
||||
if (newTitle !== null) {
|
||||
tags[titleTemplateIdx].children = newTitle;
|
||||
tags[titleTemplateIdx].tag = "title";
|
||||
titleTemplateIdx = -1;
|
||||
}
|
||||
}
|
||||
if (titleTemplateIdx !== -1) {
|
||||
delete tags[titleTemplateIdx];
|
||||
}
|
||||
return tags.filter(Boolean);
|
||||
}
|
||||
|
||||
const DedupesTagsPlugin = (options) => {
|
||||
options = options || {};
|
||||
const dedupeKeys = options.dedupeKeys || ["hid", "vmid", "key"];
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"tag:normalise": function({ tag }) {
|
||||
dedupeKeys.forEach((key) => {
|
||||
if (tag.props[key]) {
|
||||
tag.key = tag.props[key];
|
||||
delete tag.props[key];
|
||||
}
|
||||
});
|
||||
const dedupe = tag.key ? `${tag.tag}:${tag.key}` : tagDedupeKey(tag);
|
||||
if (dedupe)
|
||||
tag._d = dedupe;
|
||||
},
|
||||
"tags:resolve": function(ctx) {
|
||||
const deduping = {};
|
||||
ctx.tags.forEach((tag) => {
|
||||
let dedupeKey = tag._d || tag._p;
|
||||
const dupedTag = deduping[dedupeKey];
|
||||
if (dupedTag) {
|
||||
let strategy = tag?.tagDuplicateStrategy;
|
||||
if (!strategy && (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"))
|
||||
strategy = "merge";
|
||||
if (strategy === "merge") {
|
||||
const oldProps = dupedTag.props;
|
||||
["class", "style"].forEach((key) => {
|
||||
if (tag.props[key] && oldProps[key]) {
|
||||
if (key === "style" && !oldProps[key].endsWith(";"))
|
||||
oldProps[key] += ";";
|
||||
tag.props[key] = `${oldProps[key]} ${tag.props[key]}`;
|
||||
}
|
||||
});
|
||||
deduping[dedupeKey].props = {
|
||||
...oldProps,
|
||||
...tag.props
|
||||
};
|
||||
return;
|
||||
} else if (tag._e === dupedTag._e) {
|
||||
dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
|
||||
}
|
||||
const propCount = Object.keys(tag.props).length;
|
||||
if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
|
||||
delete deduping[dedupeKey];
|
||||
return;
|
||||
}
|
||||
}
|
||||
deduping[dedupeKey] = tag;
|
||||
});
|
||||
ctx.tags = Object.values(deduping);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const SortTagsPlugin = () => {
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"tags:resolve": (ctx) => {
|
||||
const tagIndexForKey = (key) => ctx.tags.find((tag) => tag._d === key)?._p;
|
||||
for (const tag of ctx.tags) {
|
||||
if (!tag.tagPriority || typeof tag.tagPriority === "number")
|
||||
continue;
|
||||
const modifiers = [{ prefix: "before:", offset: -1 }, { prefix: "after:", offset: 1 }];
|
||||
for (const { prefix, offset } of modifiers) {
|
||||
if (tag.tagPriority.startsWith(prefix)) {
|
||||
const key = tag.tagPriority.replace(prefix, "");
|
||||
const index = tagIndexForKey(key);
|
||||
if (typeof index !== "undefined")
|
||||
tag._p = index + offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.tags.sort((a, b) => a._p - b._p).sort(sortTags);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const TitleTemplatePlugin = () => {
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"tags:resolve": (ctx) => {
|
||||
ctx.tags = resolveTitleTemplateFromTags(ctx.tags);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const DeprecatedTagAttrPlugin = () => {
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"tag:normalise": function({ tag }) {
|
||||
if (typeof tag.props.body !== "undefined") {
|
||||
tag.tagPosition = "bodyClose";
|
||||
delete tag.props.body;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const IsBrowser = typeof window !== "undefined";
|
||||
|
||||
const ProvideTagHashPlugin = () => {
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"tag:normalise": (ctx) => {
|
||||
const { tag, entry } = ctx;
|
||||
const isDynamic = typeof tag.props._dynamic !== "undefined";
|
||||
if (!HasElementTags.includes(tag.tag) || !tag.key)
|
||||
return;
|
||||
tag._hash = dom.hashCode(JSON.stringify({ tag: tag.tag, key: tag.key }));
|
||||
if (IsBrowser || getActiveHead()?.resolvedOptions?.document)
|
||||
return;
|
||||
if (entry._m === "server" || isDynamic) {
|
||||
tag.props[`data-h-${tag._hash}`] = "";
|
||||
}
|
||||
},
|
||||
"tags:resolve": (ctx) => {
|
||||
ctx.tags = ctx.tags.map((t) => {
|
||||
delete t.props._dynamic;
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const PatchDomOnEntryUpdatesPlugin = (options) => {
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"entries:updated": function(head) {
|
||||
if (typeof options?.document === "undefined" && typeof window === "undefined")
|
||||
return;
|
||||
let delayFn = options?.delayFn;
|
||||
if (!delayFn && typeof requestAnimationFrame !== "undefined")
|
||||
delayFn = requestAnimationFrame;
|
||||
import('@unhead/dom').then(({ debouncedRenderDOMHead }) => {
|
||||
debouncedRenderDOMHead(head, { document: options?.document || window.document, delayFn });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const EventHandlersPlugin = () => {
|
||||
const stripEventHandlers = (mode, tag) => {
|
||||
const props = {};
|
||||
const eventHandlers = {};
|
||||
Object.entries(tag.props).forEach(([key, value]) => {
|
||||
if (key.startsWith("on") && typeof value === "function")
|
||||
eventHandlers[key] = value;
|
||||
else
|
||||
props[key] = value;
|
||||
});
|
||||
let delayedSrc;
|
||||
if (mode === "dom" && tag.tag === "script" && typeof props.src === "string" && typeof eventHandlers.onload !== "undefined") {
|
||||
delayedSrc = props.src;
|
||||
delete props.src;
|
||||
}
|
||||
return { props, eventHandlers, delayedSrc };
|
||||
};
|
||||
return defineHeadPlugin({
|
||||
hooks: {
|
||||
"ssr:render": function(ctx) {
|
||||
ctx.tags = ctx.tags.map((tag) => {
|
||||
tag.props = stripEventHandlers("ssr", tag).props;
|
||||
return tag;
|
||||
});
|
||||
},
|
||||
"dom:beforeRenderTag": function(ctx) {
|
||||
const { props, eventHandlers, delayedSrc } = stripEventHandlers("dom", ctx.tag);
|
||||
if (!Object.keys(eventHandlers).length)
|
||||
return;
|
||||
ctx.tag.props = props;
|
||||
ctx.tag._eventHandlers = eventHandlers;
|
||||
ctx.tag._delayedSrc = delayedSrc;
|
||||
},
|
||||
"dom:renderTag": function(ctx) {
|
||||
const $el = ctx.$el;
|
||||
if (!ctx.tag._eventHandlers || !$el)
|
||||
return;
|
||||
const $eventListenerTarget = ctx.tag.tag === "bodyAttrs" && typeof window !== "undefined" ? window : $el;
|
||||
Object.entries(ctx.tag._eventHandlers).forEach(([k, value]) => {
|
||||
const sdeKey = `${ctx.tag._d || ctx.tag._p}:${k}`;
|
||||
const eventName = k.slice(2).toLowerCase();
|
||||
const eventDedupeKey = `data-h-${eventName}`;
|
||||
delete ctx.staleSideEffects[sdeKey];
|
||||
if ($el.hasAttribute(eventDedupeKey))
|
||||
return;
|
||||
const handler = value;
|
||||
$el.setAttribute(eventDedupeKey, "");
|
||||
$eventListenerTarget.addEventListener(eventName, handler);
|
||||
if (ctx.entry) {
|
||||
ctx.entry._sde[sdeKey] = () => {
|
||||
$eventListenerTarget.removeEventListener(eventName, handler);
|
||||
$el.removeAttribute(eventDedupeKey);
|
||||
};
|
||||
}
|
||||
});
|
||||
if (ctx.tag._delayedSrc) {
|
||||
$el.setAttribute("src", ctx.tag._delayedSrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function asArray(value) {
|
||||
return Array.isArray(value) ? value : [value];
|
||||
}
|
||||
const HasElementTags = [
|
||||
"base",
|
||||
"meta",
|
||||
"link",
|
||||
"style",
|
||||
"script",
|
||||
"noscript"
|
||||
];
|
||||
|
||||
exports.activeHead = void 0;
|
||||
const setActiveHead = (head) => exports.activeHead = head;
|
||||
const getActiveHead = () => exports.activeHead;
|
||||
|
||||
function useHead(input, options = {}) {
|
||||
const head = getActiveHead();
|
||||
if (head) {
|
||||
const isBrowser = IsBrowser || head.resolvedOptions?.document;
|
||||
if (options.mode === "server" && isBrowser || options.mode === "client" && !isBrowser)
|
||||
return;
|
||||
return head.push(input, options);
|
||||
}
|
||||
}
|
||||
const useTagTitle = (title) => useHead({ title });
|
||||
const useTagBase = (base) => useHead({ base });
|
||||
const useTagMeta = (meta) => useHead({ meta: asArray(meta) });
|
||||
const useTagMetaFlat = (meta) => useTagMeta(unpackMeta(meta));
|
||||
const useSeoMeta = useTagMetaFlat;
|
||||
const useTagLink = (link) => useHead({ link: asArray(link) });
|
||||
const useTagScript = (script) => useHead({ script: asArray(script) });
|
||||
const useTagStyle = (style) => useHead({ style: asArray(style) });
|
||||
const useTagNoscript = (noscript) => useHead({ noscript: asArray(noscript) });
|
||||
const useHtmlAttrs = (attrs) => useHead({ htmlAttrs: attrs });
|
||||
const useBodyAttrs = (attrs) => useHead({ bodyAttrs: attrs });
|
||||
const useTitleTemplate = (titleTemplate) => useHead({ titleTemplate });
|
||||
|
||||
function useServerHead(input, options = {}) {
|
||||
return useHead(input, { ...options, mode: "server" });
|
||||
}
|
||||
const useServerTagTitle = (title) => useServerHead({ title });
|
||||
const useServerTagBase = (base) => useServerHead({ base });
|
||||
const useServerTagMeta = (meta) => useServerHead({ meta: asArray(meta) });
|
||||
const useServerTagMetaFlat = (meta) => useServerTagMeta(unpackMeta(meta));
|
||||
const useServerTagLink = (link) => useServerHead({ link: asArray(link) });
|
||||
const useServerTagScript = (script) => useServerHead({ script: asArray(script) });
|
||||
const useServerTagStyle = (style) => useServerHead({ style: asArray(style) });
|
||||
const useServerTagNoscript = (noscript) => useServerHead({ noscript: asArray(noscript) });
|
||||
const useServerHtmlAttrs = (attrs) => useServerHead({ htmlAttrs: attrs });
|
||||
const useServerBodyAttrs = (attrs) => useServerHead({ bodyAttrs: attrs });
|
||||
const useServerTitleTemplate = (titleTemplate) => useServerHead({ titleTemplate });
|
||||
|
||||
const TagEntityBits = 10;
|
||||
|
||||
async function normaliseEntryTags(e) {
|
||||
const tagPromises = [];
|
||||
Object.entries(e.resolvedInput || e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).forEach(([k, value]) => {
|
||||
const v = asArray(value);
|
||||
tagPromises.push(...v.map((props) => normaliseTag(k, props)).flat());
|
||||
});
|
||||
return (await Promise.all(tagPromises)).flat().map((t, i) => {
|
||||
t._e = e._i;
|
||||
t._p = (e._i << TagEntityBits) + i;
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
const CorePlugins = () => [
|
||||
DedupesTagsPlugin(),
|
||||
SortTagsPlugin(),
|
||||
TitleTemplatePlugin(),
|
||||
ProvideTagHashPlugin(),
|
||||
EventHandlersPlugin(),
|
||||
DeprecatedTagAttrPlugin()
|
||||
];
|
||||
const DOMPlugins = (options = {}) => [
|
||||
PatchDomOnEntryUpdatesPlugin({ document: options?.document, delayFn: options?.domDelayFn })
|
||||
];
|
||||
function createHead(options = {}) {
|
||||
const head = createHeadCore({
|
||||
...options,
|
||||
plugins: [...DOMPlugins(options), ...options?.plugins || []]
|
||||
});
|
||||
setActiveHead(head);
|
||||
return head;
|
||||
}
|
||||
function createHeadCore(options = {}) {
|
||||
let entries = [];
|
||||
let _sde = {};
|
||||
let _eid = 0;
|
||||
const hooks = hookable.createHooks();
|
||||
if (options?.hooks)
|
||||
hooks.addHooks(options.hooks);
|
||||
options.plugins = [
|
||||
...CorePlugins(),
|
||||
...options?.plugins || []
|
||||
];
|
||||
options.plugins.forEach((p) => p.hooks && hooks.addHooks(p.hooks));
|
||||
const updated = () => hooks.callHook("entries:updated", head);
|
||||
const head = {
|
||||
resolvedOptions: options,
|
||||
headEntries() {
|
||||
return entries;
|
||||
},
|
||||
get hooks() {
|
||||
return hooks;
|
||||
},
|
||||
use(plugin) {
|
||||
if (plugin.hooks)
|
||||
hooks.addHooks(plugin.hooks);
|
||||
},
|
||||
push(input, options2) {
|
||||
const activeEntry = {
|
||||
_i: _eid++,
|
||||
input,
|
||||
_sde: {}
|
||||
};
|
||||
if (options2?.mode)
|
||||
activeEntry._m = options2?.mode;
|
||||
entries.push(activeEntry);
|
||||
updated();
|
||||
return {
|
||||
dispose() {
|
||||
entries = entries.filter((e) => {
|
||||
if (e._i !== activeEntry._i)
|
||||
return true;
|
||||
_sde = { ..._sde, ...e._sde || {} };
|
||||
e._sde = {};
|
||||
updated();
|
||||
return false;
|
||||
});
|
||||
},
|
||||
patch(input2) {
|
||||
entries = entries.map((e) => {
|
||||
if (e._i === activeEntry._i) {
|
||||
activeEntry.input = e.input = input2;
|
||||
updated();
|
||||
}
|
||||
return e;
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
async resolveTags() {
|
||||
const resolveCtx = { tags: [], entries: [...entries] };
|
||||
await hooks.callHook("entries:resolve", resolveCtx);
|
||||
for (const entry of resolveCtx.entries) {
|
||||
for (const tag of await normaliseEntryTags(entry)) {
|
||||
const tagCtx = { tag, entry };
|
||||
await hooks.callHook("tag:normalise", tagCtx);
|
||||
resolveCtx.tags.push(tagCtx.tag);
|
||||
}
|
||||
}
|
||||
await hooks.callHook("tags:resolve", resolveCtx);
|
||||
return resolveCtx.tags;
|
||||
},
|
||||
_elMap: {},
|
||||
_popSideEffectQueue() {
|
||||
const sde = { ..._sde };
|
||||
_sde = {};
|
||||
return sde;
|
||||
}
|
||||
};
|
||||
head.hooks.callHook("init", head);
|
||||
return head;
|
||||
}
|
||||
|
||||
function defineHeadPlugin(plugin) {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
const coreComposableNames = [
|
||||
"getActiveHead"
|
||||
];
|
||||
const composableNames = [
|
||||
"useHead",
|
||||
"useTagTitle",
|
||||
"useTagBase",
|
||||
"useTagMeta",
|
||||
"useTagMetaFlat",
|
||||
"useSeoMeta",
|
||||
"useTagLink",
|
||||
"useTagScript",
|
||||
"useTagStyle",
|
||||
"useTagNoscript",
|
||||
"useHtmlAttrs",
|
||||
"useBodyAttrs",
|
||||
"useTitleTemplate",
|
||||
"useServerHead",
|
||||
"useServerTagTitle",
|
||||
"useServerTagBase",
|
||||
"useServerTagMeta",
|
||||
"useServerTagMetaFlat",
|
||||
"useServerTagLink",
|
||||
"useServerTagScript",
|
||||
"useServerTagStyle",
|
||||
"useServerTagNoscript",
|
||||
"useServerHtmlAttrs",
|
||||
"useServerBodyAttrs",
|
||||
"useServerTitleTemplate"
|
||||
];
|
||||
const unheadComposablesImports = [
|
||||
{
|
||||
from: "unhead",
|
||||
imports: [...coreComposableNames, ...composableNames]
|
||||
}
|
||||
];
|
||||
|
||||
exports.CorePlugins = CorePlugins;
|
||||
exports.DOMPlugins = DOMPlugins;
|
||||
exports.DedupesTagsPlugin = DedupesTagsPlugin;
|
||||
exports.DeprecatedTagAttrPlugin = DeprecatedTagAttrPlugin;
|
||||
exports.EventHandlersPlugin = EventHandlersPlugin;
|
||||
exports.HasElementTags = HasElementTags;
|
||||
exports.PatchDomOnEntryUpdatesPlugin = PatchDomOnEntryUpdatesPlugin;
|
||||
exports.ProvideTagHashPlugin = ProvideTagHashPlugin;
|
||||
exports.SortTagsPlugin = SortTagsPlugin;
|
||||
exports.TitleTemplatePlugin = TitleTemplatePlugin;
|
||||
exports.asArray = asArray;
|
||||
exports.composableNames = composableNames;
|
||||
exports.createHead = createHead;
|
||||
exports.createHeadCore = createHeadCore;
|
||||
exports.defineHeadPlugin = defineHeadPlugin;
|
||||
exports.getActiveHead = getActiveHead;
|
||||
exports.normaliseEntryTags = normaliseEntryTags;
|
||||
exports.setActiveHead = setActiveHead;
|
||||
exports.unheadComposablesImports = unheadComposablesImports;
|
||||
exports.useBodyAttrs = useBodyAttrs;
|
||||
exports.useHead = useHead;
|
||||
exports.useHtmlAttrs = useHtmlAttrs;
|
||||
exports.useSeoMeta = useSeoMeta;
|
||||
exports.useServerBodyAttrs = useServerBodyAttrs;
|
||||
exports.useServerHead = useServerHead;
|
||||
exports.useServerHtmlAttrs = useServerHtmlAttrs;
|
||||
exports.useServerTagBase = useServerTagBase;
|
||||
exports.useServerTagLink = useServerTagLink;
|
||||
exports.useServerTagMeta = useServerTagMeta;
|
||||
exports.useServerTagMetaFlat = useServerTagMetaFlat;
|
||||
exports.useServerTagNoscript = useServerTagNoscript;
|
||||
exports.useServerTagScript = useServerTagScript;
|
||||
exports.useServerTagStyle = useServerTagStyle;
|
||||
exports.useServerTagTitle = useServerTagTitle;
|
||||
exports.useServerTitleTemplate = useServerTitleTemplate;
|
||||
exports.useTagBase = useTagBase;
|
||||
exports.useTagLink = useTagLink;
|
||||
exports.useTagMeta = useTagMeta;
|
||||
exports.useTagMetaFlat = useTagMetaFlat;
|
||||
exports.useTagNoscript = useTagNoscript;
|
||||
exports.useTagScript = useTagScript;
|
||||
exports.useTagStyle = useTagStyle;
|
||||
exports.useTagTitle = useTagTitle;
|
||||
exports.useTitleTemplate = useTitleTemplate;
|
||||
Reference in New Issue
Block a user