94 lines
2.8 KiB
JavaScript
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',
|
|
});
|
|
}
|
|
}
|
|
},
|
|
};
|
|
},
|
|
},
|
|
}; |