diff --git a/apps/desktop-client/src/main/adapters/baijiahao.test.ts b/apps/desktop-client/src/main/adapters/baijiahao.test.ts
index 1c577ff..9a79192 100644
--- a/apps/desktop-client/src/main/adapters/baijiahao.test.ts
+++ b/apps/desktop-client/src/main/adapters/baijiahao.test.ts
@@ -5,6 +5,7 @@ import {
prepareBaijiahaoArticleHtml,
prepareBaijiahaoMarkdown,
renderBaijiahaoTablesAsBlocks,
+ renderTablesAsParagraphRows,
} from "../../../../../packages/publisher-platforms/src/baijiahao";
import { normalizeArticleHtml } from "./common";
@@ -42,8 +43,8 @@ describe("baijiahao table content", () => {
expect(result).toContain("汇总");
});
- it("downgrades tables into visible div blocks for Baijiahao", () => {
- const result = renderBaijiahaoTablesAsBlocks(`
+ it("downgrades tables into paragraph rows with three-space column separators", () => {
+ const result = renderTablesAsParagraphRows(`
| 城市 | 商家 |
@@ -57,11 +58,14 @@ describe("baijiahao table content", () => {
expect(result).not.toContain("城市 商家");
+ expect(result).toContain("合肥
");
+ });
+
+ it("keeps the legacy Baijiahao block renderer on the paragraph-row fallback", () => {
+ const result = renderBaijiahaoTablesAsBlocks("");
+
+ expect(result).toBe("A B
");
});
it("keeps the paragraph after a markdown table outside the downgraded table", () => {
@@ -86,7 +90,9 @@ describe("baijiahao table content", () => {
);
expect(html).not.toContain("品牌 评分");
+ expect(html).toContain("合肥全屋定制杨姐 9.8
");
expect(html).toContain("下一段中文说明
");
expect(html.indexOf("合肥全屋定制杨姐")).toBeGreaterThanOrEqual(0);
expect(html.indexOf("合肥全屋定制杨姐")).toBeLessThan(html.indexOf("下一段中文说明
"));
@@ -115,7 +121,8 @@ describe("baijiahao table content", () => {
expect(html).toContain("2026年合肥全屋定制口碑好品牌推荐 | 本地业主专属避坑指南
");
expect(html).not.toContain("排名 品牌名称");
expect(html).toContain("合肥全屋定制杨姐");
});
});
diff --git a/packages/publisher-platforms/src/baijiahao.ts b/packages/publisher-platforms/src/baijiahao.ts
index a45293b..a2f589c 100644
--- a/packages/publisher-platforms/src/baijiahao.ts
+++ b/packages/publisher-platforms/src/baijiahao.ts
@@ -22,50 +22,11 @@ const BAIJIAHAO_TABLE_HEADER_CELL_STYLE = [
"font-weight: 600",
].join("; ");
-const BAIJIAHAO_FAUX_TABLE_STYLE = [
- "width: 100%",
- "margin: 12px 0",
- "border-top: 1px solid #d9d9d9",
- "border-left: 1px solid #d9d9d9",
- "overflow-x: auto",
-].join("; ");
-
-const BAIJIAHAO_FAUX_TABLE_ROW_STYLE = [
- "display: flex",
- "align-items: stretch",
- "width: 100%",
-].join("; ");
-
-const BAIJIAHAO_FAUX_TABLE_CELL_STYLE = [
- "flex: 1 1 0",
- "min-width: 96px",
- "box-sizing: border-box",
- "border-right: 1px solid #d9d9d9",
- "border-bottom: 1px solid #d9d9d9",
- "padding: 8px 10px",
- "vertical-align: middle",
- "word-break: break-word",
- "font-size: 15px",
- "line-height: 1.6",
- "color: #1f2937",
- "background: #ffffff",
-].join("; ");
-
-const BAIJIAHAO_FAUX_TABLE_HEADER_CELL_STYLE = [
- BAIJIAHAO_FAUX_TABLE_CELL_STYLE,
- "background: #f5f7fa",
- "font-weight: 600",
-].join("; ");
+const TABLE_PARAGRAPH_CELL_SEPARATOR = " ";
const BAIJIAHAO_TABLE_ALLOWED_ATTRS = ["colspan", "rowspan", "align", "valign", "width"];
-interface ParsedTableCell {
- content: string;
- header: boolean;
- colSpan: number;
-}
-
-type ParsedTableRow = ParsedTableCell[];
+type ParsedParagraphTableRow = string[];
function hasUnescapedPipe(value: string): boolean {
let escaped = false;
@@ -216,12 +177,6 @@ function normalizeCellContent(value: string): string {
return trimmed ? trimmed : "
";
}
-function normalizeSpanAttribute(sourceTag: string, attributeName: "colspan" | "rowspan"): number {
- const value = extractAttribute(sourceTag, attributeName);
- const parsed = value ? Number.parseInt(value, 10) : 1;
- return Number.isFinite(parsed) && parsed > 1 ? Math.min(parsed, 12) : 1;
-}
-
function normalizeTableCell(sourceTag: string, content: string, header: boolean): string {
const attrs = allowedTableAttributes(sourceTag);
const attrPrefix = attrs ? `${attrs} ` : "";
@@ -263,18 +218,25 @@ export function normalizeBaijiahaoTables(html: string): string {
return html.replace(/]*>[\s\S]*?<\/table>/gi, (tableHtml) => normalizeSingleTable(tableHtml));
}
-function parseTableRows(tableHtml: string): ParsedTableRow[] {
- const rows: ParsedTableRow[] = [];
+function normalizeParagraphCellContent(value: string): string {
+ return value
+ .trim()
+ .replace(/
/gi, " ")
+ .replace(/<\/?(?:p|div|section|article|header|footer|ul|ol|li|blockquote|h[1-6])\b[^>]*>/gi, " ")
+ .replace(/\s+/g, " ")
+ .trim();
+}
+
+function parseParagraphTableRows(tableHtml: string): ParsedParagraphTableRow[] {
+ const rows: ParsedParagraphTableRow[] = [];
for (const rowMatch of tableHtml.matchAll(/]*>([\s\S]*?)<\/tr>/gi)) {
- const cells: ParsedTableRow = [];
+ const cells: ParsedParagraphTableRow = [];
const rowContent = rowMatch[1] ?? "";
- for (const cellMatch of rowContent.matchAll(/<(th|td)\b([^>]*)>([\s\S]*?)<\/\1>/gi)) {
- const sourceTag = `<${cellMatch[1]}${cellMatch[2] ?? ""}>`;
- cells.push({
- content: normalizeCellContent(cellMatch[3] ?? ""),
- header: cellMatch[1]?.toLowerCase() === "th",
- colSpan: normalizeSpanAttribute(sourceTag, "colspan"),
- });
+ for (const cellMatch of rowContent.matchAll(/<(?:th|td)\b[^>]*>([\s\S]*?)<\/(?:th|td)>/gi)) {
+ const content = normalizeParagraphCellContent(cellMatch[1] ?? "");
+ if (content) {
+ cells.push(content);
+ }
}
if (cells.length > 0) {
rows.push(cells);
@@ -283,36 +245,30 @@ function parseTableRows(tableHtml: string): ParsedTableRow[] {
return rows;
}
-function renderFauxTableCell(cell: ParsedTableCell, rowIndex: number): string {
- const header = cell.header || rowIndex === 0;
- const baseStyle = header ? BAIJIAHAO_FAUX_TABLE_HEADER_CELL_STYLE : BAIJIAHAO_FAUX_TABLE_CELL_STYLE;
- const style = `${baseStyle}; flex: ${cell.colSpan} ${cell.colSpan} 0`;
- const content = header ? `${cell.content}` : cell.content;
- return `${content}
`;
-}
-
-function renderSingleTableAsBlocks(tableHtml: string): string {
- const rows = parseTableRows(tableHtml);
- if (rows.length === 0) {
+function renderSingleTableAsParagraphRows(tableHtml: string): string {
+ const rows = parseParagraphTableRows(tableHtml);
+ if (!rows.length) {
return "";
}
- return `${rows
- .map((row, rowIndex) => `
${row
- .map((cell) => renderFauxTableCell(cell, rowIndex))
- .join("")}
`)
- .join("")}
`;
+ return rows
+ .map((row) => `${row.join(TABLE_PARAGRAPH_CELL_SEPARATOR)}
`)
+ .join("");
}
-export function renderBaijiahaoTablesAsBlocks(html: string): string {
+export function renderTablesAsParagraphRows(html: string): string {
if (!/]*>[\s\S]*?<\/table>/gi, (tableHtml) => renderSingleTableAsBlocks(tableHtml));
+ return html.replace(/]*>[\s\S]*?<\/table>/gi, (tableHtml) =>
+ renderSingleTableAsParagraphRows(tableHtml),
+ );
+}
+
+export function renderBaijiahaoTablesAsBlocks(html: string): string {
+ return renderTablesAsParagraphRows(html);
}
export function prepareBaijiahaoArticleHtml(html: string): string {
- // Baijiahao's preview/final article page does not consistently render native table tags,
- // so publish uses ordinary div blocks to preserve visible tabular content.
- return renderBaijiahaoTablesAsBlocks(html).trim();
+ return renderTablesAsParagraphRows(html).trim();
}