Files
gridpilot.gg/apps/website/eslint-rules/services-no-instantiation.js
2026-01-13 00:16:14 +01:00

91 lines
2.9 KiB
JavaScript

/**
* ESLint rule to forbid instantiation in services
*
* Services should not instantiate other services, API clients, or adapters.
* They should receive dependencies via constructor injection.
*/
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Forbid instantiation in services',
category: 'Services',
recommended: true,
},
fixable: null,
schema: [],
messages: {
noInstantiation: 'Services should not instantiate {{type}} "{{name}}". Use constructor injection instead.',
noNewInServices: 'Services should not use new keyword. Use constructor injection.',
},
},
create(context) {
const filename = context.getFilename();
const isInServices = filename.includes('/lib/services/');
if (!isInServices) return {};
return {
// Track new keyword usage
NewExpression(node) {
const callee = node.callee;
// Get the name being instantiated
let instantiatedName = '';
if (callee.type === 'Identifier') {
instantiatedName = callee.name;
} else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
instantiatedName = callee.property.name;
}
// Check if it's a service, API client, or adapter
const isService = instantiatedName.endsWith('Service');
const isApiClient = instantiatedName.endsWith('ApiClient') ||
instantiatedName.endsWith('Client');
const isAdapter = instantiatedName.includes('Adapter');
const isRepository = instantiatedName.includes('Repository');
const isGateway = instantiatedName.includes('Gateway');
if (isService || isApiClient || isAdapter || isRepository || isGateway) {
const type = isService ? 'Service' :
isApiClient ? 'API Client' :
isAdapter ? 'Adapter' :
isRepository ? 'Repository' : 'Gateway';
context.report({
node,
messageId: 'noInstantiation',
data: { type, name: instantiatedName },
});
} else {
// Any new keyword in services is suspicious
context.report({
node,
messageId: 'noNewInServices',
});
}
},
// Also check for object literal instantiation
ObjectExpression(node) {
// Check if this is being assigned to a variable that looks like a service
const parent = node.parent;
if (parent && parent.type === 'VariableDeclarator') {
const varName = parent.id.name;
if (varName.endsWith('Service') ||
varName.endsWith('Client') ||
varName.includes('Adapter')) {
context.report({
node,
messageId: 'noInstantiation',
data: { type: 'object literal', name: varName },
});
}
}
},
};
},
};