@addon24/eslint-config
Version:
ESLint configuration rules for WorldOfTextcraft projects - Centralized configuration for all project types
241 lines (217 loc) • 8.62 kB
JavaScript
const enforceViteHealthMetricsRule = {
meta: {
type: "problem",
docs: {
description: "Enforce Vite configuration to include required health and metrics endpoints",
category: "Best Practices",
recommended: true,
},
fixable: null,
schema: [{
type: "object",
properties: {
requiredEndpoints: {
type: "array",
items: { type: "string" },
default: ["/health", "/health/live", "/health/ready", "/metrics"],
},
requiredPackages: {
type: "array",
items: { type: "string" },
default: ["@godaddy/terminus", "prom-client"],
},
requiredServices: {
type: "array",
items: { type: "string" },
default: ["HealthMetricsService", "MetricsService"],
},
},
additionalProperties: false,
}],
messages: {
missingHealthEndpoint: "Missing required health endpoint: {{endpoint}}. Add middleware for {{endpoint}} in Vite config.",
missingMetricsEndpoint: "Missing required metrics endpoint: {{endpoint}}. Add middleware for {{endpoint}} in Vite config.",
missingPackage: "Missing required package: {{package}}. Install {{package}} for health/metrics functionality.",
missingService: "Missing required service: {{service}}. Import and use {{service}} in Vite config.",
incorrectContentType: "Health endpoint {{endpoint}} should return 'text/plain' content type for Prometheus metrics.",
missingConfigureServer: "Vite config must include configureServer function for health/metrics endpoints.",
missingMiddlewares: "Vite config must include server.middlewares.use for health/metrics endpoints.",
},
},
create(context) {
const options = context.options[0] || {};
const requiredEndpoints = options.requiredEndpoints || ["/health", "/health/live", "/health/ready", "/metrics"];
const requiredPackages = options.requiredPackages || ["@godaddy/terminus", "prom-client"];
const requiredServices = options.requiredServices || ["HealthMetricsService", "MetricsService"];
let hasViteConfig = false;
let hasConfigureServer = false;
let hasMiddlewares = false;
let foundEndpoints = new Set();
let foundServices = new Set();
let foundPackages = new Set();
return {
// Check for Vite config file
Program() {
const filename = context.getFilename();
if (filename.includes("vite.config") || filename.includes("vite.config.ts") || filename.includes("vite.config.js")) {
hasViteConfig = true;
}
},
// Check for import statements
ImportDeclaration(node) {
const source = node.source.value;
if (requiredPackages.includes(source)) {
foundPackages.add(source);
}
},
// Check for configureServer function
FunctionDeclaration(node) {
if (node.id && node.id.name === "configureServer") {
hasConfigureServer = true;
}
},
// Check for ArrowFunctionExpression with configureServer
ArrowFunctionExpression(node) {
if (node.parent && node.parent.type === "Property" && node.parent.key && node.parent.key.name === "configureServer") {
hasConfigureServer = true;
}
},
// Check for server.middlewares.use calls and content type headers
CallExpression(node) {
// Check for server.middlewares.use calls
if (node.callee.type === "MemberExpression" &&
node.callee.object.type === "MemberExpression" &&
node.callee.object.object.name === "server" &&
node.callee.object.property.name === "middlewares" &&
node.callee.property.name === "use") {
hasMiddlewares = true;
// Check for endpoint path
const endpointArg = node.arguments[0];
if (endpointArg && endpointArg.type === "Literal" && typeof endpointArg.value === "string") {
const endpoint = endpointArg.value;
if (requiredEndpoints.includes(endpoint)) {
foundEndpoints.add(endpoint);
}
}
}
// Check for content type headers
if (node.callee.type === "MemberExpression" &&
node.callee.property.name === "setHeader") {
const headerName = node.arguments[0];
const headerValue = node.arguments[1];
if (headerName && headerName.type === "Literal" && headerName.value === "Content-Type") {
if (headerValue && headerValue.type === "Literal" && headerValue.value === "application/json") {
// Find the endpoint this belongs to by traversing up
let current = node.parent;
while (current && current.type !== "CallExpression") {
current = current.parent;
}
if (current && current.callee.type === "MemberExpression" &&
current.callee.property.name === "use") {
const endpointArg = current.arguments[0];
if (endpointArg && endpointArg.type === "Literal" &&
(endpointArg.value === "/health" || endpointArg.value === "/metrics")) {
context.report({
node: headerValue,
messageId: "incorrectContentType",
data: { endpoint: endpointArg.value }
});
}
}
}
}
}
},
// Check for service imports and usage
VariableDeclarator(node) {
if (node.init && node.init.type === "CallExpression" &&
node.init.callee.type === "Identifier" &&
node.init.callee.name === "import") {
const importArg = node.init.arguments[0];
if (importArg && importArg.type === "Literal" && typeof importArg.value === "string") {
const importPath = importArg.value;
if (importPath.includes("HealthMetricsService") || importPath.includes("MetricsService")) {
requiredServices.forEach(service => {
if (importPath.includes(service)) {
foundServices.add(service);
}
});
}
}
}
},
// Check for service instantiation
NewExpression(node) {
if (node.callee.type === "Identifier") {
const serviceName = node.callee.name;
if (requiredServices.includes(serviceName)) {
foundServices.add(serviceName);
}
}
},
// Final validation on program end
"Program:exit"() {
if (!hasViteConfig) {
return; // Not a Vite config file
}
// Check for missing packages
requiredPackages.forEach(packageName => {
if (!foundPackages.has(packageName)) {
context.report({
node: context.getSourceCode().ast,
messageId: "missingPackage",
data: { package: packageName }
});
}
});
// Check for missing services
requiredServices.forEach(serviceName => {
if (!foundServices.has(serviceName)) {
context.report({
node: context.getSourceCode().ast,
messageId: "missingService",
data: { service: serviceName }
});
}
});
// Check for missing endpoints
requiredEndpoints.forEach(endpoint => {
if (!foundEndpoints.has(endpoint)) {
if (endpoint === "/health" || endpoint === "/metrics") {
context.report({
node: context.getSourceCode().ast,
messageId: "missingMetricsEndpoint",
data: { endpoint }
});
} else {
context.report({
node: context.getSourceCode().ast,
messageId: "missingHealthEndpoint",
data: { endpoint }
});
}
}
});
// Check for configureServer function
if (!hasConfigureServer) {
context.report({
node: context.getSourceCode().ast,
messageId: "missingConfigureServer"
});
}
// Check for middlewares
if (!hasMiddlewares) {
context.report({
node: context.getSourceCode().ast,
messageId: "missingMiddlewares"
});
}
}
};
}
};
export default {
rules: {
"enforce-vite-health-metrics": enforceViteHealthMetricsRule,
},
};