bertui 1.1.1 → 1.1.2
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 +424 -435
- package/package.json +1 -1
- package/src/build/generators/html-generator.js +41 -7
- package/src/build/processors/css-builder.js +71 -4
- package/src/build.js +77 -35
- package/src/client/compiler.js +23 -42
- package/src/pagebuilder/core.js +191 -0
- package/src/server/dev-server.js +134 -36
- package/src/utils/env.js +59 -39
- package/src/utils/meta-extractor.js +124 -58
|
@@ -1,61 +1,127 @@
|
|
|
1
1
|
// bertui/src/utils/meta-extractor.js
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
for (let i = metaStart + 'export const meta = {'.length; i < code.length; i++) {
|
|
17
|
-
const char = code[i];
|
|
18
|
-
const prevChar = i > 0 ? code[i - 1] : '';
|
|
19
|
-
|
|
20
|
-
if (!inString && (char === '"' || char === "'" || char === '`')) {
|
|
21
|
-
inString = true;
|
|
22
|
-
stringChar = char;
|
|
23
|
-
} else if (inString && char === stringChar && prevChar !== '\\') {
|
|
24
|
-
inString = false;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (!inString) {
|
|
28
|
-
if (char === '{') braceCount++;
|
|
29
|
-
if (char === '}') {
|
|
30
|
-
if (braceCount === 0) {
|
|
31
|
-
metaEnd = i;
|
|
32
|
-
break;
|
|
33
|
-
}
|
|
34
|
-
braceCount--;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (metaEnd === -1) return null;
|
|
40
|
-
|
|
41
|
-
const metaString = code.substring(metaStart + 'export const meta = {'.length - 1, metaEnd + 1);
|
|
42
|
-
const meta = {};
|
|
43
|
-
const pairs = metaString.match(/(\w+)\s*:\s*(['"`][^'"`]*['"`])/g) || [];
|
|
44
|
-
|
|
45
|
-
pairs.forEach(pair => {
|
|
46
|
-
const colonIndex = pair.indexOf(':');
|
|
47
|
-
if (colonIndex === -1) return;
|
|
48
|
-
|
|
49
|
-
const key = pair.substring(0, colonIndex).trim();
|
|
50
|
-
const value = pair.substring(colonIndex + 1).trim().slice(1, -1);
|
|
51
|
-
|
|
52
|
-
if (key && value) {
|
|
53
|
-
meta[key] = value;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return Object.keys(meta).length > 0 ? meta : null;
|
|
58
|
-
} catch (error) {
|
|
59
|
-
return null;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract meta information from page component source code
|
|
5
|
+
* @param {string} sourceCode - Component source code
|
|
6
|
+
* @returns {Object} Extracted meta information
|
|
7
|
+
*/
|
|
8
|
+
export function extractMetaFromSource(sourceCode) {
|
|
9
|
+
const meta = {};
|
|
10
|
+
|
|
11
|
+
// Extract title
|
|
12
|
+
const titleMatch = sourceCode.match(/export\s+const\s+title\s*=\s*['"]([^'"]+)['"]/);
|
|
13
|
+
if (titleMatch) {
|
|
14
|
+
meta.title = titleMatch[1];
|
|
60
15
|
}
|
|
16
|
+
|
|
17
|
+
// Extract description
|
|
18
|
+
const descMatch = sourceCode.match(/export\s+const\s+description\s*=\s*['"]([^'"]+)['"]/);
|
|
19
|
+
if (descMatch) {
|
|
20
|
+
meta.description = descMatch[1];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Extract keywords
|
|
24
|
+
const keywordsMatch = sourceCode.match(/export\s+const\s+keywords\s*=\s*['"]([^'"]+)['"]/);
|
|
25
|
+
if (keywordsMatch) {
|
|
26
|
+
meta.keywords = keywordsMatch[1];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Extract author
|
|
30
|
+
const authorMatch = sourceCode.match(/export\s+const\s+author\s*=\s*['"]([^'"]+)['"]/);
|
|
31
|
+
if (authorMatch) {
|
|
32
|
+
meta.author = authorMatch[1];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Extract og:title
|
|
36
|
+
const ogTitleMatch = sourceCode.match(/export\s+const\s+ogTitle\s*=\s*['"]([^'"]+)['"]/);
|
|
37
|
+
if (ogTitleMatch) {
|
|
38
|
+
meta.ogTitle = ogTitleMatch[1];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Extract og:description
|
|
42
|
+
const ogDescMatch = sourceCode.match(/export\s+const\s+ogDescription\s*=\s*['"]([^'"]+)['"]/);
|
|
43
|
+
if (ogDescMatch) {
|
|
44
|
+
meta.ogDescription = ogDescMatch[1];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Extract og:image
|
|
48
|
+
const ogImageMatch = sourceCode.match(/export\s+const\s+ogImage\s*=\s*['"]([^'"]+)['"]/);
|
|
49
|
+
if (ogImageMatch) {
|
|
50
|
+
meta.ogImage = ogImageMatch[1];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Extract language
|
|
54
|
+
const langMatch = sourceCode.match(/export\s+const\s+lang\s*=\s*['"]([^'"]+)['"]/);
|
|
55
|
+
if (langMatch) {
|
|
56
|
+
meta.lang = langMatch[1];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Extract theme color
|
|
60
|
+
const themeMatch = sourceCode.match(/export\s+const\s+themeColor\s*=\s*['"]([^'"]+)['"]/);
|
|
61
|
+
if (themeMatch) {
|
|
62
|
+
meta.themeColor = themeMatch[1];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return meta;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generate HTML meta tags from meta object
|
|
70
|
+
* @param {Object} meta - Meta information object
|
|
71
|
+
* @returns {string} HTML meta tags
|
|
72
|
+
*/
|
|
73
|
+
export function generateMetaTags(meta) {
|
|
74
|
+
const tags = [];
|
|
75
|
+
|
|
76
|
+
if (meta.title) {
|
|
77
|
+
tags.push(`<title>${escapeHtml(meta.title)}</title>`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (meta.description) {
|
|
81
|
+
tags.push(`<meta name="description" content="${escapeHtml(meta.description)}">`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (meta.keywords) {
|
|
85
|
+
tags.push(`<meta name="keywords" content="${escapeHtml(meta.keywords)}">`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (meta.author) {
|
|
89
|
+
tags.push(`<meta name="author" content="${escapeHtml(meta.author)}">`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (meta.themeColor) {
|
|
93
|
+
tags.push(`<meta name="theme-color" content="${escapeHtml(meta.themeColor)}">`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Open Graph tags
|
|
97
|
+
if (meta.ogTitle) {
|
|
98
|
+
tags.push(`<meta property="og:title" content="${escapeHtml(meta.ogTitle)}">`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (meta.ogDescription) {
|
|
102
|
+
tags.push(`<meta property="og:description" content="${escapeHtml(meta.ogDescription)}">`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (meta.ogImage) {
|
|
106
|
+
tags.push(`<meta property="og:image" content="${escapeHtml(meta.ogImage)}">`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return tags.join('\n ');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Escape HTML special characters
|
|
114
|
+
* @param {string} text - Text to escape
|
|
115
|
+
* @returns {string} Escaped text
|
|
116
|
+
*/
|
|
117
|
+
function escapeHtml(text) {
|
|
118
|
+
const map = {
|
|
119
|
+
'&': '&',
|
|
120
|
+
'<': '<',
|
|
121
|
+
'>': '>',
|
|
122
|
+
'"': '"',
|
|
123
|
+
"'": '''
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return String(text).replace(/[&<>"']/g, m => map[m]);
|
|
61
127
|
}
|