@unhead/shared 1.0.22
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/README.md +16 -0
- package/dist/index.cjs +130 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.mjs +118 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# `@unhead/schema`
|
|
2
|
+
|
|
3
|
+
Typescript definitions for document `<head>`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev @unhead/schema
|
|
9
|
+
|
|
10
|
+
# Using yarn
|
|
11
|
+
yarn add --dev @unhead/schema
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Types
|
|
15
|
+
|
|
16
|
+
See [head.ts](./src/head.ts) for the full list of types.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function asArray(value) {
|
|
4
|
+
return Array.isArray(value) ? value : [value];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const SelfClosingTags = ["meta", "link", "base"];
|
|
8
|
+
const TagsWithInnerContent = ["title", "script", "style", "noscript"];
|
|
9
|
+
const HasElementTags = [
|
|
10
|
+
"base",
|
|
11
|
+
"meta",
|
|
12
|
+
"link",
|
|
13
|
+
"style",
|
|
14
|
+
"script",
|
|
15
|
+
"noscript"
|
|
16
|
+
];
|
|
17
|
+
const ValidHeadTags = [
|
|
18
|
+
"title",
|
|
19
|
+
"titleTemplate",
|
|
20
|
+
"base",
|
|
21
|
+
"htmlAttrs",
|
|
22
|
+
"bodyAttrs",
|
|
23
|
+
"meta",
|
|
24
|
+
"link",
|
|
25
|
+
"style",
|
|
26
|
+
"script",
|
|
27
|
+
"noscript"
|
|
28
|
+
];
|
|
29
|
+
const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
|
|
30
|
+
const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
|
|
31
|
+
|
|
32
|
+
function tagDedupeKey(tag, fn) {
|
|
33
|
+
const { props, tag: tagName } = tag;
|
|
34
|
+
if (UniqueTags.includes(tagName))
|
|
35
|
+
return tagName;
|
|
36
|
+
if (tagName === "link" && props.rel === "canonical")
|
|
37
|
+
return "canonical";
|
|
38
|
+
if (props.charset)
|
|
39
|
+
return "charset";
|
|
40
|
+
const name = ["id"];
|
|
41
|
+
if (tagName === "meta")
|
|
42
|
+
name.push(...["name", "property", "http-equiv"]);
|
|
43
|
+
for (const n of name) {
|
|
44
|
+
if (typeof props[n] !== "undefined") {
|
|
45
|
+
const val = String(props[n]);
|
|
46
|
+
if (fn && !fn(val))
|
|
47
|
+
return false;
|
|
48
|
+
return `${tagName}:${n}:${val}`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const DedupesTagsPlugin = (options) => {
|
|
54
|
+
options = options || {};
|
|
55
|
+
const dedupeKeys = options.dedupeKeys || ["hid", "vmid", "key"];
|
|
56
|
+
return defineHeadPlugin({
|
|
57
|
+
hooks: {
|
|
58
|
+
"tag:normalise": function({ tag }) {
|
|
59
|
+
dedupeKeys.forEach((key) => {
|
|
60
|
+
if (tag.props[key]) {
|
|
61
|
+
tag.key = tag.props[key];
|
|
62
|
+
delete tag.props[key];
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
const dedupe = tag.key ? `${tag.tag}:${tag.key}` : tagDedupeKey(tag);
|
|
66
|
+
if (dedupe)
|
|
67
|
+
tag._d = dedupe;
|
|
68
|
+
},
|
|
69
|
+
"tags:resolve": function(ctx) {
|
|
70
|
+
const deduping = {};
|
|
71
|
+
ctx.tags.forEach((tag) => {
|
|
72
|
+
let dedupeKey = tag._d || tag._p;
|
|
73
|
+
const dupedTag = deduping[dedupeKey];
|
|
74
|
+
if (dupedTag) {
|
|
75
|
+
let strategy = tag?.tagDuplicateStrategy;
|
|
76
|
+
if (!strategy && (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"))
|
|
77
|
+
strategy = "merge";
|
|
78
|
+
if (strategy === "merge") {
|
|
79
|
+
const oldProps = dupedTag.props;
|
|
80
|
+
["class", "style"].forEach((key) => {
|
|
81
|
+
if (tag.props[key] && oldProps[key]) {
|
|
82
|
+
if (key === "style" && !oldProps[key].endsWith(";"))
|
|
83
|
+
oldProps[key] += ";";
|
|
84
|
+
tag.props[key] = `${oldProps[key]} ${tag.props[key]}`;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
deduping[dedupeKey].props = {
|
|
88
|
+
...oldProps,
|
|
89
|
+
...tag.props
|
|
90
|
+
};
|
|
91
|
+
return;
|
|
92
|
+
} else if (tag._e === dupedTag._e) {
|
|
93
|
+
dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
|
|
94
|
+
}
|
|
95
|
+
const propCount = Object.keys(tag.props).length;
|
|
96
|
+
if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
|
|
97
|
+
delete deduping[dedupeKey];
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
deduping[dedupeKey] = tag;
|
|
102
|
+
});
|
|
103
|
+
ctx.tags = Object.values(deduping);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
function defineHeadPlugin(plugin) {
|
|
110
|
+
return plugin;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function hashCode(s) {
|
|
114
|
+
let h = 9;
|
|
115
|
+
for (let i = 0; i < s.length; )
|
|
116
|
+
h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
|
|
117
|
+
return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 8).toLowerCase();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
exports.DedupesTagsPlugin = DedupesTagsPlugin;
|
|
121
|
+
exports.HasElementTags = HasElementTags;
|
|
122
|
+
exports.SelfClosingTags = SelfClosingTags;
|
|
123
|
+
exports.TagConfigKeys = TagConfigKeys;
|
|
124
|
+
exports.TagsWithInnerContent = TagsWithInnerContent;
|
|
125
|
+
exports.UniqueTags = UniqueTags;
|
|
126
|
+
exports.ValidHeadTags = ValidHeadTags;
|
|
127
|
+
exports.asArray = asArray;
|
|
128
|
+
exports.defineHeadPlugin = defineHeadPlugin;
|
|
129
|
+
exports.hashCode = hashCode;
|
|
130
|
+
exports.tagDedupeKey = tagDedupeKey;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as _unhead_schema from '@unhead/schema';
|
|
2
|
+
import { HeadPlugin } from '@unhead/schema';
|
|
3
|
+
import { HeadTag } from '@unhead/schema/dist';
|
|
4
|
+
|
|
5
|
+
type Arrayable<T> = T | Array<T>;
|
|
6
|
+
declare function asArray<T>(value: Arrayable<T>): T[];
|
|
7
|
+
|
|
8
|
+
declare const SelfClosingTags: string[];
|
|
9
|
+
declare const TagsWithInnerContent: string[];
|
|
10
|
+
declare const HasElementTags: string[];
|
|
11
|
+
declare const ValidHeadTags: string[];
|
|
12
|
+
declare const UniqueTags: string[];
|
|
13
|
+
declare const TagConfigKeys: string[];
|
|
14
|
+
|
|
15
|
+
interface DedupesTagsPluginOptions {
|
|
16
|
+
dedupeKeys?: string[];
|
|
17
|
+
}
|
|
18
|
+
declare function tagDedupeKey<T extends HeadTag>(tag: T, fn?: (key: string) => boolean): string | false;
|
|
19
|
+
declare const DedupesTagsPlugin: (options?: DedupesTagsPluginOptions) => _unhead_schema.HeadPlugin;
|
|
20
|
+
|
|
21
|
+
declare function defineHeadPlugin(plugin: HeadPlugin): HeadPlugin;
|
|
22
|
+
|
|
23
|
+
declare function hashCode(s: string): string;
|
|
24
|
+
|
|
25
|
+
export { Arrayable, DedupesTagsPlugin, DedupesTagsPluginOptions, HasElementTags, SelfClosingTags, TagConfigKeys, TagsWithInnerContent, UniqueTags, ValidHeadTags, asArray, defineHeadPlugin, hashCode, tagDedupeKey };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
function asArray(value) {
|
|
2
|
+
return Array.isArray(value) ? value : [value];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const SelfClosingTags = ["meta", "link", "base"];
|
|
6
|
+
const TagsWithInnerContent = ["title", "script", "style", "noscript"];
|
|
7
|
+
const HasElementTags = [
|
|
8
|
+
"base",
|
|
9
|
+
"meta",
|
|
10
|
+
"link",
|
|
11
|
+
"style",
|
|
12
|
+
"script",
|
|
13
|
+
"noscript"
|
|
14
|
+
];
|
|
15
|
+
const ValidHeadTags = [
|
|
16
|
+
"title",
|
|
17
|
+
"titleTemplate",
|
|
18
|
+
"base",
|
|
19
|
+
"htmlAttrs",
|
|
20
|
+
"bodyAttrs",
|
|
21
|
+
"meta",
|
|
22
|
+
"link",
|
|
23
|
+
"style",
|
|
24
|
+
"script",
|
|
25
|
+
"noscript"
|
|
26
|
+
];
|
|
27
|
+
const UniqueTags = ["base", "title", "titleTemplate", "bodyAttrs", "htmlAttrs"];
|
|
28
|
+
const TagConfigKeys = ["tagPosition", "tagPriority", "tagDuplicateStrategy"];
|
|
29
|
+
|
|
30
|
+
function tagDedupeKey(tag, fn) {
|
|
31
|
+
const { props, tag: tagName } = tag;
|
|
32
|
+
if (UniqueTags.includes(tagName))
|
|
33
|
+
return tagName;
|
|
34
|
+
if (tagName === "link" && props.rel === "canonical")
|
|
35
|
+
return "canonical";
|
|
36
|
+
if (props.charset)
|
|
37
|
+
return "charset";
|
|
38
|
+
const name = ["id"];
|
|
39
|
+
if (tagName === "meta")
|
|
40
|
+
name.push(...["name", "property", "http-equiv"]);
|
|
41
|
+
for (const n of name) {
|
|
42
|
+
if (typeof props[n] !== "undefined") {
|
|
43
|
+
const val = String(props[n]);
|
|
44
|
+
if (fn && !fn(val))
|
|
45
|
+
return false;
|
|
46
|
+
return `${tagName}:${n}:${val}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const DedupesTagsPlugin = (options) => {
|
|
52
|
+
options = options || {};
|
|
53
|
+
const dedupeKeys = options.dedupeKeys || ["hid", "vmid", "key"];
|
|
54
|
+
return defineHeadPlugin({
|
|
55
|
+
hooks: {
|
|
56
|
+
"tag:normalise": function({ tag }) {
|
|
57
|
+
dedupeKeys.forEach((key) => {
|
|
58
|
+
if (tag.props[key]) {
|
|
59
|
+
tag.key = tag.props[key];
|
|
60
|
+
delete tag.props[key];
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const dedupe = tag.key ? `${tag.tag}:${tag.key}` : tagDedupeKey(tag);
|
|
64
|
+
if (dedupe)
|
|
65
|
+
tag._d = dedupe;
|
|
66
|
+
},
|
|
67
|
+
"tags:resolve": function(ctx) {
|
|
68
|
+
const deduping = {};
|
|
69
|
+
ctx.tags.forEach((tag) => {
|
|
70
|
+
let dedupeKey = tag._d || tag._p;
|
|
71
|
+
const dupedTag = deduping[dedupeKey];
|
|
72
|
+
if (dupedTag) {
|
|
73
|
+
let strategy = tag?.tagDuplicateStrategy;
|
|
74
|
+
if (!strategy && (tag.tag === "htmlAttrs" || tag.tag === "bodyAttrs"))
|
|
75
|
+
strategy = "merge";
|
|
76
|
+
if (strategy === "merge") {
|
|
77
|
+
const oldProps = dupedTag.props;
|
|
78
|
+
["class", "style"].forEach((key) => {
|
|
79
|
+
if (tag.props[key] && oldProps[key]) {
|
|
80
|
+
if (key === "style" && !oldProps[key].endsWith(";"))
|
|
81
|
+
oldProps[key] += ";";
|
|
82
|
+
tag.props[key] = `${oldProps[key]} ${tag.props[key]}`;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
deduping[dedupeKey].props = {
|
|
86
|
+
...oldProps,
|
|
87
|
+
...tag.props
|
|
88
|
+
};
|
|
89
|
+
return;
|
|
90
|
+
} else if (tag._e === dupedTag._e) {
|
|
91
|
+
dedupeKey = tag._d = `${dedupeKey}:${tag._p}`;
|
|
92
|
+
}
|
|
93
|
+
const propCount = Object.keys(tag.props).length;
|
|
94
|
+
if ((propCount === 0 || propCount === 1 && typeof tag.props["data-h-key"] !== "undefined") && !tag.children) {
|
|
95
|
+
delete deduping[dedupeKey];
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
deduping[dedupeKey] = tag;
|
|
100
|
+
});
|
|
101
|
+
ctx.tags = Object.values(deduping);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
function defineHeadPlugin(plugin) {
|
|
108
|
+
return plugin;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function hashCode(s) {
|
|
112
|
+
let h = 9;
|
|
113
|
+
for (let i = 0; i < s.length; )
|
|
114
|
+
h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9);
|
|
115
|
+
return ((h ^ h >>> 9) + 65536).toString(16).substring(1, 8).toLowerCase();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { DedupesTagsPlugin, HasElementTags, SelfClosingTags, TagConfigKeys, TagsWithInnerContent, UniqueTags, ValidHeadTags, asArray, defineHeadPlugin, hashCode, tagDedupeKey };
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unhead/shared",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.22",
|
|
5
|
+
"packageManager": "pnpm@7.26.3",
|
|
6
|
+
"author": "Harlan Wilton <harlan@harlanzw.com>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"funding": "https://github.com/sponsors/harlan-zw",
|
|
9
|
+
"homepage": "https://unhead.harlanzw.com",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/unjs/unhead.git",
|
|
13
|
+
"directory": "packages/schema"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/unjs/unhead/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"head",
|
|
20
|
+
"meta tags",
|
|
21
|
+
"types"
|
|
22
|
+
],
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"require": "./dist/index.cjs",
|
|
28
|
+
"import": "./dist/index.mjs"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"main": "dist/index.cjs",
|
|
32
|
+
"module": "dist/index.mjs",
|
|
33
|
+
"types": "dist/index.d.ts",
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@unhead/schema": "1.0.22"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "unbuild .",
|
|
42
|
+
"stub": "unbuild . --stub"
|
|
43
|
+
}
|
|
44
|
+
}
|