function containsVpErrorToken(node) { if (!node || typeof node !== "object") { return false; } if (node.type === "Literal" && typeof node.value === "string") { return node.value.split(/\s+/u).includes("vp-error"); } if (node.type === "TemplateElement") { return node.value.raw.split(/\s+/u).includes("vp-error"); } return Object.entries(node).some(([key, value]) => { if (key === "parent") { return false; } if (Array.isArray(value)) { return value.some(containsVpErrorToken); } return containsVpErrorToken(value); }); } const rule = { meta: { type: "problem", docs: { description: "Require the Text component for legacy vp-error styling", }, schema: [], messages: { useText: 'Use the Text component for the vp-error class; pair the error message with variant="error" so feedback stays accessible and consistent.', }, }, create(context) { return { JSXAttribute(node) { if (node.name?.name !== "className" || !containsVpErrorToken(node.value)) { return; } const elementName = node.parent?.name; if (elementName?.type === "JSXIdentifier" && elementName.name === "Text") { return; } context.report({ node, messageId: "useText" }); }, }; }, }; export default rule;