@lytjs/metadata 6.6.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/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # @lytjs/metadata
2
+
3
+ > LytJS 元数据管理系统。
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@lytjs/metadata.svg)](https://www.npmjs.com/package/@lytjs/metadata)
6
+ [![license](https://img.shields.io/npm/l/@lytjs/metadata.svg)](https://gitee.com/lytjs/lytjs/blob/main/LICENSE)
7
+
8
+ ## 简介
9
+
10
+ `@lytjs/metadata` 是 LytJS 框架的元数据管理系统,支持 HTML meta 标签、OpenGraph、Twitter Cards 等。
11
+
12
+ ### 核心特性
13
+
14
+ - **链式 API**:流畅的链式调用方式
15
+ - **OpenGraph 支持**:完整的 OpenGraph 元数据
16
+ - **Twitter Cards 支持**:支持 Twitter 卡片
17
+ - **SEO 优化**:自动处理 SEO 相关元数据
18
+ - **零依赖**:不引入任何外部依赖
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ npm install @lytjs/metadata
24
+ ```
25
+
26
+ 或使用 pnpm:
27
+
28
+ ```bash
29
+ pnpm add @lytjs/metadata
30
+ ```
31
+
32
+ ## 许可证
33
+
34
+ MIT License - [查看许可证](https://gitee.com/lytjs/lytjs/blob/main/LICENSE)
35
+
36
+ ## 贡献指南
37
+
38
+ 欢迎提交 Issue 和 Pull Request!
39
+
40
+ - [Gitee 仓库](https://gitee.com/lytjs/lytjs)
41
+ - [问题反馈](https://gitee.com/lytjs/lytjs/issues)
package/dist/index.cjs ADDED
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ var commonString = require('@lytjs/common-string');
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
8
+
9
+ // src/builder.ts
10
+ var MetadataBuilder = class {
11
+ constructor() {
12
+ /** 元数据对象 */
13
+ __publicField(this, "metadata", {});
14
+ }
15
+ /**
16
+ * 设置标题
17
+ *
18
+ * @param title - 标题
19
+ * @returns 构建器实例
20
+ */
21
+ title(title) {
22
+ this.metadata.title = title;
23
+ return this;
24
+ }
25
+ /**
26
+ * 设置描述
27
+ *
28
+ * @param description - 描述
29
+ * @returns 构建器实例
30
+ */
31
+ description(description) {
32
+ this.metadata.description = description;
33
+ return this;
34
+ }
35
+ /**
36
+ * 设置关键词
37
+ *
38
+ * @param keywords - 关键词数组
39
+ * @returns 构建器实例
40
+ */
41
+ keywords(keywords) {
42
+ this.metadata.keywords = keywords;
43
+ return this;
44
+ }
45
+ /**
46
+ * 设置 Open Graph 元数据
47
+ *
48
+ * @param og - Open Graph 元数据
49
+ * @returns 构建器实例
50
+ */
51
+ openGraph(og) {
52
+ this.metadata.openGraph = { ...this.metadata.openGraph, ...og };
53
+ return this;
54
+ }
55
+ /**
56
+ * 设置 Twitter 元数据
57
+ *
58
+ * @param twitter - Twitter 元数据
59
+ * @returns 构建器实例
60
+ */
61
+ twitter(twitter) {
62
+ this.metadata.twitter = { ...this.metadata.twitter, ...twitter };
63
+ return this;
64
+ }
65
+ /**
66
+ * 设置自定义属性
67
+ *
68
+ * @param key - 键
69
+ * @param value - 值
70
+ * @returns 构建器实例
71
+ */
72
+ set(key, value) {
73
+ this.metadata[key] = value;
74
+ return this;
75
+ }
76
+ /**
77
+ * 构建元数据
78
+ *
79
+ * @returns 元数据对象
80
+ */
81
+ build() {
82
+ return { ...this.metadata };
83
+ }
84
+ };
85
+ function createMetadataBuilder() {
86
+ return new MetadataBuilder();
87
+ }
88
+ function renderMetadata(metadata) {
89
+ const tags = [];
90
+ if (metadata.title) {
91
+ tags.push(`<title>${commonString.escapeHTML(metadata.title)}</title>`);
92
+ }
93
+ if (metadata.description) {
94
+ tags.push(`<meta name="description" content="${commonString.escapeHTML(metadata.description)}">`);
95
+ }
96
+ if (metadata.keywords && metadata.keywords.length > 0) {
97
+ tags.push(`<meta name="keywords" content="${commonString.escapeHTML(metadata.keywords.join(", "))}">`);
98
+ }
99
+ if (metadata.openGraph) {
100
+ for (const [key, value] of Object.entries(metadata.openGraph)) {
101
+ if (value) {
102
+ tags.push(`<meta property="og:${key}" content="${commonString.escapeHTML(String(value))}">`);
103
+ }
104
+ }
105
+ }
106
+ if (metadata.twitter) {
107
+ for (const [key, value] of Object.entries(metadata.twitter)) {
108
+ if (value) {
109
+ tags.push(`<meta name="twitter:${key}" content="${commonString.escapeHTML(String(value))}">`);
110
+ }
111
+ }
112
+ }
113
+ return tags.join("\n");
114
+ }
115
+
116
+ exports.MetadataBuilder = MetadataBuilder;
117
+ exports.createMetadataBuilder = createMetadataBuilder;
118
+ exports.renderMetadata = renderMetadata;
119
+ //# sourceMappingURL=index.cjs.map
120
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/builder.ts","../src/renderer.ts"],"names":["escapeHTML"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * 元数据构建器\n */\nimport type { Metadata, OpenGraphMetadata, TwitterMetadata } from '@lytjs/shared-types';\n\n/**\n * 元数据构建器类\n */\nexport class MetadataBuilder {\n /** 元数据对象 */\n private metadata: Metadata = {};\n\n /**\n * 设置标题\n *\n * @param title - 标题\n * @returns 构建器实例\n */\n title(title: string): this {\n this.metadata.title = title;\n return this;\n }\n\n /**\n * 设置描述\n *\n * @param description - 描述\n * @returns 构建器实例\n */\n description(description: string): this {\n this.metadata.description = description;\n return this;\n }\n\n /**\n * 设置关键词\n *\n * @param keywords - 关键词数组\n * @returns 构建器实例\n */\n keywords(keywords: string[]): this {\n this.metadata.keywords = keywords;\n return this;\n }\n\n /**\n * 设置 Open Graph 元数据\n *\n * @param og - Open Graph 元数据\n * @returns 构建器实例\n */\n openGraph(og: OpenGraphMetadata): this {\n this.metadata.openGraph = { ...this.metadata.openGraph, ...og };\n return this;\n }\n\n /**\n * 设置 Twitter 元数据\n *\n * @param twitter - Twitter 元数据\n * @returns 构建器实例\n */\n twitter(twitter: TwitterMetadata): this {\n this.metadata.twitter = { ...this.metadata.twitter, ...twitter };\n return this;\n }\n\n /**\n * 设置自定义属性\n *\n * @param key - 键\n * @param value - 值\n * @returns 构建器实例\n */\n set(key: string, value: unknown): this {\n this.metadata[key] = value;\n return this;\n }\n\n /**\n * 构建元数据\n *\n * @returns 元数据对象\n */\n build(): Metadata {\n return { ...this.metadata };\n }\n}\n\n/**\n * 创建元数据构建器\n *\n * @returns 构建器实例\n */\nexport function createMetadataBuilder(): MetadataBuilder {\n return new MetadataBuilder();\n}\n","/**\n * 元数据渲染器\n */\nimport type { Metadata } from '@lytjs/shared-types';\nimport { escapeHTML } from '@lytjs/common-string';\n\n/**\n * 渲染元数据为 HTML 标签\n *\n * @param metadata - 元数据对象\n * @returns HTML 标签字符串\n */\nexport function renderMetadata(metadata: Metadata): string {\n const tags: string[] = [];\n\n if (metadata.title) {\n tags.push(`<title>${escapeHTML(metadata.title)}</title>`);\n }\n\n if (metadata.description) {\n tags.push(`<meta name=\"description\" content=\"${escapeHTML(metadata.description)}\">`);\n }\n\n if (metadata.keywords && metadata.keywords.length > 0) {\n tags.push(`<meta name=\"keywords\" content=\"${escapeHTML(metadata.keywords.join(', '))}\">`);\n }\n\n if (metadata.openGraph) {\n for (const [key, value] of Object.entries(metadata.openGraph)) {\n if (value) {\n tags.push(`<meta property=\"og:${key}\" content=\"${escapeHTML(String(value))}\">`);\n }\n }\n }\n\n if (metadata.twitter) {\n for (const [key, value] of Object.entries(metadata.twitter)) {\n if (value) {\n tags.push(`<meta name=\"twitter:${key}\" content=\"${escapeHTML(String(value))}\">`);\n }\n }\n }\n\n return tags.join('\\n');\n}\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,116 @@
1
+ import { escapeHTML } from '@lytjs/common-string';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
+ var __publicField = (obj, key, value) => __defNormalProp(obj, key + "" , value);
6
+
7
+ // src/builder.ts
8
+ var MetadataBuilder = class {
9
+ constructor() {
10
+ /** 元数据对象 */
11
+ __publicField(this, "metadata", {});
12
+ }
13
+ /**
14
+ * 设置标题
15
+ *
16
+ * @param title - 标题
17
+ * @returns 构建器实例
18
+ */
19
+ title(title) {
20
+ this.metadata.title = title;
21
+ return this;
22
+ }
23
+ /**
24
+ * 设置描述
25
+ *
26
+ * @param description - 描述
27
+ * @returns 构建器实例
28
+ */
29
+ description(description) {
30
+ this.metadata.description = description;
31
+ return this;
32
+ }
33
+ /**
34
+ * 设置关键词
35
+ *
36
+ * @param keywords - 关键词数组
37
+ * @returns 构建器实例
38
+ */
39
+ keywords(keywords) {
40
+ this.metadata.keywords = keywords;
41
+ return this;
42
+ }
43
+ /**
44
+ * 设置 Open Graph 元数据
45
+ *
46
+ * @param og - Open Graph 元数据
47
+ * @returns 构建器实例
48
+ */
49
+ openGraph(og) {
50
+ this.metadata.openGraph = { ...this.metadata.openGraph, ...og };
51
+ return this;
52
+ }
53
+ /**
54
+ * 设置 Twitter 元数据
55
+ *
56
+ * @param twitter - Twitter 元数据
57
+ * @returns 构建器实例
58
+ */
59
+ twitter(twitter) {
60
+ this.metadata.twitter = { ...this.metadata.twitter, ...twitter };
61
+ return this;
62
+ }
63
+ /**
64
+ * 设置自定义属性
65
+ *
66
+ * @param key - 键
67
+ * @param value - 值
68
+ * @returns 构建器实例
69
+ */
70
+ set(key, value) {
71
+ this.metadata[key] = value;
72
+ return this;
73
+ }
74
+ /**
75
+ * 构建元数据
76
+ *
77
+ * @returns 元数据对象
78
+ */
79
+ build() {
80
+ return { ...this.metadata };
81
+ }
82
+ };
83
+ function createMetadataBuilder() {
84
+ return new MetadataBuilder();
85
+ }
86
+ function renderMetadata(metadata) {
87
+ const tags = [];
88
+ if (metadata.title) {
89
+ tags.push(`<title>${escapeHTML(metadata.title)}</title>`);
90
+ }
91
+ if (metadata.description) {
92
+ tags.push(`<meta name="description" content="${escapeHTML(metadata.description)}">`);
93
+ }
94
+ if (metadata.keywords && metadata.keywords.length > 0) {
95
+ tags.push(`<meta name="keywords" content="${escapeHTML(metadata.keywords.join(", "))}">`);
96
+ }
97
+ if (metadata.openGraph) {
98
+ for (const [key, value] of Object.entries(metadata.openGraph)) {
99
+ if (value) {
100
+ tags.push(`<meta property="og:${key}" content="${escapeHTML(String(value))}">`);
101
+ }
102
+ }
103
+ }
104
+ if (metadata.twitter) {
105
+ for (const [key, value] of Object.entries(metadata.twitter)) {
106
+ if (value) {
107
+ tags.push(`<meta name="twitter:${key}" content="${escapeHTML(String(value))}">`);
108
+ }
109
+ }
110
+ }
111
+ return tags.join("\n");
112
+ }
113
+
114
+ export { MetadataBuilder, createMetadataBuilder, renderMetadata };
115
+ //# sourceMappingURL=index.mjs.map
116
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/builder.ts","../src/renderer.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * 元数据构建器\n */\nimport type { Metadata, OpenGraphMetadata, TwitterMetadata } from '@lytjs/shared-types';\n\n/**\n * 元数据构建器类\n */\nexport class MetadataBuilder {\n /** 元数据对象 */\n private metadata: Metadata = {};\n\n /**\n * 设置标题\n *\n * @param title - 标题\n * @returns 构建器实例\n */\n title(title: string): this {\n this.metadata.title = title;\n return this;\n }\n\n /**\n * 设置描述\n *\n * @param description - 描述\n * @returns 构建器实例\n */\n description(description: string): this {\n this.metadata.description = description;\n return this;\n }\n\n /**\n * 设置关键词\n *\n * @param keywords - 关键词数组\n * @returns 构建器实例\n */\n keywords(keywords: string[]): this {\n this.metadata.keywords = keywords;\n return this;\n }\n\n /**\n * 设置 Open Graph 元数据\n *\n * @param og - Open Graph 元数据\n * @returns 构建器实例\n */\n openGraph(og: OpenGraphMetadata): this {\n this.metadata.openGraph = { ...this.metadata.openGraph, ...og };\n return this;\n }\n\n /**\n * 设置 Twitter 元数据\n *\n * @param twitter - Twitter 元数据\n * @returns 构建器实例\n */\n twitter(twitter: TwitterMetadata): this {\n this.metadata.twitter = { ...this.metadata.twitter, ...twitter };\n return this;\n }\n\n /**\n * 设置自定义属性\n *\n * @param key - 键\n * @param value - 值\n * @returns 构建器实例\n */\n set(key: string, value: unknown): this {\n this.metadata[key] = value;\n return this;\n }\n\n /**\n * 构建元数据\n *\n * @returns 元数据对象\n */\n build(): Metadata {\n return { ...this.metadata };\n }\n}\n\n/**\n * 创建元数据构建器\n *\n * @returns 构建器实例\n */\nexport function createMetadataBuilder(): MetadataBuilder {\n return new MetadataBuilder();\n}\n","/**\n * 元数据渲染器\n */\nimport type { Metadata } from '@lytjs/shared-types';\nimport { escapeHTML } from '@lytjs/common-string';\n\n/**\n * 渲染元数据为 HTML 标签\n *\n * @param metadata - 元数据对象\n * @returns HTML 标签字符串\n */\nexport function renderMetadata(metadata: Metadata): string {\n const tags: string[] = [];\n\n if (metadata.title) {\n tags.push(`<title>${escapeHTML(metadata.title)}</title>`);\n }\n\n if (metadata.description) {\n tags.push(`<meta name=\"description\" content=\"${escapeHTML(metadata.description)}\">`);\n }\n\n if (metadata.keywords && metadata.keywords.length > 0) {\n tags.push(`<meta name=\"keywords\" content=\"${escapeHTML(metadata.keywords.join(', '))}\">`);\n }\n\n if (metadata.openGraph) {\n for (const [key, value] of Object.entries(metadata.openGraph)) {\n if (value) {\n tags.push(`<meta property=\"og:${key}\" content=\"${escapeHTML(String(value))}\">`);\n }\n }\n }\n\n if (metadata.twitter) {\n for (const [key, value] of Object.entries(metadata.twitter)) {\n if (value) {\n tags.push(`<meta name=\"twitter:${key}\" content=\"${escapeHTML(String(value))}\">`);\n }\n }\n }\n\n return tags.join('\\n');\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@lytjs/metadata",
3
+ "version": "6.6.0",
4
+ "description": "LytJS 元数据系统",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE"
21
+ ],
22
+ "sideEffects": false,
23
+ "scripts": {
24
+ "dev": "tsup --watch",
25
+ "build": "tsup",
26
+ "test": "vitest run",
27
+ "test:watch": "test:watch",
28
+ "test:coverage": "vitest run --coverage",
29
+ "type-check": "tsc --noEmit",
30
+ "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\"",
31
+ "clean": "rm -rf dist node_modules .turbo"
32
+ },
33
+ "dependencies": {
34
+ "@lytjs/common-is": "workspace:*",
35
+ "@lytjs/common-string": "workspace:*",
36
+ "@lytjs/shared-types": "workspace:*"
37
+ },
38
+ "devDependencies": {
39
+ "tsup": "^8.3.6",
40
+ "typescript": "^5.7.3",
41
+ "vitest": "^3.0.0"
42
+ },
43
+ "peerDependencies": {},
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "registry": "https://registry.npmjs.org/"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://gitee.com/lytjs/lytjs.git",
51
+ "directory": "packages/ecosystem/packages/web-framework/packages/metadata"
52
+ },
53
+ "keywords": [
54
+ "lytjs",
55
+ "metadata",
56
+ "meta",
57
+ "seo"
58
+ ],
59
+ "author": "LytJS Team",
60
+ "license": "MIT"
61
+ }