Nuxt UI Validation
Validates Nuxt UI component usage and enforces v4 migration patterns.
Overview
This rule helps migrate from Nuxt UI v3 to v4 by:
- Catching deprecated component names
- Validating semantic color props
- Enforcing v4 naming conventions
- Checking model modifier patterns
Source Code
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
import type { PatternRule } from "@syncrolabs/claude-code-validator";
const patterns: PatternRule[] = [
{
regex: /UFormGroup/,
message: "❌ UFormGroup is outdated. Use UFormField instead.",
replacement: "UFormField",
},
{
regex: /UButtonGroup/,
message: "❌ UButtonGroup has been renamed in v4. Use UFieldGroup instead.",
replacement: "UFieldGroup",
},
{
regex: /UPageMarquee/,
message: "❌ UPageMarquee has been renamed in v4. Use UMarquee instead.",
replacement: "UMarquee",
},
{
regex: /UPageAccordion/,
message:
"❌ UPageAccordion is deprecated in v4. Use UAccordion from @nuxt/ui-pro instead.",
replacement: "UAccordion",
},
{
regex: /v-model[.:]\w*nullify/,
message:
'❌ The "nullify" model modifier has been renamed to "nullable" in Nuxt UI v4.',
replacement: "v-model:nullable",
},
];
const COMPONENTS_WITH_COLOR = [
"UButton",
"UBadge",
"UChip",
"UAlert",
"UToast",
"UInput",
"UTextarea",
"USelect",
"USelectMenu",
"UInputMenu",
"UPinInput",
"UInputNumber",
"UCheckbox",
"UCheckboxGroup",
"URadioGroup",
"USwitch",
"UBanner",
"UCalendar",
"UTabs",
"UNavigationMenu",
"UContentNavigation",
"UContentToc",
"UPagination",
"UProgress",
"USlider",
"UDivider",
];
const SEMANTIC_COLORS = ["primary", "neutral", "error", "success", "warning"];
const COLOR_MAPPING: Record<string, string> = {
red: "error",
green: "success",
yellow: "warning",
gray: "neutral",
grey: "neutral",
blue: "primary",
};
function validateColors(content: string, filePath: string): string[] {
const errors: string[] = [];
for (const component of COMPONENTS_WITH_COLOR) {
const regex = new RegExp(`<${component}[^>]*:?color=["']([^"']+)["']`, "g");
let match;
while ((match = regex.exec(content)) !== null) {
const color = match[1];
if (!SEMANTIC_COLORS.includes(color)) {
const suggested = COLOR_MAPPING[color] || "primary";
errors.push(
`❌ Invalid color "${color}" on <${component}>\n` +
` → Use Nuxt UI v4 semantic color: "${suggested}"\n` +
` ℹ️ Valid colors: ${SEMANTIC_COLORS.join(", ")}\n` +
` 📄 File: ${filePath}`
);
}
}
}
return errors;
}
export const nuxtUIRules = defineCodeRule({
name: "nuxt-ui",
description: "Validate Nuxt UI component usage and patterns",
shouldRun: (context) => {
return context.filePath.endsWith(".vue");
},
validate(context) {
const errors: string[] = [];
// Check pattern-based rules
for (const { regex, message, replacement } of patterns) {
if (regex.test(context.content)) {
let error = message;
if (replacement) {
error += `\n → Use: ${replacement}`;
}
error += `\n 📄 File: ${context.filePath}`;
errors.push(error);
}
}
// Check color prop validation
const colorErrors = validateColors(context.content, context.filePath);
errors.push(...colorErrors);
return errors;
},
});
What It Catches
Deprecated Components
<!-- ❌ Blocked -->
<UFormGroup label="Name">
<UInput v-model="name" />
</UFormGroup>
<!-- ✅ Allowed -->
<UFormField label="Name">
<UInput v-model="name" />
</UFormField>
Invalid Colors
<!-- ❌ Blocked -->
<UButton color="red">Delete</UButton>
<!-- ✅ Allowed -->
<UButton color="error">Delete</UButton>
Renamed Components
<!-- ❌ Blocked -->
<UButtonGroup>
<UButton>One</UButton>
<UButton>Two</UButton>
</UButtonGroup>
<!-- ✅ Allowed -->
<UFieldGroup>
<UButton>One</UButton>
<UButton>Two</UButton>
</UFieldGroup>
Model Modifiers
<!-- ❌ Blocked -->
<UInput v-model:nullify="value" />
<!-- ✅ Allowed -->
<UInput v-model:nullable="value" />
Test Cases
The rule includes comprehensive test coverage:
describe("Nuxt UI Rules", () => {
it("should detect UFormGroup", () => {
const context = {
toolName: "Write",
filePath: "test.vue",
content: '<UFormGroup label="Test">',
operation: "write" as const,
};
const errors = nuxtUIRules.validate(context);
expect(errors).toHaveLength(1);
expect(errors[0]).toContain("UFormGroup");
});
it("should detect invalid color", () => {
const context = {
toolName: "Write",
filePath: "test.vue",
content: '<UButton color="red">Click</UButton>',
operation: "write" as const,
};
const errors = nuxtUIRules.validate(context);
expect(errors).toHaveLength(1);
expect(errors[0]).toContain("red");
});
});
Benefits
- Prevents outdated patterns - Catches v3 patterns during migration
- Enforces semantic colors - Uses meaningful color names
- Clear error messages - Provides actionable suggestions
- Comprehensive - Covers all 23 components with color props