@ubean/seo 0.1.2 → 0.1.3
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.d.ts +110 -0
- package/dist/index.js +272 -0
- package/package.json +1 -1
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { UseSeoMetaInput } from "@unhead/vue";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
interface RobotsOptions {
|
|
4
|
+
userAgent?: string;
|
|
5
|
+
allow?: string | string[];
|
|
6
|
+
disallow?: string | string[];
|
|
7
|
+
sitemap?: string | string[];
|
|
8
|
+
crawlDelay?: number;
|
|
9
|
+
}
|
|
10
|
+
interface SitemapUrl {
|
|
11
|
+
loc: string;
|
|
12
|
+
lastmod?: string | Date;
|
|
13
|
+
changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
|
|
14
|
+
priority?: number;
|
|
15
|
+
}
|
|
16
|
+
interface MetaTag {
|
|
17
|
+
name?: string;
|
|
18
|
+
property?: string;
|
|
19
|
+
content: string;
|
|
20
|
+
}
|
|
21
|
+
interface LinkTag {
|
|
22
|
+
rel: string;
|
|
23
|
+
href: string;
|
|
24
|
+
hreflang?: string;
|
|
25
|
+
type?: string;
|
|
26
|
+
sizes?: string;
|
|
27
|
+
media?: string;
|
|
28
|
+
as?: string;
|
|
29
|
+
crossorigin?: '' | 'anonymous' | 'use-credentials';
|
|
30
|
+
}
|
|
31
|
+
interface OpenGraphMeta {
|
|
32
|
+
title?: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
type?: 'website' | 'article' | 'book' | 'profile' | 'music.song' | 'music.album' | 'video.movie';
|
|
35
|
+
url?: string;
|
|
36
|
+
image?: string | OGImage;
|
|
37
|
+
siteName?: string;
|
|
38
|
+
locale?: string;
|
|
39
|
+
localeAlternate?: string[];
|
|
40
|
+
}
|
|
41
|
+
interface OGImage {
|
|
42
|
+
url: string;
|
|
43
|
+
width?: number;
|
|
44
|
+
height?: number;
|
|
45
|
+
alt?: string;
|
|
46
|
+
type?: string;
|
|
47
|
+
}
|
|
48
|
+
interface TwitterMeta {
|
|
49
|
+
card?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
50
|
+
site?: string;
|
|
51
|
+
creator?: string;
|
|
52
|
+
title?: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
image?: string;
|
|
55
|
+
}
|
|
56
|
+
interface SeoMetadata {
|
|
57
|
+
title?: string;
|
|
58
|
+
titleTemplate?: string | ((title: string) => string);
|
|
59
|
+
description?: string;
|
|
60
|
+
keywords?: string | string[];
|
|
61
|
+
author?: string;
|
|
62
|
+
canonical?: string;
|
|
63
|
+
robots?: string | {
|
|
64
|
+
index?: boolean;
|
|
65
|
+
follow?: boolean;
|
|
66
|
+
};
|
|
67
|
+
openGraph?: OpenGraphMeta;
|
|
68
|
+
twitter?: TwitterMeta;
|
|
69
|
+
meta?: MetaTag[];
|
|
70
|
+
link?: LinkTag[];
|
|
71
|
+
htmlAttrs?: Record<string, string>;
|
|
72
|
+
bodyAttrs?: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
interface ManifestIcon {
|
|
75
|
+
src: string;
|
|
76
|
+
sizes: string;
|
|
77
|
+
type: string;
|
|
78
|
+
purpose?: string;
|
|
79
|
+
}
|
|
80
|
+
interface WebAppManifest {
|
|
81
|
+
name?: string;
|
|
82
|
+
short_name?: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
start_url?: string;
|
|
85
|
+
display?: 'fullscreen' | 'standalone' | 'minimal-ui' | 'browser';
|
|
86
|
+
background_color?: string;
|
|
87
|
+
theme_color?: string;
|
|
88
|
+
orientation?: 'portrait' | 'landscape' | 'any';
|
|
89
|
+
icons?: ManifestIcon[];
|
|
90
|
+
scope?: string;
|
|
91
|
+
lang?: string;
|
|
92
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
93
|
+
}
|
|
94
|
+
declare function useSeoMeta<T extends Record<string, any>>(meta: T): T;
|
|
95
|
+
declare function mergeMetadata(...metadatas: (SeoMetadata | undefined | null)[]): SeoMetadata;
|
|
96
|
+
declare function buildMetaTags(meta: SeoMetadata): MetaTag[];
|
|
97
|
+
declare function buildLinkTags(meta: SeoMetadata): LinkTag[];
|
|
98
|
+
declare function buildTitle(meta: SeoMetadata, fallbackTitle?: string): string;
|
|
99
|
+
declare function renderHeadTags(meta: SeoMetadata, fallbackTitle?: string): string;
|
|
100
|
+
declare function createManifestResponse(manifest: WebAppManifest): Response;
|
|
101
|
+
declare function defineManifest(manifest: WebAppManifest): WebAppManifest;
|
|
102
|
+
declare function formatRobotsTxt(options: RobotsOptions[] | RobotsOptions): string;
|
|
103
|
+
declare function escapeXml(str: string): string;
|
|
104
|
+
declare function formatSitemapXml(urls: SitemapUrl[]): string;
|
|
105
|
+
declare function createRobotsResponse(options: RobotsOptions[] | RobotsOptions): Response;
|
|
106
|
+
declare function createSitemapResponse(urls: SitemapUrl[]): Response;
|
|
107
|
+
declare function defineRobotsConfig(config: RobotsOptions[] | RobotsOptions): RobotsOptions[] | RobotsOptions;
|
|
108
|
+
declare function defineSitemapConfig(urls: SitemapUrl[] | (() => SitemapUrl[] | Promise<SitemapUrl[]>)): SitemapUrl[] | (() => SitemapUrl[] | Promise<SitemapUrl[]>);
|
|
109
|
+
//#endregion
|
|
110
|
+
export { LinkTag, ManifestIcon, MetaTag, OGImage, OpenGraphMeta, RobotsOptions, SeoMetadata, SitemapUrl, TwitterMeta, type UseSeoMetaInput, WebAppManifest, buildLinkTags, buildMetaTags, buildTitle, createManifestResponse, createRobotsResponse, createSitemapResponse, defineManifest, defineRobotsConfig, defineSitemapConfig, escapeXml, formatRobotsTxt, formatSitemapXml, mergeMetadata, renderHeadTags, useSeoMeta };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { useSeoMeta as useSeoMeta$1 } from "@unhead/vue";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
function useSeoMeta(meta) {
|
|
4
|
+
try {
|
|
5
|
+
useSeoMeta$1(meta);
|
|
6
|
+
} catch {}
|
|
7
|
+
return meta;
|
|
8
|
+
}
|
|
9
|
+
function mergeMetadata(...metadatas) {
|
|
10
|
+
const result = {};
|
|
11
|
+
for (const meta of metadatas) {
|
|
12
|
+
if (!meta) continue;
|
|
13
|
+
if (meta.title !== void 0) result.title = meta.title;
|
|
14
|
+
if (meta.titleTemplate !== void 0) result.titleTemplate = meta.titleTemplate;
|
|
15
|
+
if (meta.description !== void 0) result.description = meta.description;
|
|
16
|
+
if (meta.keywords !== void 0) result.keywords = meta.keywords;
|
|
17
|
+
if (meta.author !== void 0) result.author = meta.author;
|
|
18
|
+
if (meta.canonical !== void 0) result.canonical = meta.canonical;
|
|
19
|
+
if (meta.robots !== void 0) result.robots = meta.robots;
|
|
20
|
+
if (meta.htmlAttrs) result.htmlAttrs = {
|
|
21
|
+
...result.htmlAttrs,
|
|
22
|
+
...meta.htmlAttrs
|
|
23
|
+
};
|
|
24
|
+
if (meta.bodyAttrs) result.bodyAttrs = {
|
|
25
|
+
...result.bodyAttrs,
|
|
26
|
+
...meta.bodyAttrs
|
|
27
|
+
};
|
|
28
|
+
if (meta.openGraph) result.openGraph = {
|
|
29
|
+
...result.openGraph,
|
|
30
|
+
...meta.openGraph
|
|
31
|
+
};
|
|
32
|
+
if (meta.twitter) result.twitter = {
|
|
33
|
+
...result.twitter,
|
|
34
|
+
...meta.twitter
|
|
35
|
+
};
|
|
36
|
+
if (meta.meta) result.meta = [...result.meta || [], ...meta.meta];
|
|
37
|
+
if (meta.link) result.link = [...result.link || [], ...meta.link];
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
function buildMetaTags(meta) {
|
|
42
|
+
const tags = [];
|
|
43
|
+
if (meta.description) tags.push({
|
|
44
|
+
name: "description",
|
|
45
|
+
content: meta.description
|
|
46
|
+
});
|
|
47
|
+
if (meta.keywords) {
|
|
48
|
+
const kws = Array.isArray(meta.keywords) ? meta.keywords.join(", ") : meta.keywords;
|
|
49
|
+
tags.push({
|
|
50
|
+
name: "keywords",
|
|
51
|
+
content: kws
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (meta.author) tags.push({
|
|
55
|
+
name: "author",
|
|
56
|
+
content: meta.author
|
|
57
|
+
});
|
|
58
|
+
if (meta.robots) {
|
|
59
|
+
let robotsValue;
|
|
60
|
+
if (typeof meta.robots === "string") robotsValue = meta.robots;
|
|
61
|
+
else {
|
|
62
|
+
const parts = [];
|
|
63
|
+
if (meta.robots.index !== void 0) parts.push(meta.robots.index ? "index" : "noindex");
|
|
64
|
+
if (meta.robots.follow !== void 0) parts.push(meta.robots.follow ? "follow" : "nofollow");
|
|
65
|
+
robotsValue = parts.join(", ");
|
|
66
|
+
}
|
|
67
|
+
if (robotsValue) tags.push({
|
|
68
|
+
name: "robots",
|
|
69
|
+
content: robotsValue
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (meta.openGraph) {
|
|
73
|
+
const og = meta.openGraph;
|
|
74
|
+
if (og.title) tags.push({
|
|
75
|
+
property: "og:title",
|
|
76
|
+
content: og.title
|
|
77
|
+
});
|
|
78
|
+
if (og.description) tags.push({
|
|
79
|
+
property: "og:description",
|
|
80
|
+
content: og.description
|
|
81
|
+
});
|
|
82
|
+
if (og.type) tags.push({
|
|
83
|
+
property: "og:type",
|
|
84
|
+
content: og.type
|
|
85
|
+
});
|
|
86
|
+
if (og.url) tags.push({
|
|
87
|
+
property: "og:url",
|
|
88
|
+
content: og.url
|
|
89
|
+
});
|
|
90
|
+
if (og.siteName) tags.push({
|
|
91
|
+
property: "og:site_name",
|
|
92
|
+
content: og.siteName
|
|
93
|
+
});
|
|
94
|
+
if (og.locale) tags.push({
|
|
95
|
+
property: "og:locale",
|
|
96
|
+
content: og.locale
|
|
97
|
+
});
|
|
98
|
+
if (og.localeAlternate) for (const loc of og.localeAlternate) tags.push({
|
|
99
|
+
property: "og:locale:alternate",
|
|
100
|
+
content: loc
|
|
101
|
+
});
|
|
102
|
+
if (og.image) if (typeof og.image === "string") tags.push({
|
|
103
|
+
property: "og:image",
|
|
104
|
+
content: og.image
|
|
105
|
+
});
|
|
106
|
+
else {
|
|
107
|
+
tags.push({
|
|
108
|
+
property: "og:image",
|
|
109
|
+
content: og.image.url
|
|
110
|
+
});
|
|
111
|
+
if (og.image.width) tags.push({
|
|
112
|
+
property: "og:image:width",
|
|
113
|
+
content: String(og.image.width)
|
|
114
|
+
});
|
|
115
|
+
if (og.image.height) tags.push({
|
|
116
|
+
property: "og:image:height",
|
|
117
|
+
content: String(og.image.height)
|
|
118
|
+
});
|
|
119
|
+
if (og.image.alt) tags.push({
|
|
120
|
+
property: "og:image:alt",
|
|
121
|
+
content: og.image.alt
|
|
122
|
+
});
|
|
123
|
+
if (og.image.type) tags.push({
|
|
124
|
+
property: "og:image:type",
|
|
125
|
+
content: og.image.type
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (meta.twitter) {
|
|
130
|
+
const tw = meta.twitter;
|
|
131
|
+
if (tw.card) tags.push({
|
|
132
|
+
name: "twitter:card",
|
|
133
|
+
content: tw.card
|
|
134
|
+
});
|
|
135
|
+
if (tw.site) tags.push({
|
|
136
|
+
name: "twitter:site",
|
|
137
|
+
content: tw.site
|
|
138
|
+
});
|
|
139
|
+
if (tw.creator) tags.push({
|
|
140
|
+
name: "twitter:creator",
|
|
141
|
+
content: tw.creator
|
|
142
|
+
});
|
|
143
|
+
if (tw.title) tags.push({
|
|
144
|
+
name: "twitter:title",
|
|
145
|
+
content: tw.title
|
|
146
|
+
});
|
|
147
|
+
if (tw.description) tags.push({
|
|
148
|
+
name: "twitter:description",
|
|
149
|
+
content: tw.description
|
|
150
|
+
});
|
|
151
|
+
if (tw.image) tags.push({
|
|
152
|
+
name: "twitter:image",
|
|
153
|
+
content: tw.image
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (meta.meta) tags.push(...meta.meta);
|
|
157
|
+
return tags;
|
|
158
|
+
}
|
|
159
|
+
function buildLinkTags(meta) {
|
|
160
|
+
const links = [];
|
|
161
|
+
if (meta.canonical) links.push({
|
|
162
|
+
rel: "canonical",
|
|
163
|
+
href: meta.canonical
|
|
164
|
+
});
|
|
165
|
+
if (meta.link) links.push(...meta.link);
|
|
166
|
+
return links;
|
|
167
|
+
}
|
|
168
|
+
function buildTitle(meta, fallbackTitle) {
|
|
169
|
+
let title = meta.title || fallbackTitle || "";
|
|
170
|
+
if (meta.titleTemplate && title) if (typeof meta.titleTemplate === "function") title = meta.titleTemplate(title);
|
|
171
|
+
else title = meta.titleTemplate.replace("%s", title);
|
|
172
|
+
return title;
|
|
173
|
+
}
|
|
174
|
+
function renderHeadTags(meta, fallbackTitle) {
|
|
175
|
+
const parts = [];
|
|
176
|
+
const title = buildTitle(meta, fallbackTitle);
|
|
177
|
+
if (title) parts.push(`<title>${escapeHtml(title)}</title>`);
|
|
178
|
+
const metaTags = buildMetaTags(meta);
|
|
179
|
+
for (const tag of metaTags) if (tag.name) parts.push(`<meta name="${escapeHtml(tag.name)}" content="${escapeHtml(tag.content)}">`);
|
|
180
|
+
else if (tag.property) parts.push(`<meta property="${escapeHtml(tag.property)}" content="${escapeHtml(tag.content)}">`);
|
|
181
|
+
const linkTags = buildLinkTags(meta);
|
|
182
|
+
for (const link of linkTags) {
|
|
183
|
+
const attrs = [`rel="${escapeHtml(link.rel)}"`, `href="${escapeHtml(link.href)}"`];
|
|
184
|
+
if (link.hreflang) attrs.push(`hreflang="${escapeHtml(link.hreflang)}"`);
|
|
185
|
+
if (link.type) attrs.push(`type="${escapeHtml(link.type)}"`);
|
|
186
|
+
if (link.sizes) attrs.push(`sizes="${escapeHtml(link.sizes)}"`);
|
|
187
|
+
if (link.media) attrs.push(`media="${escapeHtml(link.media)}"`);
|
|
188
|
+
if (link.as) attrs.push(`as="${escapeHtml(link.as)}"`);
|
|
189
|
+
if (link.crossorigin !== void 0) attrs.push(link.crossorigin ? `crossorigin="${escapeHtml(link.crossorigin)}"` : "crossorigin");
|
|
190
|
+
parts.push(`<link ${attrs.join(" ")}>`);
|
|
191
|
+
}
|
|
192
|
+
return parts.join("\n");
|
|
193
|
+
}
|
|
194
|
+
function createManifestResponse(manifest) {
|
|
195
|
+
return new Response(JSON.stringify(manifest, null, 2), { headers: {
|
|
196
|
+
"Content-Type": "application/manifest+json; charset=utf-8",
|
|
197
|
+
"Cache-Control": "public, max-age=86400"
|
|
198
|
+
} });
|
|
199
|
+
}
|
|
200
|
+
function defineManifest(manifest) {
|
|
201
|
+
return manifest;
|
|
202
|
+
}
|
|
203
|
+
function escapeHtml(str) {
|
|
204
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
205
|
+
}
|
|
206
|
+
function formatRobotsTxt(options) {
|
|
207
|
+
const groups = Array.isArray(options) ? options : [options];
|
|
208
|
+
const lines = [];
|
|
209
|
+
for (const group of groups) {
|
|
210
|
+
lines.push(`User-agent: ${group.userAgent || "*"}`);
|
|
211
|
+
if (group.allow) {
|
|
212
|
+
const allows = Array.isArray(group.allow) ? group.allow : [group.allow];
|
|
213
|
+
for (const path of allows) lines.push(`Allow: ${path}`);
|
|
214
|
+
}
|
|
215
|
+
if (group.disallow) {
|
|
216
|
+
const disallows = Array.isArray(group.disallow) ? group.disallow : [group.disallow];
|
|
217
|
+
for (const path of disallows) lines.push(`Disallow: ${path}`);
|
|
218
|
+
}
|
|
219
|
+
if (group.crawlDelay !== void 0) lines.push(`Crawl-delay: ${group.crawlDelay}`);
|
|
220
|
+
lines.push("");
|
|
221
|
+
}
|
|
222
|
+
const sitemaps = /* @__PURE__ */ new Set();
|
|
223
|
+
for (const group of groups) if (group.sitemap) {
|
|
224
|
+
const maps = Array.isArray(group.sitemap) ? group.sitemap : [group.sitemap];
|
|
225
|
+
for (const url of maps) sitemaps.add(url);
|
|
226
|
+
}
|
|
227
|
+
for (const sitemap of sitemaps) lines.push(`Sitemap: ${sitemap}`);
|
|
228
|
+
return `${lines.join("\n").trim()}\n`;
|
|
229
|
+
}
|
|
230
|
+
function escapeXml(str) {
|
|
231
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
232
|
+
}
|
|
233
|
+
function formatDate(date) {
|
|
234
|
+
if (date instanceof Date) return date.toISOString().split("T")[0];
|
|
235
|
+
return date;
|
|
236
|
+
}
|
|
237
|
+
function formatSitemapXml(urls) {
|
|
238
|
+
const lines = ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>"];
|
|
239
|
+
lines.push("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">");
|
|
240
|
+
for (const url of urls) {
|
|
241
|
+
lines.push(" <url>");
|
|
242
|
+
lines.push(` <loc>${escapeXml(url.loc)}</loc>`);
|
|
243
|
+
if (url.lastmod) lines.push(` <lastmod>${escapeXml(formatDate(url.lastmod))}</lastmod>`);
|
|
244
|
+
if (url.changefreq) lines.push(` <changefreq>${url.changefreq}</changefreq>`);
|
|
245
|
+
if (url.priority !== void 0) lines.push(` <priority>${url.priority.toFixed(1)}</priority>`);
|
|
246
|
+
lines.push(" </url>");
|
|
247
|
+
}
|
|
248
|
+
lines.push("</urlset>");
|
|
249
|
+
return lines.join("\n");
|
|
250
|
+
}
|
|
251
|
+
function createRobotsResponse(options) {
|
|
252
|
+
const body = formatRobotsTxt(options);
|
|
253
|
+
return new Response(body, { headers: {
|
|
254
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
255
|
+
"Cache-Control": "public, max-age=3600"
|
|
256
|
+
} });
|
|
257
|
+
}
|
|
258
|
+
function createSitemapResponse(urls) {
|
|
259
|
+
const body = formatSitemapXml(urls);
|
|
260
|
+
return new Response(body, { headers: {
|
|
261
|
+
"Content-Type": "application/xml; charset=utf-8",
|
|
262
|
+
"Cache-Control": "public, max-age=3600"
|
|
263
|
+
} });
|
|
264
|
+
}
|
|
265
|
+
function defineRobotsConfig(config) {
|
|
266
|
+
return config;
|
|
267
|
+
}
|
|
268
|
+
function defineSitemapConfig(urls) {
|
|
269
|
+
return urls;
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
export { buildLinkTags, buildMetaTags, buildTitle, createManifestResponse, createRobotsResponse, createSitemapResponse, defineManifest, defineRobotsConfig, defineSitemapConfig, escapeXml, formatRobotsTxt, formatSitemapXml, mergeMetadata, renderHeadTags, useSeoMeta };
|