I have a Logger class which beautifies the logs before showing them in JS browser console. I use .bind() to let console display correct script name and line (like script_name.ts:62) in the sources instead of always showing Logger.ts:130:
Logger
.bind()
script_name.ts:62
Logger.ts:130
console.log.bind(console, ...args)
console.log(...args)
Logger.log()
But there is a problem: I often forgot to call the function returned by Logger.log(). In this case I won’t see any log in the console. Is there any ESLint rule which may help to handle this and show warning when this happens?
Roughly the Logger code is:
class Logger { log(...args: any[]) { // doing here something with log args return console.log.bind(console, ...args); } } // correct call Logger.log("some text")(); // incorrect call (nothing will be shown) Logger.log("some text");
I use this in browser extension in content scripts, this case doesn’t work well with many existing logger libraries.
While ESLint doesn’t have a built-in rule to specifically catch situations where the logger’s returned function is not invoked immediately, you can achieve this by creating a custom ESLint rule. Here’s an example of how you might approach this:
@typescript-eslint/parser
@typescript-eslint/eslint-plugin
eslint
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint
// .eslintrc.js or .eslintrc.json { "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended" ], "rules": { "invoke-logger-function": ["error", "always"] }, "overrides": [ { "files": ["*.ts", "*.tsx"], "rules": { "@typescript-eslint/explicit-function-return-type": "off" } } ] }
``` // invoke-logger-function.ts import { Rule } from “eslint”; import { TSESTree } from “@typescript-eslint/experimental-utils”;
const rule: Rule.RuleModule = { meta: { type: “problem”, docs: { description: “Enforce immediate invocation of logger’s returned function”, category: “Best Practices”, recommended: true, }, fixable: null, }, create: (context) => { return { CallExpression(node: TSESTree.CallExpression) { if ( node.callee.type === “MemberExpression” && node.callee.property.type === “Identifier” && node.callee.property.name === “log” ) { const parentType = node.parent?.type; if (parentType !== “CallExpression”) { context.report({ node: node.callee.property, message: “Logger’s returned function should be invoked immediately.”, }); } } }, }; }, };
export default rule; ```
// .eslintrc.js or .eslintrc.json { // ... "plugins": ["@typescript-eslint", "./path/to/custom-rules"], "rules": { // ... "invoke-logger-function": ["error", "always"] }, // ... }
Ensure that the path to the custom rule (./path/to/custom-rules) is correct.
./path/to/custom-rules
npx eslint --ext .ts .
Now ESLint will show an error if you forget to immediately invoke the logger’s returned function.