website refactor

This commit is contained in:
2026-01-12 15:24:32 +01:00
parent 48957bfc56
commit 7c54cba445
3 changed files with 59 additions and 3 deletions

View File

@@ -25,11 +25,13 @@ const writeBoundaryRules = require('./write-boundary-rules');
const modelTaxonomyRules = require('./model-taxonomy-rules');
const filenameRules = require('./filename-rules');
const componentNoDataManipulation = require('./component-no-data-manipulation');
const presenterPurity = require('./presenter-purity');
module.exports = {
rules: {
// Presenter Contract
'presenter-contract': presenterContract,
'presenter-purity': presenterPurity,
// RSC Boundary Rules
'rsc-no-container-manager': rscBoundaryRules['no-container-manager-in-server'],

View File

@@ -87,10 +87,11 @@ module.exports = {
// Check for present method in classes
MethodDefinition(node) {
if (presenterClassNode &&
node.key.type === 'Identifier' &&
if (presenterClassNode &&
node.key.type === 'Identifier' &&
node.key.name === 'present' &&
node.parent === presenterClassNode) {
node.parent.type === 'ClassBody' &&
node.parent.parent === presenterClassNode) {
hasPresentMethod = true;
}
},

View File

@@ -0,0 +1,53 @@
/**
* ESLint rule: Presenters should only do pure mapping, not business logic
*
* Presenters should NOT use:
* - .filter() - filtering should happen in PageQuery
* - .sort() - sorting should happen in PageQuery
* - .reduce() - aggregation should happen in PageQuery
* - .find() - lookup should happen in PageQuery
* - .some() / .every() - checks should happen in PageQuery
*/
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Forbid business logic operations in presenters',
category: 'Presenter Purity',
},
messages: {
message: 'Presenter should only do pure mapping. Move {{operation}}() to PageQuery - see apps/website/lib/contracts/presenters/Presenter.ts',
},
},
create(context) {
return {
CallExpression(node) {
const filename = context.getFilename();
// Check if this is a presenter file
if (filename.includes('/lib/presenters/') && filename.endsWith('.ts')) {
// Check for business logic operations
if (node.callee.type === 'MemberExpression') {
const property = node.callee.property;
if (property.type === 'Identifier') {
const forbiddenOperations = ['filter', 'sort', 'reduce', 'find', 'some', 'every', 'map'];
const operation = property.name;
// Allow .map() - that's the core presenter operation
if (forbiddenOperations.includes(operation) && operation !== 'map') {
context.report({
node,
messageId: 'message',
data: { operation },
});
}
}
}
}
},
};
},
};