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 +101 -89
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +101 -88
- package/package.json +3 -3
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
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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):
|
|
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,
|
|
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
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
412
|
+
head.hooks.callHook("init", head);
|
|
396
413
|
setActiveHead(head);
|
|
397
414
|
return head;
|
|
398
415
|
}
|
|
399
416
|
|
|
400
|
-
|
|
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.
|
|
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.
|
|
33
|
+
"@unhead/schema": "0.2.0",
|
|
34
34
|
"hookable": "^5.4.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"zhead": "1.0.0-beta.
|
|
37
|
+
"zhead": "1.0.0-beta.8"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "unbuild .",
|