website refactor

This commit is contained in:
2026-01-14 02:02:24 +01:00
parent 8d7c709e0c
commit 4522d41aef
291 changed files with 12763 additions and 9309 deletions

View File

@@ -2,11 +2,12 @@
* ESLint rule to enforce Services follow clean architecture patterns
*
* Services must:
* 1. Return Result types for type-safe error handling
* 2. Use DomainError types (not strings)
* 3. Be classes named *Service
* 4. Create their own dependencies (API Client, Logger, ErrorReporter)
* 5. Have NO constructor parameters (self-contained)
* 1. Explicitly implement Service<TApiDto, TError> interface
* 2. Return Result types for type-safe error handling
* 3. Use DomainError types (not strings)
* 4. Be classes named *Service
* 5. Create their own dependencies (API Client, Logger, ErrorReporter)
* 6. Have NO constructor parameters (self-contained)
*
* Note: Method names can vary (execute(), getSomething(), etc.)
*/
@@ -25,6 +26,7 @@ module.exports = {
mustReturnResult: 'Service methods must return Promise<Result<T, DomainError>>',
mustUseDomainError: 'Error types must be DomainError objects, not strings',
noConstructorParams: 'Services must be self-contained. Constructor cannot have parameters. Dependencies should be created inside the constructor.',
mustImplementContract: 'Services must explicitly implement Service<TApiDto, TError> interface',
},
},
@@ -48,6 +50,27 @@ module.exports = {
return; // Not a service class
}
// Check if class implements Service interface
// The implements clause can be:
// - implements Service
// - implements Service<TApiDto, TError>
// The AST structure is:
// impl.expression: Identifier { name: 'Service' }
// impl.typeArguments: TSTypeParameterInstantiation (for generic types)
const implementsService = node.implements && node.implements.some(impl => {
if (impl.expression.type === 'Identifier') {
return impl.expression.name === 'Service';
}
return false;
});
if (!implementsService) {
context.report({
node: node.id,
messageId: 'mustImplementContract',
});
}
// Check all methods for Result return types
node.body.body.forEach(member => {
if (member.type === 'MethodDefinition' &&