mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-19 08:59:48 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30d2ac98ce | |||
| bfdd64bd4e |
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||||
"version": "1.103.0"
|
"version": "1.103.1"
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
English | [中文](./CHANGELOG.zh.md)
|
English | [中文](./CHANGELOG.zh.md)
|
||||||
|
|
||||||
|
## 1.103.1 - 2026-04-13
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- `baoyu-markdown-to-html`: decode HTML entities and strip tags from article summary
|
||||||
|
- `baoyu-post-to-weibo`: decode HTML entities and strip tags from article summary
|
||||||
|
|
||||||
## 1.103.0 - 2026-04-12
|
## 1.103.0 - 2026-04-12
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
[English](./CHANGELOG.md) | 中文
|
[English](./CHANGELOG.md) | 中文
|
||||||
|
|
||||||
|
## 1.103.1 - 2026-04-13
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
- `baoyu-markdown-to-html`:修复文章摘要中 HTML 实体未解码及 HTML 标签未剥离的问题
|
||||||
|
- `baoyu-post-to-weibo`:修复文章摘要中 HTML 实体未解码及 HTML 标签未剥离的问题
|
||||||
|
|
||||||
## 1.103.0 - 2026-04-12
|
## 1.103.0 - 2026-04-12
|
||||||
|
|
||||||
### 新功能
|
### 新功能
|
||||||
|
|||||||
@@ -46,6 +46,45 @@ export function stripWrappingQuotes(value: string): string {
|
|||||||
return value.trim();
|
return value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HTML_ENTITIES: Record<string, string> = {
|
||||||
|
amp: "&",
|
||||||
|
apos: "'",
|
||||||
|
gt: ">",
|
||||||
|
lt: "<",
|
||||||
|
nbsp: " ",
|
||||||
|
quot: '"',
|
||||||
|
};
|
||||||
|
|
||||||
|
function decodeHtmlCodePoint(codePoint: number, fallback: string): string {
|
||||||
|
if (!Number.isFinite(codePoint) || codePoint < 0 || codePoint > 0x10ffff) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return String.fromCodePoint(codePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeHtmlEntities(value: string): string {
|
||||||
|
return value.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (entity, body: string) => {
|
||||||
|
const normalized = body.toLowerCase();
|
||||||
|
if (normalized.startsWith("#x")) {
|
||||||
|
return decodeHtmlCodePoint(Number.parseInt(normalized.slice(2), 16), entity);
|
||||||
|
}
|
||||||
|
if (normalized.startsWith("#")) {
|
||||||
|
return decodeHtmlCodePoint(Number.parseInt(normalized.slice(1), 10), entity);
|
||||||
|
}
|
||||||
|
return HTML_ENTITIES[normalized] ?? entity;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanSummaryText(value: string): string {
|
||||||
|
return decodeHtmlEntities(stripWrappingQuotes(value))
|
||||||
|
.replace(/<script\b[\s\S]*?<\/script>/gi, " ")
|
||||||
|
.replace(/<style\b[\s\S]*?<\/style>/gi, " ")
|
||||||
|
.replace(/<br\s*\/?>/gi, " ")
|
||||||
|
.replace(/<\/?[a-z][a-z0-9:-]*(?:\s+[^>]*)?>/gi, " ")
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
export function toFrontmatterString(value: unknown): string | undefined {
|
export function toFrontmatterString(value: unknown): string | undefined {
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
return stripWrappingQuotes(value);
|
return stripWrappingQuotes(value);
|
||||||
@@ -94,10 +133,11 @@ export function extractSummaryFromBody(body: string, maxLen: number): string {
|
|||||||
.replace(/\*(.+?)\*/g, "$1")
|
.replace(/\*(.+?)\*/g, "$1")
|
||||||
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
||||||
.replace(/`([^`]+)`/g, "$1");
|
.replace(/`([^`]+)`/g, "$1");
|
||||||
|
const summaryText = cleanSummaryText(cleanText);
|
||||||
|
|
||||||
if (cleanText.length > 20) {
|
if (summaryText.length > 20) {
|
||||||
if (cleanText.length <= maxLen) return cleanText;
|
if (summaryText.length <= maxLen) return summaryText;
|
||||||
return `${cleanText.slice(0, maxLen - 3)}...`;
|
return `${summaryText.slice(0, maxLen - 3)}...`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,19 +45,24 @@ export function loadCodeThemeCss(themeName: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildHtmlDocument(meta: HtmlDocumentMeta, css: string, html: string, codeThemeCss?: string): string {
|
export function buildHtmlDocument(meta: HtmlDocumentMeta, css: string, html: string, codeThemeCss?: string): string {
|
||||||
|
const escapeHtmlAttribute = (value: string) => value
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">");
|
||||||
const lines = [
|
const lines = [
|
||||||
"<!doctype html>",
|
"<!doctype html>",
|
||||||
"<html>",
|
"<html>",
|
||||||
"<head>",
|
"<head>",
|
||||||
' <meta charset="utf-8" />',
|
' <meta charset="utf-8" />',
|
||||||
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
||||||
` <title>${meta.title}</title>`,
|
` <title>${escapeHtmlAttribute(meta.title)}</title>`,
|
||||||
];
|
];
|
||||||
if (meta.author) {
|
if (meta.author) {
|
||||||
lines.push(` <meta name="author" content="${meta.author}" />`);
|
lines.push(` <meta name="author" content="${escapeHtmlAttribute(meta.author)}" />`);
|
||||||
}
|
}
|
||||||
if (meta.description) {
|
if (meta.description) {
|
||||||
lines.push(` <meta name="description" content="${meta.description}" />`);
|
lines.push(` <meta name="description" content="${escapeHtmlAttribute(meta.description)}" />`);
|
||||||
}
|
}
|
||||||
lines.push(` <style>${css}</style>`);
|
lines.push(` <style>${css}</style>`);
|
||||||
if (codeThemeCss) {
|
if (codeThemeCss) {
|
||||||
|
|||||||
@@ -46,6 +46,45 @@ export function stripWrappingQuotes(value: string): string {
|
|||||||
return value.trim();
|
return value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const HTML_ENTITIES: Record<string, string> = {
|
||||||
|
amp: "&",
|
||||||
|
apos: "'",
|
||||||
|
gt: ">",
|
||||||
|
lt: "<",
|
||||||
|
nbsp: " ",
|
||||||
|
quot: '"',
|
||||||
|
};
|
||||||
|
|
||||||
|
function decodeHtmlCodePoint(codePoint: number, fallback: string): string {
|
||||||
|
if (!Number.isFinite(codePoint) || codePoint < 0 || codePoint > 0x10ffff) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return String.fromCodePoint(codePoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeHtmlEntities(value: string): string {
|
||||||
|
return value.replace(/&(#x?[0-9a-f]+|[a-z]+);/gi, (entity, body: string) => {
|
||||||
|
const normalized = body.toLowerCase();
|
||||||
|
if (normalized.startsWith("#x")) {
|
||||||
|
return decodeHtmlCodePoint(Number.parseInt(normalized.slice(2), 16), entity);
|
||||||
|
}
|
||||||
|
if (normalized.startsWith("#")) {
|
||||||
|
return decodeHtmlCodePoint(Number.parseInt(normalized.slice(1), 10), entity);
|
||||||
|
}
|
||||||
|
return HTML_ENTITIES[normalized] ?? entity;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanSummaryText(value: string): string {
|
||||||
|
return decodeHtmlEntities(stripWrappingQuotes(value))
|
||||||
|
.replace(/<script\b[\s\S]*?<\/script>/gi, " ")
|
||||||
|
.replace(/<style\b[\s\S]*?<\/style>/gi, " ")
|
||||||
|
.replace(/<br\s*\/?>/gi, " ")
|
||||||
|
.replace(/<\/?[a-z][a-z0-9:-]*(?:\s+[^>]*)?>/gi, " ")
|
||||||
|
.replace(/\s+/g, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
export function toFrontmatterString(value: unknown): string | undefined {
|
export function toFrontmatterString(value: unknown): string | undefined {
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
return stripWrappingQuotes(value);
|
return stripWrappingQuotes(value);
|
||||||
@@ -94,10 +133,11 @@ export function extractSummaryFromBody(body: string, maxLen: number): string {
|
|||||||
.replace(/\*(.+?)\*/g, "$1")
|
.replace(/\*(.+?)\*/g, "$1")
|
||||||
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
|
||||||
.replace(/`([^`]+)`/g, "$1");
|
.replace(/`([^`]+)`/g, "$1");
|
||||||
|
const summaryText = cleanSummaryText(cleanText);
|
||||||
|
|
||||||
if (cleanText.length > 20) {
|
if (summaryText.length > 20) {
|
||||||
if (cleanText.length <= maxLen) return cleanText;
|
if (summaryText.length <= maxLen) return summaryText;
|
||||||
return `${cleanText.slice(0, maxLen - 3)}...`;
|
return `${summaryText.slice(0, maxLen - 3)}...`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,19 +45,24 @@ export function loadCodeThemeCss(themeName: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function buildHtmlDocument(meta: HtmlDocumentMeta, css: string, html: string, codeThemeCss?: string): string {
|
export function buildHtmlDocument(meta: HtmlDocumentMeta, css: string, html: string, codeThemeCss?: string): string {
|
||||||
|
const escapeHtmlAttribute = (value: string) => value
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">");
|
||||||
const lines = [
|
const lines = [
|
||||||
"<!doctype html>",
|
"<!doctype html>",
|
||||||
"<html>",
|
"<html>",
|
||||||
"<head>",
|
"<head>",
|
||||||
' <meta charset="utf-8" />',
|
' <meta charset="utf-8" />',
|
||||||
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
' <meta name="viewport" content="width=device-width, initial-scale=1" />',
|
||||||
` <title>${meta.title}</title>`,
|
` <title>${escapeHtmlAttribute(meta.title)}</title>`,
|
||||||
];
|
];
|
||||||
if (meta.author) {
|
if (meta.author) {
|
||||||
lines.push(` <meta name="author" content="${meta.author}" />`);
|
lines.push(` <meta name="author" content="${escapeHtmlAttribute(meta.author)}" />`);
|
||||||
}
|
}
|
||||||
if (meta.description) {
|
if (meta.description) {
|
||||||
lines.push(` <meta name="description" content="${meta.description}" />`);
|
lines.push(` <meta name="description" content="${escapeHtmlAttribute(meta.description)}" />`);
|
||||||
}
|
}
|
||||||
lines.push(` <style>${css}</style>`);
|
lines.push(` <style>${css}</style>`);
|
||||||
if (codeThemeCss) {
|
if (codeThemeCss) {
|
||||||
|
|||||||
Reference in New Issue
Block a user