Code Quality Examples
Validation rules to enforce code quality standards.
No Console Statements
Prevents console.log and similar statements in production code.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const noConsole = defineCodeRule({
name: "no-console",
description: "Prevents console statements in production code",
shouldRun: (context) => {
// Only check source files, not test files
return (
/\.(ts|js|vue)$/.test(context.filePath) &&
!/\.(test|spec)\.(ts|js)$/.test(context.filePath)
);
},
validate(context) {
const errors: string[] = [];
const consolePatterns = [
{ regex: /console\.log\(/, method: "console.log" },
{ regex: /console\.debug\(/, method: "console.debug" },
{ regex: /console\.info\(/, method: "console.info" },
{ regex: /console\.warn\(/, method: "console.warn" },
];
for (const { regex, method } of consolePatterns) {
if (regex.test(context.content)) {
errors.push(
`â ${method}() detected in production code\n` +
` â Use a proper logging library instead\n` +
` âšī¸ Consider using: pino, winston, or consola\n` +
` đ File: ${context.filePath}`
);
}
}
return errors;
},
});
No TODO Comments
Ensures TODO comments aren't committed.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const noTodos = defineCodeRule({
name: "no-todos",
description: "Prevents TODO comments in committed code",
shouldRun: () => true,
validate(context) {
const errors: string[] = [];
// Match TODO, FIXME, HACK, XXX comments
const todoPattern = /(TODO|FIXME|HACK|XXX):/i;
if (todoPattern.test(context.content)) {
errors.push(
`â TODO/FIXME comment detected\n` +
` â Complete the task or create an issue\n` +
` âšī¸ Remove temporary comments before committing\n` +
` đ File: ${context.filePath}`
);
}
return errors;
},
});
Enforce Async/Await
Prefers async/await over .then() chains.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const preferAsyncAwait = defineCodeRule({
name: "prefer-async-await",
description: "Prefers async/await over Promise chains",
shouldRun: (context) => /\.(ts|js)$/.test(context.filePath),
validate(context) {
const errors: string[] = [];
// Check for .then() chains
const thenPattern = /\.\s*then\s*\(/g;
const matches = context.content.match(thenPattern);
if (matches && matches.length > 0) {
errors.push(
`â Promise .then() chain detected\n` +
` â Use async/await for better readability\n` +
` âšī¸ Example:\n` +
` // Instead of: promise.then(result => ...)\n` +
` // Use: const result = await promise\n` +
` đ File: ${context.filePath}`
);
}
return errors;
},
});
No Magic Numbers
Requires constants for magic numbers.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const noMagicNumbers = defineCodeRule({
name: "no-magic-numbers",
description: "Prevents magic numbers without constants",
shouldRun: (context) => /\.(ts|js)$/.test(context.filePath),
validate(context) {
const errors: string[] = [];
// Look for suspicious numeric literals (not 0, 1, -1, 2)
// This is a simplified version - a real implementation would be more sophisticated
const magicNumberPattern = /\b(?!0|1|2|-1)\d{3,}\b/g;
const matches = context.content.match(magicNumberPattern);
if (matches && matches.length > 0) {
const uniqueNumbers = [...new Set(matches)];
errors.push(
`â Magic numbers detected: ${uniqueNumbers.join(", ")}\n` +
` â Extract to named constants\n` +
` âšī¸ Example:\n` +
` const MAX_RETRY_ATTEMPTS = 3;\n` +
` const TIMEOUT_MS = 5000;\n` +
` đ File: ${context.filePath}`
);
}
return errors;
},
});
Enforce Named Exports
Prefers named exports over default exports.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const preferNamedExports = defineCodeRule({
name: "prefer-named-exports",
description: "Prefers named exports over default exports",
shouldRun: (context) => {
// Skip Vue SFCs and certain files
return (
/\.(ts|js)$/.test(context.filePath) &&
!context.filePath.includes("index.")
);
},
validate(context) {
const errors: string[] = [];
// Check for default exports
if (/export\s+default/.test(context.content)) {
errors.push(
`â Default export detected\n` +
` â Use named exports for better refactoring\n` +
` âšī¸ Named exports:\n` +
` - Enable better tree-shaking\n` +
` - Improve IDE auto-imports\n` +
` - Make refactoring easier\n` +
` đ File: ${context.filePath}`
);
}
return errors;
},
});
No Any Type
Prevents usage of any type in TypeScript.
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const noAnyType = defineCodeRule({
name: "no-any-type",
description: "Prevents usage of any type",
shouldRun: (context) => /\.ts$/.test(context.filePath),
validate(context) {
const errors: string[] = [];
// Check for : any or <any> or as any
const anyTypePatterns = [/:\s*any\b/, /<any>/, /as\s+any\b/];
for (const pattern of anyTypePatterns) {
if (pattern.test(context.content)) {
errors.push(
`â Type 'any' detected\n` +
` â Use proper types or 'unknown' for dynamic values\n` +
` âšī¸ Consider:\n` +
` - Define a proper interface\n` +
` - Use 'unknown' and type guards\n` +
` - Use generics for flexible types\n` +
` đ File: ${context.filePath}`
);
break;
}
}
return errors;
},
});
Example Usage
Combine all code quality rules:
// .claude/rules/code-quality.ts
import { defineCodeRule } from "@syncrolabs/claude-code-validator";
export const noConsole = defineCodeRule({
/* ... */
});
export const noTodos = defineCodeRule({
/* ... */
});
export const preferAsyncAwait = defineCodeRule({
/* ... */
});
export const noMagicNumbers = defineCodeRule({
/* ... */
});
export const preferNamedExports = defineCodeRule({
/* ... */
});
export const noAnyType = defineCodeRule({
/* ... */
});
All rules will be automatically discovered and enforced!
Customization
You can customize these rules for your team's needs:
// Adjust strictness
export const noConsole = defineCodeRule({
name: "no-console",
description: "Prevents console statements",
shouldRun: (context) => {
// Allow console in development files
return (
!context.filePath.includes("dev/") && !context.filePath.includes(".dev.")
);
},
validate(context) {
// Only block console.log, allow console.error
if (/console\.log\(/.test(context.content)) {
return ["â console.log() not allowed in production"];
}
return [];
},
});