import { createHooks } from 'hookable'; import { n as normalizeEntryToTags, d as dedupeKey, i as isMetaArrayDupeKey } from './unhead.BaPU1zLf.mjs'; import { t as tagWeight, s as sortTags } from './unhead.DZbvapt-.mjs'; import { c as UsesMergeStrategy, V as ValidHeadTags } from './unhead.yem5I2v_.mjs'; function registerPlugin(head, p) { const plugin = typeof p === "function" ? p(head) : p; const key = plugin.key || String(head.plugins.size + 1); const exists = head.plugins.get(key); if (!exists) { head.plugins.set(key, plugin); head.hooks.addHooks(plugin.hooks || {}); } } function createHeadCore(resolvedOptions = {}) { return createUnhead(resolvedOptions); } function createUnhead(resolvedOptions = {}) { const hooks = createHooks(); hooks.addHooks(resolvedOptions.hooks || {}); const ssr = !resolvedOptions.document; const entries = /* @__PURE__ */ new Map(); const plugins = /* @__PURE__ */ new Map(); const normalizeQueue = []; const head = { _entryCount: 1, // 0 is reserved for internal use plugins, dirty: false, resolvedOptions, hooks, ssr, entries, headEntries() { return [...entries.values()]; }, use: (p) => registerPlugin(head, p), push(input, _options) { const options = { ..._options || {} }; delete options.head; const _i = options._index ?? head._entryCount++; const inst = { _i, input, options }; const _ = { _poll(rm = false) { head.dirty = true; !rm && normalizeQueue.push(_i); hooks.callHook("entries:updated", head); }, dispose() { if (entries.delete(_i)) { _._poll(true); } }, // a patch is the same as creating a new entry, just a nice DX patch(input2) { if (!options.mode || options.mode === "server" && ssr || options.mode === "client" && !ssr) { inst.input = input2; entries.set(_i, inst); _._poll(); } } }; _.patch(input); return _; }, async resolveTags() { const ctx = { tagMap: /* @__PURE__ */ new Map(), tags: [], entries: [...head.entries.values()] }; await hooks.callHook("entries:resolve", ctx); while (normalizeQueue.length) { const i = normalizeQueue.shift(); const e = entries.get(i); if (e) { const normalizeCtx = { tags: normalizeEntryToTags(e.input, resolvedOptions.propResolvers || []).map((t) => Object.assign(t, e.options)), entry: e }; await hooks.callHook("entries:normalize", normalizeCtx); e._tags = normalizeCtx.tags.map((t, i2) => { t._w = tagWeight(head, t); t._p = (e._i << 10) + i2; t._d = dedupeKey(t); return t; }); } } let hasFlatMeta = false; ctx.entries.flatMap((e) => (e._tags || []).map((t) => ({ ...t, props: { ...t.props } }))).sort(sortTags).reduce((acc, next) => { const k = String(next._d || next._p); if (!acc.has(k)) return acc.set(k, next); const prev = acc.get(k); const strategy = next?.tagDuplicateStrategy || (UsesMergeStrategy.has(next.tag) ? "merge" : null) || (next.key && next.key === prev.key ? "merge" : null); if (strategy === "merge") { const newProps = { ...prev.props }; Object.entries(next.props).forEach(([p, v]) => ( // @ts-expect-error untyped newProps[p] = p === "style" ? new Map([...prev.props.style || /* @__PURE__ */ new Map(), ...v]) : p === "class" ? /* @__PURE__ */ new Set([...prev.props.class || /* @__PURE__ */ new Set(), ...v]) : v )); acc.set(k, { ...next, props: newProps }); } else if (next._p >> 10 === prev._p >> 10 && isMetaArrayDupeKey(next._d)) { acc.set(k, Object.assign([...Array.isArray(prev) ? prev : [prev], next], next)); hasFlatMeta = true; } else if (next._w === prev._w ? next._p > prev._p : next?._w < prev?._w) { acc.set(k, next); } return acc; }, ctx.tagMap); const title = ctx.tagMap.get("title"); const titleTemplate = ctx.tagMap.get("titleTemplate"); head._title = title?.textContent; if (titleTemplate) { const titleTemplateFn = titleTemplate?.textContent; head._titleTemplate = typeof titleTemplateFn === "string" ? titleTemplateFn : void 0; if (titleTemplateFn) { let newTitle = typeof titleTemplateFn === "function" ? titleTemplateFn(title?.textContent) : titleTemplateFn; if (typeof newTitle === "string" && !head.plugins.has("template-params")) { newTitle = newTitle.replace("%s", title?.textContent || ""); } if (title) { newTitle === null ? ctx.tagMap.delete("title") : ctx.tagMap.set("title", { ...title, textContent: newTitle }); } else { titleTemplate.tag = "title"; titleTemplate.textContent = newTitle; } } } ctx.tags = Array.from(ctx.tagMap.values()); if (hasFlatMeta) { ctx.tags = ctx.tags.flat().sort(sortTags); } await hooks.callHook("tags:beforeResolve", ctx); await hooks.callHook("tags:resolve", ctx); await hooks.callHook("tags:afterResolve", ctx); const finalTags = []; for (const t of ctx.tags) { const { innerHTML, tag, props } = t; if (!ValidHeadTags.has(tag)) { continue; } if (Object.keys(props).length === 0 && !t.innerHTML && !t.textContent) { continue; } if (tag === "meta" && !props.content && !props["http-equiv"] && !props.charset) { continue; } if (tag === "script" && innerHTML) { if (props.type?.endsWith("json")) { const v = typeof innerHTML === "string" ? innerHTML : JSON.stringify(innerHTML); t.innerHTML = v.replace(/ registerPlugin(head, p)); head.hooks.callHook("init", head); resolvedOptions.init?.forEach((e) => e && head.push(e)); return head; } export { createUnhead as a, createHeadCore as c };