Skip to main content
Glama
no-old-registered-function-syntax.ts3.69 kB
import type { TSESTree } from "@typescript-eslint/utils"; import { CONVEX_REGISTRARS, createRule, isEntryPoint } from "../util.js"; /** * Rule to enforce using object syntax for Convex functions instead of the older function syntax */ export const noOldRegisteredFunctionSyntax = createRule({ name: "no-old-registered-function-syntax", meta: { type: "suggestion", docs: { description: "Don't use the non-object Convex function syntax. It's harder to add validation rules.", }, messages: { "use-object-syntax": "Use the object syntax for registered Convex queries, mutations, and actions.", }, schema: [], fixable: "code", }, defaultOptions: [], create: (context) => { // yes it's deprecated, but that's the version that exists // in eslint 8 const filename = context.getFilename(); // Skip generated files const isGenerated = filename.includes("_generated"); const entry = isEntryPoint(filename); if (isGenerated || !entry) { return {}; } /** * Check if the function has a second parameter (args parameter) * that would indicate it expects arguments */ function hasFunctionArgs( fn: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, ): boolean { return fn.params.length >= 2; } return { // Check variable declarations for exports that use the old syntax VariableDeclarator(node) { // Only interested in export declarations const parentDecl = node.parent; if (!parentDecl) return; const exportDecl = parentDecl.parent; if ( exportDecl?.type !== "ExportNamedDeclaration" && parentDecl.parent?.parent?.type !== "ExportNamedDeclaration" ) { return; } // Check if it's a call to a registrar with a function argument if ( node.init?.type === "CallExpression" && node.init.callee.type === "Identifier" && CONVEX_REGISTRARS.includes(node.init.callee.name) && node.init.arguments.length === 1 && (node.init.arguments[0].type === "ArrowFunctionExpression" || node.init.arguments[0].type === "FunctionExpression") ) { const functionArg = node.init.arguments[0] as | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression; // Report the issue context.report({ node: node.init, messageId: "use-object-syntax", fix: (fixer) => { // Check if the function has a second parameter (args) const hasArgsParam = hasFunctionArgs(functionArg); // Create object syntax replacement let fixText = "{\n"; // We only add empty args if there's no second parameter // If there is a second parameter, we leave args undefined for the no-missing-args-validator // rule to handle it correctly later if (!hasArgsParam) { fixText += " args: {},\n"; } // Preserve the original function as much as possible const sourceCode = context.getSourceCode(); // Get the original function text without the outer parentheses const originalFunctionText = sourceCode.getText(functionArg); // Add the handler property with the original function fixText += ` handler: ${originalFunctionText}`; fixText += "\n}"; return fixer.replaceText(functionArg, fixText); }, }); } }, }; }, });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server