chore: sync baoyu-md vendor to baoyu-markdown-to-html and baoyu-post-to-weibo
This commit is contained in:
parent
434d4857da
commit
bfdd64bd4e
|
|
@ -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) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue