unhead 1.1.23 → 1.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -99,31 +99,18 @@ const DeprecatedTagAttrPlugin = () => {
99
99
  });
100
100
  };
101
101
 
102
- const IsBrowser = typeof window !== "undefined";
103
-
102
+ const DupeableTags = ["link", "style", "script", "noscript"];
104
103
  const ProvideTagHashPlugin = () => {
105
104
  return shared.defineHeadPlugin({
106
105
  hooks: {
107
- "tag:normalise": (ctx) => {
108
- const { tag, entry, resolvedOptions } = ctx;
106
+ "tag:normalise": ({ tag, resolvedOptions }) => {
109
107
  if (resolvedOptions.experimentalHashHydration === true) {
110
108
  tag._h = shared.hashTag(tag);
111
109
  }
112
- const isDynamic = typeof tag.props._dynamic !== "undefined";
113
- if (!shared.HasElementTags.includes(tag.tag) || !tag.key)
114
- return;
115
- if (IsBrowser || getActiveHead()?.resolvedOptions?.document)
116
- return;
117
- if (entry._m === "server" || isDynamic) {
118
- tag._h = tag._h || shared.hashTag(tag);
110
+ if (tag.key && DupeableTags.includes(tag.tag)) {
111
+ tag._h = shared.hashCode(tag.key);
119
112
  tag.props[`data-h-${tag._h}`] = "";
120
113
  }
121
- },
122
- "tags:resolve": (ctx) => {
123
- ctx.tags = ctx.tags.map((t) => {
124
- delete t.props._dynamic;
125
- return t;
126
- });
127
114
  }
128
115
  }
129
116
  });
@@ -270,12 +257,15 @@ const DedupesTagsPlugin = () => {
270
257
 
271
258
  function processTemplateParams(s, config) {
272
259
  function sub(token) {
273
- let val = "";
274
260
  if (["s", "pageTitle"].includes(token))
275
- val = config.pageTitle;
276
- else if (token.includes("."))
277
- val = token.split(".").reduce((acc, key) => acc[key] || "", config);
278
- return val || config[token] || "";
261
+ return config.pageTitle;
262
+ let val;
263
+ if (token.includes(".")) {
264
+ val = token.split(".").reduce((acc, key) => acc ? acc[key] || void 0 : void 0, config);
265
+ } else {
266
+ val = config[token];
267
+ }
268
+ return typeof val !== "undefined" ? val || "" : false;
279
269
  }
280
270
  let decoded = s;
281
271
  try {
@@ -284,7 +274,10 @@ function processTemplateParams(s, config) {
284
274
  }
285
275
  const tokens = (decoded.match(/%(\w+\.+\w+)|%(\w+)/g) || []).sort().reverse();
286
276
  tokens.forEach((token) => {
287
- s = s.replaceAll(token, sub(token.slice(1))).trim();
277
+ const re = sub(token.slice(1));
278
+ if (typeof re === "string") {
279
+ s = s.replaceAll(new RegExp(`\\${token}(\\W|$)`, "g"), `${re}$1`).trim();
280
+ }
288
281
  });
289
282
  if (config.separator) {
290
283
  if (s.endsWith(config.separator))
@@ -302,13 +295,15 @@ function TemplateParamsPlugin() {
302
295
  const { tags } = ctx;
303
296
  const title = tags.find((tag) => tag.tag === "title")?.textContent;
304
297
  const idx = tags.findIndex((tag) => tag.tag === "templateParams");
305
- const params = idx !== -1 ? tags[idx].textContent : {};
298
+ const params = idx !== -1 ? tags[idx].props : {};
306
299
  params.pageTitle = params.pageTitle || title || "";
307
300
  for (const tag of tags) {
308
301
  if (["titleTemplate", "title"].includes(tag.tag) && typeof tag.textContent === "string") {
309
302
  tag.textContent = processTemplateParams(tag.textContent, params);
310
303
  } else if (tag.tag === "meta" && typeof tag.props.content === "string") {
311
304
  tag.props.content = processTemplateParams(tag.props.content, params);
305
+ } else if (tag.tag === "link" && typeof tag.props.href === "string") {
306
+ tag.props.href = processTemplateParams(tag.props.href, params);
312
307
  } else if (tag.tag === "script" && ["application/json", "application/ld+json"].includes(tag.props.type) && typeof tag.innerHTML === "string") {
313
308
  try {
314
309
  tag.innerHTML = JSON.stringify(JSON.parse(tag.innerHTML), (key, val) => {
@@ -326,6 +321,8 @@ function TemplateParamsPlugin() {
326
321
  });
327
322
  }
328
323
 
324
+ const IsBrowser = typeof window !== "undefined";
325
+
329
326
  exports.activeHead = void 0;
330
327
  const setActiveHead = (head) => exports.activeHead = head;
331
328
  const getActiveHead = () => exports.activeHead;
@@ -653,19 +650,21 @@ function resolvePackedMetaObjectValue(value, key) {
653
650
 
654
651
  async function normaliseTag(tagName, input) {
655
652
  const tag = { tag: tagName, props: {} };
656
- if (["title", "titleTemplate", "templateParams"].includes(tagName)) {
653
+ if (tagName === "templateParams") {
654
+ tag.props = input;
655
+ return tag;
656
+ }
657
+ if (["title", "titleTemplate"].includes(tagName)) {
657
658
  tag.textContent = input instanceof Promise ? await input : input;
658
659
  return tag;
659
660
  }
660
661
  if (typeof input === "string") {
661
662
  if (!["script", "noscript", "style"].includes(tagName))
662
663
  return false;
663
- if (tagName === "script" && (/^(https?:)?\/\//.test(input) || input.startsWith("/"))) {
664
+ if (tagName === "script" && (/^(https?:)?\/\//.test(input) || input.startsWith("/")))
664
665
  tag.props.src = input;
665
- } else {
666
+ else
666
667
  tag.innerHTML = input;
667
- tag.key = shared.hashCode(input);
668
- }
669
668
  return tag;
670
669
  }
671
670
  tag.props = await normaliseProps(tagName, { ...input });
@@ -934,10 +933,12 @@ function createHeadCore(options = {}) {
934
933
  for (const entry of resolveCtx.entries) {
935
934
  const transformer = entry._t || ((i) => i);
936
935
  entry.resolvedInput = transformer(entry.resolvedInput || entry.input);
937
- for (const tag of await normaliseEntryTags(entry)) {
938
- const tagCtx = { tag, entry, resolvedOptions: head.resolvedOptions };
939
- await hooks.callHook("tag:normalise", tagCtx);
940
- resolveCtx.tags.push(tagCtx.tag);
936
+ if (entry.resolvedInput) {
937
+ for (const tag of await normaliseEntryTags(entry)) {
938
+ const tagCtx = { tag, entry, resolvedOptions: head.resolvedOptions };
939
+ await hooks.callHook("tag:normalise", tagCtx);
940
+ resolveCtx.tags.push(tagCtx.tag);
941
+ }
941
942
  }
942
943
  }
943
944
  await hooks.callHook("tags:resolve", resolveCtx);
@@ -1017,6 +1018,7 @@ exports.normaliseEntryTags = normaliseEntryTags;
1017
1018
  exports.normaliseProps = normaliseProps;
1018
1019
  exports.normaliseTag = normaliseTag;
1019
1020
  exports.packMeta = packMeta;
1021
+ exports.processTemplateParams = processTemplateParams;
1020
1022
  exports.resolveMetaKeyType = resolveMetaKeyType;
1021
1023
  exports.resolveMetaKeyValue = resolveMetaKeyValue;
1022
1024
  exports.resolvePackedMetaObjectValue = resolvePackedMetaObjectValue;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _unhead_schema from '@unhead/schema';
2
- import { HeadTag, Head, HeadEntryOptions, ActiveHeadEntry, HeadSafe, MetaFlatInput, Title, TitleTemplate, Base, Meta, Link, Script, Style, Noscript, HtmlAttributes, BodyAttributes, Unhead, HeadPlugin, CreateHeadOptions, HeadEntry, MaybeArray } from '@unhead/schema';
2
+ import { HeadTag, TemplateParams, Head, HeadEntryOptions, ActiveHeadEntry, HeadSafe, MetaFlatInput, Title, TitleTemplate, Base, Meta, Link, Script, Style, Noscript, HtmlAttributes, BodyAttributes, Unhead, HeadPlugin, CreateHeadOptions, HeadEntry, MaybeArray } from '@unhead/schema';
3
3
  import { Arrayable } from '@unhead/shared';
4
4
 
5
5
  declare const TAG_WEIGHTS: {
@@ -32,6 +32,7 @@ declare const EventHandlersPlugin: () => _unhead_schema.HeadPlugin;
32
32
 
33
33
  declare const DedupesTagsPlugin: () => _unhead_schema.HeadPlugin;
34
34
 
35
+ declare function processTemplateParams(s: string, config: TemplateParams): string;
35
36
  declare function TemplateParamsPlugin(): _unhead_schema.HeadPlugin;
36
37
 
37
38
  declare function useHead<T extends Head>(input: T, options?: HeadEntryOptions): ActiveHeadEntry<T> | void;
@@ -184,4 +185,4 @@ declare function normaliseEntryTags<T extends {} = Head>(e: HeadEntry<T>): Promi
184
185
 
185
186
  declare function whitelistSafeInput(input: Record<string, MaybeArray<Record<string, string>>>): HeadSafe;
186
187
 
187
- export { CorePlugins, DOMPlugins, DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, ProvideTagHashPlugin, SortModifiers, SortTagsPlugin, TAG_WEIGHTS, TagEntityBits, TemplateParamsPlugin, TitleTemplatePlugin, UseSeoMetaInput, activeHead, composableNames, createHead, createHeadCore, createServerHead, getActiveHead, normaliseClassProp, normaliseEntryTags, normaliseProps, normaliseTag, packMeta, resolveMetaKeyType, resolveMetaKeyValue, resolvePackedMetaObjectValue, setActiveHead, tagWeight, unheadComposablesImports, unpackMeta, useBodyAttrs, useHead, useHeadSafe, useHtmlAttrs, useSeoMeta, useServerBodyAttrs, useServerHead, useServerHeadSafe, useServerHtmlAttrs, useServerSeoMeta, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate, whitelistSafeInput };
188
+ export { CorePlugins, DOMPlugins, DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, ProvideTagHashPlugin, SortModifiers, SortTagsPlugin, TAG_WEIGHTS, TagEntityBits, TemplateParamsPlugin, TitleTemplatePlugin, UseSeoMetaInput, activeHead, composableNames, createHead, createHeadCore, createServerHead, getActiveHead, normaliseClassProp, normaliseEntryTags, normaliseProps, normaliseTag, packMeta, processTemplateParams, resolveMetaKeyType, resolveMetaKeyValue, resolvePackedMetaObjectValue, setActiveHead, tagWeight, unheadComposablesImports, unpackMeta, useBodyAttrs, useHead, useHeadSafe, useHtmlAttrs, useSeoMeta, useServerBodyAttrs, useServerHead, useServerHeadSafe, useServerHtmlAttrs, useServerSeoMeta, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate, whitelistSafeInput };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createHooks } from 'hookable';
2
2
  import { PatchDomOnEntryUpdatesPlugin, maybeGetSSRHash } from '@unhead/dom';
3
- import { defineHeadPlugin, resolveTitleTemplate, hashTag, HasElementTags, tagDedupeKey, asArray as asArray$1, hashCode, TagConfigKeys, TagsWithInnerContent, ValidHeadTags } from '@unhead/shared';
3
+ import { defineHeadPlugin, resolveTitleTemplate, hashTag, hashCode, tagDedupeKey, asArray as asArray$1, TagConfigKeys, TagsWithInnerContent, ValidHeadTags } from '@unhead/shared';
4
4
 
5
5
  const TAG_WEIGHTS = {
6
6
  // aliases
@@ -97,31 +97,18 @@ const DeprecatedTagAttrPlugin = () => {
97
97
  });
98
98
  };
99
99
 
100
- const IsBrowser = typeof window !== "undefined";
101
-
100
+ const DupeableTags = ["link", "style", "script", "noscript"];
102
101
  const ProvideTagHashPlugin = () => {
103
102
  return defineHeadPlugin({
104
103
  hooks: {
105
- "tag:normalise": (ctx) => {
106
- const { tag, entry, resolvedOptions } = ctx;
104
+ "tag:normalise": ({ tag, resolvedOptions }) => {
107
105
  if (resolvedOptions.experimentalHashHydration === true) {
108
106
  tag._h = hashTag(tag);
109
107
  }
110
- const isDynamic = typeof tag.props._dynamic !== "undefined";
111
- if (!HasElementTags.includes(tag.tag) || !tag.key)
112
- return;
113
- if (IsBrowser || getActiveHead()?.resolvedOptions?.document)
114
- return;
115
- if (entry._m === "server" || isDynamic) {
116
- tag._h = tag._h || hashTag(tag);
108
+ if (tag.key && DupeableTags.includes(tag.tag)) {
109
+ tag._h = hashCode(tag.key);
117
110
  tag.props[`data-h-${tag._h}`] = "";
118
111
  }
119
- },
120
- "tags:resolve": (ctx) => {
121
- ctx.tags = ctx.tags.map((t) => {
122
- delete t.props._dynamic;
123
- return t;
124
- });
125
112
  }
126
113
  }
127
114
  });
@@ -268,12 +255,15 @@ const DedupesTagsPlugin = () => {
268
255
 
269
256
  function processTemplateParams(s, config) {
270
257
  function sub(token) {
271
- let val = "";
272
258
  if (["s", "pageTitle"].includes(token))
273
- val = config.pageTitle;
274
- else if (token.includes("."))
275
- val = token.split(".").reduce((acc, key) => acc[key] || "", config);
276
- return val || config[token] || "";
259
+ return config.pageTitle;
260
+ let val;
261
+ if (token.includes(".")) {
262
+ val = token.split(".").reduce((acc, key) => acc ? acc[key] || void 0 : void 0, config);
263
+ } else {
264
+ val = config[token];
265
+ }
266
+ return typeof val !== "undefined" ? val || "" : false;
277
267
  }
278
268
  let decoded = s;
279
269
  try {
@@ -282,7 +272,10 @@ function processTemplateParams(s, config) {
282
272
  }
283
273
  const tokens = (decoded.match(/%(\w+\.+\w+)|%(\w+)/g) || []).sort().reverse();
284
274
  tokens.forEach((token) => {
285
- s = s.replaceAll(token, sub(token.slice(1))).trim();
275
+ const re = sub(token.slice(1));
276
+ if (typeof re === "string") {
277
+ s = s.replaceAll(new RegExp(`\\${token}(\\W|$)`, "g"), `${re}$1`).trim();
278
+ }
286
279
  });
287
280
  if (config.separator) {
288
281
  if (s.endsWith(config.separator))
@@ -300,13 +293,15 @@ function TemplateParamsPlugin() {
300
293
  const { tags } = ctx;
301
294
  const title = tags.find((tag) => tag.tag === "title")?.textContent;
302
295
  const idx = tags.findIndex((tag) => tag.tag === "templateParams");
303
- const params = idx !== -1 ? tags[idx].textContent : {};
296
+ const params = idx !== -1 ? tags[idx].props : {};
304
297
  params.pageTitle = params.pageTitle || title || "";
305
298
  for (const tag of tags) {
306
299
  if (["titleTemplate", "title"].includes(tag.tag) && typeof tag.textContent === "string") {
307
300
  tag.textContent = processTemplateParams(tag.textContent, params);
308
301
  } else if (tag.tag === "meta" && typeof tag.props.content === "string") {
309
302
  tag.props.content = processTemplateParams(tag.props.content, params);
303
+ } else if (tag.tag === "link" && typeof tag.props.href === "string") {
304
+ tag.props.href = processTemplateParams(tag.props.href, params);
310
305
  } else if (tag.tag === "script" && ["application/json", "application/ld+json"].includes(tag.props.type) && typeof tag.innerHTML === "string") {
311
306
  try {
312
307
  tag.innerHTML = JSON.stringify(JSON.parse(tag.innerHTML), (key, val) => {
@@ -324,6 +319,8 @@ function TemplateParamsPlugin() {
324
319
  });
325
320
  }
326
321
 
322
+ const IsBrowser = typeof window !== "undefined";
323
+
327
324
  let activeHead;
328
325
  const setActiveHead = (head) => activeHead = head;
329
326
  const getActiveHead = () => activeHead;
@@ -651,19 +648,21 @@ function resolvePackedMetaObjectValue(value, key) {
651
648
 
652
649
  async function normaliseTag(tagName, input) {
653
650
  const tag = { tag: tagName, props: {} };
654
- if (["title", "titleTemplate", "templateParams"].includes(tagName)) {
651
+ if (tagName === "templateParams") {
652
+ tag.props = input;
653
+ return tag;
654
+ }
655
+ if (["title", "titleTemplate"].includes(tagName)) {
655
656
  tag.textContent = input instanceof Promise ? await input : input;
656
657
  return tag;
657
658
  }
658
659
  if (typeof input === "string") {
659
660
  if (!["script", "noscript", "style"].includes(tagName))
660
661
  return false;
661
- if (tagName === "script" && (/^(https?:)?\/\//.test(input) || input.startsWith("/"))) {
662
+ if (tagName === "script" && (/^(https?:)?\/\//.test(input) || input.startsWith("/")))
662
663
  tag.props.src = input;
663
- } else {
664
+ else
664
665
  tag.innerHTML = input;
665
- tag.key = hashCode(input);
666
- }
667
666
  return tag;
668
667
  }
669
668
  tag.props = await normaliseProps(tagName, { ...input });
@@ -932,10 +931,12 @@ function createHeadCore(options = {}) {
932
931
  for (const entry of resolveCtx.entries) {
933
932
  const transformer = entry._t || ((i) => i);
934
933
  entry.resolvedInput = transformer(entry.resolvedInput || entry.input);
935
- for (const tag of await normaliseEntryTags(entry)) {
936
- const tagCtx = { tag, entry, resolvedOptions: head.resolvedOptions };
937
- await hooks.callHook("tag:normalise", tagCtx);
938
- resolveCtx.tags.push(tagCtx.tag);
934
+ if (entry.resolvedInput) {
935
+ for (const tag of await normaliseEntryTags(entry)) {
936
+ const tagCtx = { tag, entry, resolvedOptions: head.resolvedOptions };
937
+ await hooks.callHook("tag:normalise", tagCtx);
938
+ resolveCtx.tags.push(tagCtx.tag);
939
+ }
939
940
  }
940
941
  }
941
942
  await hooks.callHook("tags:resolve", resolveCtx);
@@ -993,4 +994,4 @@ const unheadComposablesImports = [
993
994
  }
994
995
  ];
995
996
 
996
- export { CorePlugins, DOMPlugins, DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, ProvideTagHashPlugin, SortModifiers, SortTagsPlugin, TAG_WEIGHTS, TagEntityBits, TemplateParamsPlugin, TitleTemplatePlugin, activeHead, composableNames, createHead, createHeadCore, createServerHead, getActiveHead, normaliseClassProp, normaliseEntryTags, normaliseProps, normaliseTag, packMeta, resolveMetaKeyType, resolveMetaKeyValue, resolvePackedMetaObjectValue, setActiveHead, tagWeight, unheadComposablesImports, unpackMeta, useBodyAttrs, useHead, useHeadSafe, useHtmlAttrs, useSeoMeta, useServerBodyAttrs, useServerHead, useServerHeadSafe, useServerHtmlAttrs, useServerSeoMeta, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate, whitelistSafeInput };
997
+ export { CorePlugins, DOMPlugins, DedupesTagsPlugin, DeprecatedTagAttrPlugin, EventHandlersPlugin, ProvideTagHashPlugin, SortModifiers, SortTagsPlugin, TAG_WEIGHTS, TagEntityBits, TemplateParamsPlugin, TitleTemplatePlugin, activeHead, composableNames, createHead, createHeadCore, createServerHead, getActiveHead, normaliseClassProp, normaliseEntryTags, normaliseProps, normaliseTag, packMeta, processTemplateParams, resolveMetaKeyType, resolveMetaKeyValue, resolvePackedMetaObjectValue, setActiveHead, tagWeight, unheadComposablesImports, unpackMeta, useBodyAttrs, useHead, useHeadSafe, useHtmlAttrs, useSeoMeta, useServerBodyAttrs, useServerHead, useServerHeadSafe, useServerHtmlAttrs, useServerSeoMeta, useServerTagBase, useServerTagLink, useServerTagMeta, useServerTagMetaFlat, useServerTagNoscript, useServerTagScript, useServerTagStyle, useServerTagTitle, useServerTitleTemplate, useTagBase, useTagLink, useTagMeta, useTagMetaFlat, useTagNoscript, useTagScript, useTagStyle, useTagTitle, useTitleTemplate, whitelistSafeInput };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "1.1.23",
5
- "packageManager": "pnpm@7.28.0",
4
+ "version": "1.1.25",
5
+ "packageManager": "pnpm@7.30.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/harlan-zw",
@@ -30,10 +30,10 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "hookable": "^5.4.2",
34
- "@unhead/dom": "1.1.23",
35
- "@unhead/schema": "1.1.23",
36
- "@unhead/shared": "1.1.23"
33
+ "hookable": "^5.5.1",
34
+ "@unhead/dom": "1.1.25",
35
+ "@unhead/schema": "1.1.25",
36
+ "@unhead/shared": "1.1.25"
37
37
  },
38
38
  "devDependencies": {
39
39
  "packrup": "^0.1.0"