core/validators/element.validator.ts
core/validators/element.validator.ts is a file in Bane's Lab Build Scripts. 39 lines of code and 8 definitions.
import { ALT_ATTRIBUTE, ARIA_LABEL_ATTRIBUTE, HREF_ATTRIBUTE, TITLE_ATTRIBUTE } from "#core/ids/element.ids";
import { genericLink, namelessLink } from "#configuration/strings/element.strings";
import type { Finding } from "#types/validation.types";
import { isGenericLabel } from "@banes-lab/web/core/predicates/link.predicate.ts";
import { readDocument } from "#core/adapters/document.adapter";
const SPACE = " ";
const imageNames = function imageNames(anchor: Element): string {
return [...anchor.querySelectorAll("img")]
.map((image) => image.getAttribute(ALT_ATTRIBUTE)?.trim() ?? "")
.filter((alt) => alt.length > 0)
.join(SPACE);
};
const accessibleName = function accessibleName(anchor: Element): string {
const candidates = [
anchor.getAttribute(ARIA_LABEL_ATTRIBUTE) ?? "",
anchor.textContent,
imageNames(anchor),
anchor.getAttribute(TITLE_ATTRIBUTE) ?? "",
];
return candidates.map((candidate) => candidate.trim()).find((name) => name.length > 0) ?? "";
};
const findingOf = function findingOf(file: string, anchor: Element): Finding | null {
const href = anchor.getAttribute(HREF_ATTRIBUTE) ?? "";
const text = anchor.textContent.trim();
if (accessibleName(anchor).length === 0) {
return { file, message: namelessLink(href) };
}
if (isGenericLabel(text)) {
return { file, message: genericLink(href, text) };
}
return null;
};
export const checkLinkNames = function checkLinkNames(file: string, html: string): Finding[] {
return readDocument(html, (document) =>
[...document.querySelectorAll("a[href]")]
.map((anchor) => findingOf(file, anchor))
.filter((finding): finding is Finding => finding !== null),
);
};