Files
gridpilot.gg/apps/website/eslint-rules/client-only-rules.js
2026-01-12 14:52:04 +01:00

94 lines
2.8 KiB
JavaScript

/**
* ESLint rules for Client-Only Guardrails
*
* Enforces client-side only boundaries
*/
module.exports = {
// Rule 1: No server-side code in client-only files
'no-server-code-in-client-only': {
meta: {
type: 'problem',
docs: {
description: 'Forbid server-side code in client-only files',
category: 'Client-Only',
},
messages: {
message: 'Client-only files cannot contain server-side code - see apps/website/lib/contracts/view-models/ViewModel.ts',
},
},
create(context) {
return {
Program(node) {
const filename = context.getFilename();
if (filename.includes('/app/') &&
filename.endsWith('.tsx') &&
!filename.endsWith('page.tsx') &&
!filename.endsWith('layout.tsx')) {
const sourceCode = context.getSourceCode();
const text = sourceCode.getText();
// Check for server-side patterns
const serverPatterns = [
/getServerSideProps/,
/cookies\(\)/,
/headers\(\)/,
/next\/headers/,
];
for (const pattern of serverPatterns) {
if (pattern.test(text)) {
context.report({
loc: { line: 1, column: 0 },
messageId: 'message',
});
break;
}
}
}
},
};
},
},
// Rule 2: Client-only files must have 'use client' directive
'client-only-must-have-directive': {
meta: {
type: 'problem',
docs: {
description: 'Enforce use client directive',
category: 'Client-Only',
},
messages: {
message: 'Client-only files must have "use client" directive at the top - see apps/website/lib/contracts/view-models/ViewModel.ts',
},
},
create(context) {
return {
Program(node) {
const filename = context.getFilename();
if (filename.includes('/app/') &&
filename.endsWith('.tsx') &&
!filename.endsWith('page.tsx') &&
!filename.endsWith('layout.tsx')) {
const sourceCode = context.getSourceCode();
const firstComment = sourceCode.getAllComments()[0];
const hasDirective = firstComment &&
firstComment.type === 'Line' &&
firstComment.value.trim() === '"use client"';
if (!hasDirective) {
context.report({
loc: { line: 1, column: 0 },
messageId: 'message',
});
}
}
},
};
},
},
};