chore(frontend): introduce prettier + eslint and prune unused code
- Add Prettier 3 with prettier-plugin-organize-imports (sorts/removes unused imports) - Add ESLint 10 flat config with typescript-eslint + eslint-plugin-vue + eslint-config-prettier - Add root scripts: format, format:check, lint, lint:fix - Reformat 257 files across admin-web, ops-web, desktop-client, packages - Remove unused locals/exports flagged by --noUnusedLocals/--noUnusedParameters - Fix duplicate localTabLabel key, surrogate-pair regex u-flag, NBSP literal in regex - Skip server/ (Go) and apps/browser-extension/ (deprecated per ADR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,104 +1,114 @@
|
||||
import { renderTablesAsParagraphRows } from "../../../../../packages/publisher-platforms/src/baijiahao";
|
||||
import { renderTablesAsParagraphRows } from '../../../../../packages/publisher-platforms/src/baijiahao'
|
||||
|
||||
export function prepareDongchediArticleHtml(html: string, title = ""): string {
|
||||
let next = renderTablesAsParagraphRows(html).trim();
|
||||
next = next.replace(/<hr\b[^>]*\/?>/gi, "");
|
||||
next = normalizeDongchediImageTags(next);
|
||||
export function prepareDongchediArticleHtml(html: string, title = ''): string {
|
||||
let next = renderTablesAsParagraphRows(html).trim()
|
||||
next = next.replace(/<hr\b[^>]*\/?>/gi, '')
|
||||
next = normalizeDongchediImageTags(next)
|
||||
next = next.replace(/<h[1-6]\b[^>]*>([\s\S]*?)<\/h[1-6]>/gi, (_match, content: string) => {
|
||||
const text = normalizeInlineContent(content);
|
||||
return text ? `<p><strong>${text}</strong></p>` : "";
|
||||
});
|
||||
const text = normalizeInlineContent(content)
|
||||
return text ? `<p><strong>${text}</strong></p>` : ''
|
||||
})
|
||||
next = next.replace(/<li\b[^>]*>([\s\S]*?)<\/li>/gi, (_match, content: string) => {
|
||||
const text = normalizeInlineContent(content);
|
||||
return text ? `<p>${text}</p>` : "";
|
||||
});
|
||||
next = next.replace(/<\/?(?:ol|ul)\b[^>]*>/gi, "");
|
||||
next = next.replace(/<p\b[^>]*>/gi, "<p>");
|
||||
next = next.replace(/<(strong|b)\b[^>]*>/gi, "<strong>").replace(/<\/b>/gi, "</strong>");
|
||||
next = next.replace(/<br\s*\/?>/gi, " ");
|
||||
next = next.replace(/<(?!\/?(?:p|strong|img)\b)[^>]+>/gi, "");
|
||||
next = next.replace(/<p>\s*<\/p>/gi, "");
|
||||
next = next.replace(/\s+/g, " ");
|
||||
next = next.replace(/>\s+</g, "><");
|
||||
next = stripLeadingDuplicateTitleParagraph(next, title);
|
||||
return next.trim();
|
||||
const text = normalizeInlineContent(content)
|
||||
return text ? `<p>${text}</p>` : ''
|
||||
})
|
||||
next = next.replace(/<\/?(?:ol|ul)\b[^>]*>/gi, '')
|
||||
next = next.replace(/<p\b[^>]*>/gi, '<p>')
|
||||
next = next.replace(/<(strong|b)\b[^>]*>/gi, '<strong>').replace(/<\/b>/gi, '</strong>')
|
||||
next = next.replace(/<br\s*\/?>/gi, ' ')
|
||||
next = next.replace(/<(?!\/?(?:p|strong|img)\b)[^>]+>/gi, '')
|
||||
next = next.replace(/<p>\s*<\/p>/gi, '')
|
||||
next = next.replace(/\s+/g, ' ')
|
||||
next = next.replace(/>\s+</g, '><')
|
||||
next = stripLeadingDuplicateTitleParagraph(next, title)
|
||||
return next.trim()
|
||||
}
|
||||
|
||||
export function countDongchediContentWordCount(html: string): number {
|
||||
const text = decodeDongchediHtmlEntities(html)
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/\s+/g, "")
|
||||
.trim();
|
||||
return [...text].length;
|
||||
.replace(/<[^>]*>/g, '')
|
||||
.replace(/\s+/g, '')
|
||||
.trim()
|
||||
return [...text].length
|
||||
}
|
||||
|
||||
function decodeDongchediHtmlEntities(value: string): string {
|
||||
return value
|
||||
.replace(/ /gi, " ")
|
||||
.replace(/&/gi, "&")
|
||||
.replace(/</gi, "<")
|
||||
.replace(/>/gi, ">")
|
||||
.replace(/"/gi, "\"")
|
||||
.replace(/ /gi, ' ')
|
||||
.replace(/&/gi, '&')
|
||||
.replace(/</gi, '<')
|
||||
.replace(/>/gi, '>')
|
||||
.replace(/"/gi, '"')
|
||||
.replace(/'|'/gi, "'")
|
||||
.replace(/&#(\d+);/g, (_match, code: string) => {
|
||||
const value = Number.parseInt(code, 10);
|
||||
return Number.isFinite(value) && value >= 0 && value <= 0x10FFFF ? String.fromCodePoint(value) : "";
|
||||
const value = Number.parseInt(code, 10)
|
||||
return Number.isFinite(value) && value >= 0 && value <= 0x10ffff
|
||||
? String.fromCodePoint(value)
|
||||
: ''
|
||||
})
|
||||
.replace(/&#x([0-9a-f]+);/gi, (_match, code: string) => {
|
||||
const value = Number.parseInt(code, 16);
|
||||
return Number.isFinite(value) && value >= 0 && value <= 0x10FFFF ? String.fromCodePoint(value) : "";
|
||||
});
|
||||
const value = Number.parseInt(code, 16)
|
||||
return Number.isFinite(value) && value >= 0 && value <= 0x10ffff
|
||||
? String.fromCodePoint(value)
|
||||
: ''
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeDongchediImageTags(html: string): string {
|
||||
return html.replace(/<img\b[^>]*>/gi, (imageTag: string) => {
|
||||
const src = extractAttribute(imageTag, "src");
|
||||
const src = extractAttribute(imageTag, 'src')
|
||||
if (!src) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
const alt = extractAttribute(imageTag, "alt") ?? "";
|
||||
return `<img src="${escapeAttribute(src)}" alt="${escapeAttribute(alt)}" />`;
|
||||
});
|
||||
const alt = extractAttribute(imageTag, 'alt') ?? ''
|
||||
return `<img src="${escapeAttribute(src)}" alt="${escapeAttribute(alt)}" />`
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeInlineContent(value: string): string {
|
||||
return value
|
||||
.replace(/<br\s*\/?>/gi, " ")
|
||||
.replace(/<\/?(?:p|div|section|article|header|footer|ol|ul|li|blockquote|h[1-6])\b[^>]*>/gi, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
.replace(/<br\s*\/?>/gi, ' ')
|
||||
.replace(
|
||||
/<\/?(?:p|div|section|article|header|footer|ol|ul|li|blockquote|h[1-6])\b[^>]*>/gi,
|
||||
' ',
|
||||
)
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function stripLeadingDuplicateTitleParagraph(html: string, title: string): string {
|
||||
const normalizedTitle = normalizeComparableText(title);
|
||||
const normalizedTitle = normalizeComparableText(title)
|
||||
if (!normalizedTitle) {
|
||||
return html;
|
||||
return html
|
||||
}
|
||||
|
||||
return html.replace(/^\s*<p>([\s\S]*?)<\/p>/i, (match, paragraphContent: string) => {
|
||||
return normalizeComparableText(paragraphContent) === normalizedTitle ? "" : match;
|
||||
});
|
||||
return normalizeComparableText(paragraphContent) === normalizedTitle ? '' : match
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeComparableText(value: string): string {
|
||||
return decodeDongchediHtmlEntities(value)
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/\s+/g, "")
|
||||
.trim();
|
||||
.replace(/<[^>]*>/g, '')
|
||||
.replace(/\s+/g, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function extractAttribute(sourceTag: string, attributeName: string): string | null {
|
||||
const matcher = new RegExp(`\\s${attributeName}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'>]+))`, "i");
|
||||
const match = matcher.exec(sourceTag);
|
||||
const value = match?.[1] ?? match?.[2] ?? match?.[3] ?? "";
|
||||
const trimmed = value.trim();
|
||||
return trimmed ? trimmed : null;
|
||||
const matcher = new RegExp(
|
||||
`\\s${attributeName}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s"'>]+))`,
|
||||
'i',
|
||||
)
|
||||
const match = matcher.exec(sourceTag)
|
||||
const value = match?.[1] ?? match?.[2] ?? match?.[3] ?? ''
|
||||
const trimmed = value.trim()
|
||||
return trimmed ? trimmed : null
|
||||
}
|
||||
|
||||
function escapeAttribute(value: string): string {
|
||||
return value
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user