diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f87ad..5099fc2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Changes +- Utils: The tailwind/trash class checks are now named predicates (`isTailwindClass`, `isTrashClass`) shared + by the HTML snapshots and the diff's container-class filter, replacing three copies of the same inline + lambda. - Config: `dynamicPageRegex` now extends the built-in dynamic-segment heuristics (numeric, UUID, ULID, hex) instead of replacing them. Previously, setting a custom pattern silently disabled every built-in match on any segment the custom pattern didn't also cover. diff --git a/src/utils/html-diff.ts b/src/utils/html-diff.ts index 591741a..9295bb3 100644 --- a/src/utils/html-diff.ts +++ b/src/utils/html-diff.ts @@ -1,7 +1,7 @@ import { parse, serialize } from 'parse5'; import type * as parse5TreeAdapter from 'parse5/lib/tree-adapters/default'; import type { HtmlConfig } from '../config.ts'; -import { TAILWIND_CLASS_PATTERNS, TRASH_HTML_CLASSES, minifyHtml } from './html.ts'; +import { isTailwindClass, isTrashClass, minifyHtml } from './html.ts'; import { isDynamicId, isGenericClass } from './xpath.ts'; export interface HtmlDiffPart { @@ -467,15 +467,13 @@ const directTextDiffer = (current: ElementNode, previous: ElementNode): boolean return false; }; -const trashHtmlClasses = TRASH_HTML_CLASSES; - function filterContainerClasses(classes: string[]): string[] { return classes .filter((cls) => !/\d/.test(cls)) .filter((cls) => !isGenericClass(cls)) - .filter((cls) => !trashHtmlClasses.test(cls)) + .filter((cls) => !isTrashClass(cls)) .filter((cls) => !/(:|__)/.test(cls)) - .filter((cls) => !TAILWIND_CLASS_PATTERNS.some((pattern) => pattern.test(cls))); + .filter((cls) => !isTailwindClass(cls)); } function buildContainerSelector(element: ElementNode, allElements: NodeMap): string | null { diff --git a/src/utils/html.ts b/src/utils/html.ts index 0e45748..f7ed9a4 100644 --- a/src/utils/html.ts +++ b/src/utils/html.ts @@ -544,6 +544,9 @@ export const TAILWIND_CLASS_PATTERNS: RegExp[] = [ /^prose$/i, ]; +export const isTailwindClass = (cls: string): boolean => TAILWIND_CLASS_PATTERNS.some((pattern) => pattern.test(cls)); +export const isTrashClass = (cls: string): boolean => TRASH_HTML_CLASSES.test(cls); + const NON_SEMANTIC_TAGS = new Set([ 'style', 'script', @@ -758,7 +761,6 @@ export function sanitizeHtmlString(html: string, htmlConfig?: HtmlConfig): strin */ export function htmlMinimalUISnapshot(html: string, htmlConfig?: HtmlConfig['minimal']) { const document = parse(html); - const trashHtmlClasses = TRASH_HTML_CLASSES; const removeElements = ['path', 'script']; function isFilteredOut(node) { @@ -867,9 +869,9 @@ export function htmlMinimalUISnapshot(html: string, htmlConfig?: HtmlConfig['min attr.value = value .split(' ') .filter((className) => !/\d/.test(className)) - .filter((className) => !className.match(trashHtmlClasses)) + .filter((className) => !isTrashClass(className)) .filter((className) => !className.match(/(:|__)/)) - .filter((className) => !TAILWIND_CLASS_PATTERNS.some((pattern) => pattern.test(className))) + .filter((className) => !isTailwindClass(className)) .join(' '); if (attr.value === '') return false; } @@ -1451,7 +1453,7 @@ function cleanElement(element: parse5TreeAdapter.Element): void { .filter(Boolean) .filter((className) => !/\d/.test(className)) .filter((className) => !className.includes(':')) - .filter((className) => !TAILWIND_CLASS_PATTERNS.some((pattern) => pattern.test(className))) + .filter((className) => !isTailwindClass(className)) .join(' '); if (!attr.value) {