unhead 0.1.3 → 0.2.0

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
@@ -2,30 +2,6 @@
2
2
 
3
3
  const hookable = require('hookable');
4
4
 
5
- function normaliseTag$1(tagName, input, options = {}) {
6
- const tag = { tag: tagName, props: {} };
7
- if (tagName === "title")
8
- tag.children = String(input);
9
- else
10
- tag.props = normaliseProps({ ...input });
11
- ["children", ...options?.childrenKeys || []].forEach((key) => {
12
- if (typeof tag.props[key] !== "undefined") {
13
- tag.children = tag.props[key];
14
- delete tag.props[key];
15
- }
16
- });
17
- return tag;
18
- }
19
- function normaliseProps(props) {
20
- for (const k in props) {
21
- if (String(props[k]) === "true") {
22
- props[k] = "";
23
- } else if (String(props[k]) === "false") {
24
- delete props[k];
25
- }
26
- }
27
- return props;
28
- }
29
5
  const HasElementTags = [
30
6
  "base",
31
7
  "meta",
@@ -46,24 +22,70 @@ const ValidHeadTags = [
46
22
  "script",
47
23
  "noscript"
48
24
  ];
25
+ const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
49
26
 
50
- const sortCriticalTags = (aTag, bTag) => {
51
- const tagWeight = (tag) => {
52
- switch (tag.tag) {
53
- case "base":
54
- return -1;
55
- case "title":
56
- return 1;
57
- case "meta":
58
- if (tag.props.charset)
59
- return -2;
60
- if (tag.props["http-equiv"] === "content-security-policy")
61
- return 0;
62
- return 10;
63
- default:
64
- return 10;
27
+ function normaliseTag(tagName, input) {
28
+ const tag = { tag: tagName, props: {} };
29
+ if (tagName === "title" || tagName === "titleTemplate") {
30
+ tag.children = input;
31
+ return tag;
32
+ }
33
+ tag.props = normaliseProps({ ...input });
34
+ ["children", "innerHtml", "innerHTML"].forEach((key) => {
35
+ if (typeof tag.props[key] !== "undefined") {
36
+ tag.children = tag.props[key];
37
+ delete tag.props[key];
65
38
  }
66
- };
39
+ });
40
+ Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
41
+ tag[k] = tag.props[k];
42
+ delete tag.props[k];
43
+ });
44
+ if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
45
+ tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
46
+ }
47
+ if (Array.isArray(tag.props.class))
48
+ tag.props.class = tag.props.class.join(" ");
49
+ if (tag.props.content && Array.isArray(tag.props.content)) {
50
+ return tag.props.content.map((v, i) => {
51
+ const newTag = { ...tag, props: { ...tag.props } };
52
+ newTag.props.content = v;
53
+ newTag.key = `${tag.props.name || tag.props.property}:${i}`;
54
+ return newTag;
55
+ });
56
+ }
57
+ return tag;
58
+ }
59
+ function normaliseProps(props) {
60
+ for (const k in props) {
61
+ if (String(props[k]) === "true") {
62
+ props[k] = "";
63
+ } else if (String(props[k]) === "false") {
64
+ delete props[k];
65
+ }
66
+ }
67
+ return props;
68
+ }
69
+
70
+ const tagWeight = (tag) => {
71
+ if (typeof tag.tagPriority === "number")
72
+ return tag.tagPriority;
73
+ switch (tag.tag) {
74
+ case "base":
75
+ return -1;
76
+ case "title":
77
+ return 1;
78
+ case "meta":
79
+ if (tag.props.charset)
80
+ return -2;
81
+ if (tag.props["http-equiv"] === "content-security-policy")
82
+ return 0;
83
+ return 10;
84
+ default:
85
+ return 10;
86
+ }
87
+ };
88
+ const sortTags = (aTag, bTag) => {
67
89
  return tagWeight(aTag) - tagWeight(bTag);
68
90
  };
69
91
 
@@ -104,7 +126,7 @@ function resolveTitleTemplateFromTags(tags) {
104
126
  if (newTitle !== null) {
105
127
  tags[titleIdx].children = newTitle || tags[titleIdx].children;
106
128
  } else {
107
- tags = tags.filter((_, i) => i !== titleIdx);
129
+ delete tags[titleIdx];
108
130
  }
109
131
  } else if (titleTemplateIdx !== -1) {
110
132
  const newTitle = renderTitleTemplate(
@@ -115,9 +137,10 @@ function resolveTitleTemplateFromTags(tags) {
115
137
  tags[titleTemplateIdx].tag = "title";
116
138
  }
117
139
  }
118
- if (titleTemplateIdx !== -1)
119
- tags = tags.filter((_, i) => i !== titleTemplateIdx);
120
- return tags;
140
+ if (titleTemplateIdx !== -1) {
141
+ delete tags[titleTemplateIdx];
142
+ }
143
+ return tags.filter(Boolean);
121
144
  }
122
145
 
123
146
  const DedupesTagsPlugin = (options) => {
@@ -181,12 +204,8 @@ const SortTagsPlugin = () => {
181
204
  "tags:resolve": (ctx) => {
182
205
  const tagIndexForKey = (key) => ctx.tags.find((tag) => tag._d === key)?._p;
183
206
  for (const tag of ctx.tags) {
184
- if (!tag?.tagPriority)
185
- continue;
186
- if (typeof tag.tagPriority === "number") {
187
- tag._p = tag.tagPriority;
207
+ if (!tag.tagPriority || typeof tag.tagPriority === "number")
188
208
  continue;
189
- }
190
209
  const modifiers = [{ prefix: "before:", offset: -1 }, { prefix: "after:", offset: 1 }];
191
210
  for (const { prefix, offset } of modifiers) {
192
211
  if (tag.tagPriority.startsWith(prefix)) {
@@ -197,7 +216,7 @@ const SortTagsPlugin = () => {
197
216
  }
198
217
  }
199
218
  }
200
- ctx.tags.sort((a, b) => a._p - b._p).sort(sortCriticalTags);
219
+ ctx.tags.sort((a, b) => a._p - b._p).sort(sortTags);
201
220
  }
202
221
  }
203
222
  });
@@ -213,6 +232,23 @@ const TitleTemplatePlugin = () => {
213
232
  });
214
233
  };
215
234
 
235
+ function defineHeadPlugin(plugin) {
236
+ return plugin;
237
+ }
238
+
239
+ const DeprecatedTagAttrPlugin = () => {
240
+ return defineHeadPlugin({
241
+ hooks: {
242
+ "tag:normalise": function({ tag }) {
243
+ if (tag.props.body) {
244
+ tag.tagPosition = "bodyClose";
245
+ delete tag.props.body;
246
+ }
247
+ }
248
+ }
249
+ });
250
+ };
251
+
216
252
  function hashCode(s) {
217
253
  let h = 9;
218
254
  for (let i = 0; i < s.length; )
@@ -286,40 +322,18 @@ const useNoscript = (noscript) => {
286
322
  function asArray(value) {
287
323
  return Array.isArray(value) ? value : [value];
288
324
  }
289
- const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
290
325
 
291
- function normaliseTag(tagName, input, entry) {
292
- const tag = normaliseTag$1(tagName, input, { childrenKeys: ["innerHTML", "textContent"] });
293
- tag._e = entry._i;
294
- Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
295
- tag[k] = tag.props[k];
296
- delete tag.props[k];
297
- });
298
- if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
299
- tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
300
- }
301
- if (Array.isArray(tag.props.class))
302
- tag.props.class = tag.props.class.join(" ");
303
- if (tag.props.content && Array.isArray(tag.props.content)) {
304
- return tag.props.content.map((v, i) => {
305
- const newTag = { ...tag, props: { ...tag.props } };
306
- newTag.props.content = v;
307
- newTag.key = `${tag.props.name || tag.props.property}:${i}`;
308
- return newTag;
309
- });
310
- }
311
- return tag;
312
- }
313
326
  function normaliseEntryTags(e) {
314
327
  return Object.entries(e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).map(
315
- ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props, e)))
328
+ ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props)))
316
329
  ).flat(3).map((t, i) => {
330
+ t._e = e._i;
317
331
  t._p = (e._i << 8) + i++;
318
332
  return t;
319
333
  });
320
334
  }
321
335
 
322
- async function createHead(options = {}) {
336
+ function createHead(options = {}) {
323
337
  let entries = [];
324
338
  let _sde = {};
325
339
  let entryId = 0;
@@ -327,12 +341,14 @@ async function createHead(options = {}) {
327
341
  if (options.hooks)
328
342
  hooks.addHooks(options.hooks);
329
343
  const plugins = [
344
+ DeprecatedTagAttrPlugin(),
330
345
  DedupesTagsPlugin(),
331
346
  SortTagsPlugin(),
332
347
  TitleTemplatePlugin()
333
348
  ];
334
349
  plugins.push(...options.plugins || []);
335
350
  plugins.forEach((plugin) => hooks.addHooks(plugin.hooks || {}));
351
+ const triggerUpdate = () => hooks.callHook("entries:updated", head);
336
352
  const head = {
337
353
  _removeQueuedSideEffect(key) {
338
354
  delete _sde[key];
@@ -355,28 +371,29 @@ async function createHead(options = {}) {
355
371
  _sde: {},
356
372
  ...options2
357
373
  });
358
- hooks.callHook("entries:updated", head);
374
+ triggerUpdate();
375
+ const queueSideEffects = (e) => {
376
+ _sde = { ..._sde, ...e._sde || {} };
377
+ e._sde = {};
378
+ triggerUpdate();
379
+ };
359
380
  return {
360
381
  dispose() {
361
382
  entries = entries.filter((e) => {
362
383
  if (e._i !== _i)
363
384
  return true;
364
- _sde = { ..._sde, ...e._sde || {} };
365
- e._sde = {};
385
+ queueSideEffects(e);
366
386
  return false;
367
387
  });
368
- hooks.callHook("entries:updated", head);
369
388
  },
370
389
  patch(input2) {
371
390
  entries = entries.map((e) => {
372
391
  if (e._i === _i) {
373
- _sde = { ..._sde, ...e._sde || {} };
374
- e._sde = {};
392
+ queueSideEffects(e);
375
393
  e.input = e._i === _i ? input2 : e.input;
376
394
  }
377
395
  return e;
378
396
  });
379
- hooks.callHook("entries:updated", head);
380
397
  }
381
398
  };
382
399
  },
@@ -394,26 +411,21 @@ async function createHead(options = {}) {
394
411
  return resolveCtx.tags;
395
412
  }
396
413
  };
397
- await head.hooks.callHook("init", head);
414
+ head.hooks.callHook("init", head);
398
415
  setActiveHead(head);
399
416
  return head;
400
417
  }
401
418
 
402
- function defineHeadPlugin(plugin) {
403
- return plugin;
404
- }
405
-
406
419
  exports.DedupesTagsPlugin = DedupesTagsPlugin;
420
+ exports.DeprecatedTagAttrPlugin = DeprecatedTagAttrPlugin;
407
421
  exports.HydratesStatePlugin = HydratesStatePlugin;
408
422
  exports.SortTagsPlugin = SortTagsPlugin;
409
- exports.TagConfigKeys = TagConfigKeys;
410
423
  exports.TitleTemplatePlugin = TitleTemplatePlugin;
411
424
  exports.asArray = asArray;
412
425
  exports.createHead = createHead;
413
426
  exports.defineHeadPlugin = defineHeadPlugin;
414
427
  exports.getActiveHead = getActiveHead;
415
428
  exports.normaliseEntryTags = normaliseEntryTags;
416
- exports.normaliseTag = normaliseTag;
417
429
  exports.setActiveHead = setActiveHead;
418
430
  exports.useBase = useBase;
419
431
  exports.useBodyAttrs = useBodyAttrs;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _unhead_schema from '@unhead/schema';
2
- import { Head, HeadEntryOptions, Meta, Link, Script, Style, Base, HtmlAttributes, BodyAttributes, Noscript, HeadClient, CreateHeadOptions, HeadPlugin, HeadTag, HeadEntry } from '@unhead/schema';
2
+ import { Head, HeadEntryOptions, Meta, Link, Script, Style, Base, HtmlAttributes, BodyAttributes, Noscript, HeadClient, CreateHeadOptions, HeadPlugin, HeadEntry, HeadTag } from '@unhead/schema';
3
3
 
4
4
  interface DedupesTagsPluginOptions {
5
5
  dedupeKeys?: string[];
@@ -10,6 +10,8 @@ declare const SortTagsPlugin: () => _unhead_schema.HeadPlugin;
10
10
 
11
11
  declare const TitleTemplatePlugin: () => _unhead_schema.HeadPlugin;
12
12
 
13
+ declare const DeprecatedTagAttrPlugin: () => _unhead_schema.HeadPlugin;
14
+
13
15
  declare const HydratesStatePlugin: () => _unhead_schema.HeadPlugin;
14
16
 
15
17
  declare function useHead<T extends Head>(input: T, options?: HeadEntryOptions): void;
@@ -29,15 +31,13 @@ declare let activeHead: HeadClient<any> | undefined;
29
31
  declare const setActiveHead: <T extends HeadClient<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>>(head: T | undefined) => T | undefined;
30
32
  declare const getActiveHead: <T extends HeadClient<_unhead_schema.Head<_unhead_schema.SchemaAugmentations>>>() => T;
31
33
 
32
- declare function createHead<T extends {} = Head>(options?: CreateHeadOptions): Promise<HeadClient<T>>;
34
+ declare function createHead<T extends {} = Head>(options?: CreateHeadOptions): HeadClient<T>;
33
35
 
34
36
  declare function defineHeadPlugin(plugin: HeadPlugin): HeadPlugin;
35
37
 
36
- declare function normaliseTag<T>(tagName: HeadTag['tag'], input: HeadTag['props'], entry: HeadEntry<T>): HeadTag | HeadTag[];
37
38
  declare function normaliseEntryTags<T extends {} = Head>(e: HeadEntry<T>): HeadTag[];
38
39
 
39
40
  declare type Arrayable<T> = T | Array<T>;
40
41
  declare function asArray<T>(value: Arrayable<T>): T[];
41
- declare const TagConfigKeys: string[];
42
42
 
43
- export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, HydratesStatePlugin, SortTagsPlugin, TagConfigKeys, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, normaliseTag, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useServerHead, useStyle, useTitle, useTitleTemplate };
43
+ export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, DeprecatedTagAttrPlugin, HydratesStatePlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useServerHead, useStyle, useTitle, useTitleTemplate };
package/dist/index.mjs CHANGED
@@ -1,29 +1,5 @@
1
1
  import { createHooks } from 'hookable';
2
2
 
3
- function normaliseTag$1(tagName, input, options = {}) {
4
- const tag = { tag: tagName, props: {} };
5
- if (tagName === "title")
6
- tag.children = String(input);
7
- else
8
- tag.props = normaliseProps({ ...input });
9
- ["children", ...options?.childrenKeys || []].forEach((key) => {
10
- if (typeof tag.props[key] !== "undefined") {
11
- tag.children = tag.props[key];
12
- delete tag.props[key];
13
- }
14
- });
15
- return tag;
16
- }
17
- function normaliseProps(props) {
18
- for (const k in props) {
19
- if (String(props[k]) === "true") {
20
- props[k] = "";
21
- } else if (String(props[k]) === "false") {
22
- delete props[k];
23
- }
24
- }
25
- return props;
26
- }
27
3
  const HasElementTags = [
28
4
  "base",
29
5
  "meta",
@@ -44,24 +20,70 @@ const ValidHeadTags = [
44
20
  "script",
45
21
  "noscript"
46
22
  ];
23
+ const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
47
24
 
48
- const sortCriticalTags = (aTag, bTag) => {
49
- const tagWeight = (tag) => {
50
- switch (tag.tag) {
51
- case "base":
52
- return -1;
53
- case "title":
54
- return 1;
55
- case "meta":
56
- if (tag.props.charset)
57
- return -2;
58
- if (tag.props["http-equiv"] === "content-security-policy")
59
- return 0;
60
- return 10;
61
- default:
62
- return 10;
25
+ function normaliseTag(tagName, input) {
26
+ const tag = { tag: tagName, props: {} };
27
+ if (tagName === "title" || tagName === "titleTemplate") {
28
+ tag.children = input;
29
+ return tag;
30
+ }
31
+ tag.props = normaliseProps({ ...input });
32
+ ["children", "innerHtml", "innerHTML"].forEach((key) => {
33
+ if (typeof tag.props[key] !== "undefined") {
34
+ tag.children = tag.props[key];
35
+ delete tag.props[key];
63
36
  }
64
- };
37
+ });
38
+ Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
39
+ tag[k] = tag.props[k];
40
+ delete tag.props[k];
41
+ });
42
+ if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
43
+ tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
44
+ }
45
+ if (Array.isArray(tag.props.class))
46
+ tag.props.class = tag.props.class.join(" ");
47
+ if (tag.props.content && Array.isArray(tag.props.content)) {
48
+ return tag.props.content.map((v, i) => {
49
+ const newTag = { ...tag, props: { ...tag.props } };
50
+ newTag.props.content = v;
51
+ newTag.key = `${tag.props.name || tag.props.property}:${i}`;
52
+ return newTag;
53
+ });
54
+ }
55
+ return tag;
56
+ }
57
+ function normaliseProps(props) {
58
+ for (const k in props) {
59
+ if (String(props[k]) === "true") {
60
+ props[k] = "";
61
+ } else if (String(props[k]) === "false") {
62
+ delete props[k];
63
+ }
64
+ }
65
+ return props;
66
+ }
67
+
68
+ const tagWeight = (tag) => {
69
+ if (typeof tag.tagPriority === "number")
70
+ return tag.tagPriority;
71
+ switch (tag.tag) {
72
+ case "base":
73
+ return -1;
74
+ case "title":
75
+ return 1;
76
+ case "meta":
77
+ if (tag.props.charset)
78
+ return -2;
79
+ if (tag.props["http-equiv"] === "content-security-policy")
80
+ return 0;
81
+ return 10;
82
+ default:
83
+ return 10;
84
+ }
85
+ };
86
+ const sortTags = (aTag, bTag) => {
65
87
  return tagWeight(aTag) - tagWeight(bTag);
66
88
  };
67
89
 
@@ -102,7 +124,7 @@ function resolveTitleTemplateFromTags(tags) {
102
124
  if (newTitle !== null) {
103
125
  tags[titleIdx].children = newTitle || tags[titleIdx].children;
104
126
  } else {
105
- tags = tags.filter((_, i) => i !== titleIdx);
127
+ delete tags[titleIdx];
106
128
  }
107
129
  } else if (titleTemplateIdx !== -1) {
108
130
  const newTitle = renderTitleTemplate(
@@ -113,9 +135,10 @@ function resolveTitleTemplateFromTags(tags) {
113
135
  tags[titleTemplateIdx].tag = "title";
114
136
  }
115
137
  }
116
- if (titleTemplateIdx !== -1)
117
- tags = tags.filter((_, i) => i !== titleTemplateIdx);
118
- return tags;
138
+ if (titleTemplateIdx !== -1) {
139
+ delete tags[titleTemplateIdx];
140
+ }
141
+ return tags.filter(Boolean);
119
142
  }
120
143
 
121
144
  const DedupesTagsPlugin = (options) => {
@@ -179,12 +202,8 @@ const SortTagsPlugin = () => {
179
202
  "tags:resolve": (ctx) => {
180
203
  const tagIndexForKey = (key) => ctx.tags.find((tag) => tag._d === key)?._p;
181
204
  for (const tag of ctx.tags) {
182
- if (!tag?.tagPriority)
183
- continue;
184
- if (typeof tag.tagPriority === "number") {
185
- tag._p = tag.tagPriority;
205
+ if (!tag.tagPriority || typeof tag.tagPriority === "number")
186
206
  continue;
187
- }
188
207
  const modifiers = [{ prefix: "before:", offset: -1 }, { prefix: "after:", offset: 1 }];
189
208
  for (const { prefix, offset } of modifiers) {
190
209
  if (tag.tagPriority.startsWith(prefix)) {
@@ -195,7 +214,7 @@ const SortTagsPlugin = () => {
195
214
  }
196
215
  }
197
216
  }
198
- ctx.tags.sort((a, b) => a._p - b._p).sort(sortCriticalTags);
217
+ ctx.tags.sort((a, b) => a._p - b._p).sort(sortTags);
199
218
  }
200
219
  }
201
220
  });
@@ -211,6 +230,23 @@ const TitleTemplatePlugin = () => {
211
230
  });
212
231
  };
213
232
 
233
+ function defineHeadPlugin(plugin) {
234
+ return plugin;
235
+ }
236
+
237
+ const DeprecatedTagAttrPlugin = () => {
238
+ return defineHeadPlugin({
239
+ hooks: {
240
+ "tag:normalise": function({ tag }) {
241
+ if (tag.props.body) {
242
+ tag.tagPosition = "bodyClose";
243
+ delete tag.props.body;
244
+ }
245
+ }
246
+ }
247
+ });
248
+ };
249
+
214
250
  function hashCode(s) {
215
251
  let h = 9;
216
252
  for (let i = 0; i < s.length; )
@@ -284,40 +320,18 @@ const useNoscript = (noscript) => {
284
320
  function asArray(value) {
285
321
  return Array.isArray(value) ? value : [value];
286
322
  }
287
- const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
288
323
 
289
- function normaliseTag(tagName, input, entry) {
290
- const tag = normaliseTag$1(tagName, input, { childrenKeys: ["innerHTML", "textContent"] });
291
- tag._e = entry._i;
292
- Object.keys(tag.props).filter((k) => TagConfigKeys.includes(k)).forEach((k) => {
293
- tag[k] = tag.props[k];
294
- delete tag.props[k];
295
- });
296
- if (typeof tag.props.class === "object" && !Array.isArray(tag.props.class)) {
297
- tag.props.class = Object.keys(tag.props.class).filter((k) => tag.props.class[k]);
298
- }
299
- if (Array.isArray(tag.props.class))
300
- tag.props.class = tag.props.class.join(" ");
301
- if (tag.props.content && Array.isArray(tag.props.content)) {
302
- return tag.props.content.map((v, i) => {
303
- const newTag = { ...tag, props: { ...tag.props } };
304
- newTag.props.content = v;
305
- newTag.key = `${tag.props.name || tag.props.property}:${i}`;
306
- return newTag;
307
- });
308
- }
309
- return tag;
310
- }
311
324
  function normaliseEntryTags(e) {
312
325
  return Object.entries(e.input).filter(([k, v]) => typeof v !== "undefined" && ValidHeadTags.includes(k)).map(
313
- ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props, e)))
326
+ ([k, value]) => asArray(value).map((props) => asArray(normaliseTag(k, props)))
314
327
  ).flat(3).map((t, i) => {
328
+ t._e = e._i;
315
329
  t._p = (e._i << 8) + i++;
316
330
  return t;
317
331
  });
318
332
  }
319
333
 
320
- async function createHead(options = {}) {
334
+ function createHead(options = {}) {
321
335
  let entries = [];
322
336
  let _sde = {};
323
337
  let entryId = 0;
@@ -325,12 +339,14 @@ async function createHead(options = {}) {
325
339
  if (options.hooks)
326
340
  hooks.addHooks(options.hooks);
327
341
  const plugins = [
342
+ DeprecatedTagAttrPlugin(),
328
343
  DedupesTagsPlugin(),
329
344
  SortTagsPlugin(),
330
345
  TitleTemplatePlugin()
331
346
  ];
332
347
  plugins.push(...options.plugins || []);
333
348
  plugins.forEach((plugin) => hooks.addHooks(plugin.hooks || {}));
349
+ const triggerUpdate = () => hooks.callHook("entries:updated", head);
334
350
  const head = {
335
351
  _removeQueuedSideEffect(key) {
336
352
  delete _sde[key];
@@ -353,28 +369,29 @@ async function createHead(options = {}) {
353
369
  _sde: {},
354
370
  ...options2
355
371
  });
356
- hooks.callHook("entries:updated", head);
372
+ triggerUpdate();
373
+ const queueSideEffects = (e) => {
374
+ _sde = { ..._sde, ...e._sde || {} };
375
+ e._sde = {};
376
+ triggerUpdate();
377
+ };
357
378
  return {
358
379
  dispose() {
359
380
  entries = entries.filter((e) => {
360
381
  if (e._i !== _i)
361
382
  return true;
362
- _sde = { ..._sde, ...e._sde || {} };
363
- e._sde = {};
383
+ queueSideEffects(e);
364
384
  return false;
365
385
  });
366
- hooks.callHook("entries:updated", head);
367
386
  },
368
387
  patch(input2) {
369
388
  entries = entries.map((e) => {
370
389
  if (e._i === _i) {
371
- _sde = { ..._sde, ...e._sde || {} };
372
- e._sde = {};
390
+ queueSideEffects(e);
373
391
  e.input = e._i === _i ? input2 : e.input;
374
392
  }
375
393
  return e;
376
394
  });
377
- hooks.callHook("entries:updated", head);
378
395
  }
379
396
  };
380
397
  },
@@ -392,13 +409,9 @@ async function createHead(options = {}) {
392
409
  return resolveCtx.tags;
393
410
  }
394
411
  };
395
- await head.hooks.callHook("init", head);
412
+ head.hooks.callHook("init", head);
396
413
  setActiveHead(head);
397
414
  return head;
398
415
  }
399
416
 
400
- function defineHeadPlugin(plugin) {
401
- return plugin;
402
- }
403
-
404
- export { DedupesTagsPlugin, HydratesStatePlugin, SortTagsPlugin, TagConfigKeys, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, normaliseTag, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useServerHead, useStyle, useTitle, useTitleTemplate };
417
+ export { DedupesTagsPlugin, DeprecatedTagAttrPlugin, HydratesStatePlugin, SortTagsPlugin, TitleTemplatePlugin, activeHead, asArray, createHead, defineHeadPlugin, getActiveHead, normaliseEntryTags, setActiveHead, useBase, useBodyAttrs, useHead, useHtmlAttrs, useLink, useMeta, useNoscript, useScript, useServerHead, useStyle, useTitle, useTitleTemplate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unhead",
3
3
  "type": "module",
4
- "version": "0.1.3",
4
+ "version": "0.2.0",
5
5
  "packageManager": "pnpm@7.14.0",
6
6
  "author": "Harlan Wilton <harlan@harlanzw.com>",
7
7
  "license": "MIT",
@@ -30,11 +30,11 @@
30
30
  "dist"
31
31
  ],
32
32
  "dependencies": {
33
- "@unhead/schema": "0.1.3",
33
+ "@unhead/schema": "0.2.0",
34
34
  "hookable": "^5.4.1"
35
35
  },
36
36
  "devDependencies": {
37
- "zhead": "1.0.0-beta.4"
37
+ "zhead": "1.0.0-beta.8"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "unbuild .",