Skip to Content
Author's profile photo Jakob Marius Kjær

Create your own custom ESLint rule for SAPUI5 development

One of the best tools available to ensure better code quality and consistency is linting. We already have a large suite of rules we can apply on SAP WebIDE on our projects. You can find these under the project settings and Code checking

 

But what if you can’t find a rule that matches your requirement. Well that scenario happened to me recently and the beauty is it was fairly simple to create my own!

Heres how you do it.

There is plenty of blogs written on how to create your own ESlint plugin and rule. Follow the steps in that provided blog to install your dependencies and initiate your plugin.

Where to ball dropped for me what when i needed to use the ASTExplorer

I am a self taught developer and wouldn’t brag anywhere with being good at Javascript. So AST was like someone speaking polish to me.

Luckily I found this great video that explains it really well

So what I learned was that Javascript is parsed via AST (Abstract Syntax Tree) and as soon as you learn how to read it, it is actually pretty neat.

So in my custom plugin I wanted to ensure a proper naming convention like:

  • sVariableName for String
  • oVariableName for object
  • fVariableName for function
  • aVariableName for array
  • bVariableName for boolean
  • iVariableName for integer

So when you first open the AST explorer there is an awful lot of code that looks terrifying, but fear not. In my example I made sure the parser is set to espree and I deleted all the code and then replaced it with my unit test:

var oHello = {};
var sHello = "Hello";
var hello = "World";


var aArray = [];
var iInt = 9;
var bBool = true;
var bool = true;
var fFunction = function(){};
var myfunction = function(){};
    

My first example is var oHello = {}

The variabledecleration is the entire line. I have here a variabledeclerator which is identified by an id and in that id a name

 

After the = I have my {} which is an ObjectExpression

 

See not so scary after all is it?

Now click the transform button and choose eslint v4.

Two more windows appear. This is where you write your lint rule and see the output.

In my case I want my lint rule to run on all variableDeclerators so I add that with a function. All branches of your AST are addressed as nodes. So I added the following code:

export default function (context) {
	return {
		VariableDeclarator: function (node) {
			return
		}
	};

};

You will see that the lint rule hasn’t been fired. Because when you return, that is when stuff is good. We need to add a context report for the rule to trigger an error.

So replace the return with

context.report({
	node: node,
	message: "Bad naming of variable"
});

Now you’ll start to see all variables failing.

That means that we can add our acceptable cases.

export default function (context) {
	return {
		VariableDeclarator: function (node) {
			if (node.id.name.charAt(0) === "s" && (node.init === null || node.init.type === "Literal" || node.init.type === "CallExpression")) {
				return
			} else if (node.id.name.charAt(0) === "f" && !(node.init === null || node.init.type === "FunctionExpression" || node.init.type ===
					"CallExpression")) {
				return;
			} else if (node.id.name.charAt(0) === "o" &&
				(node.init === null || node.init.type === "CallExpression" || node.init.type ===
					"ObjectExpression")) {
				return;
			} else if (node.id.name.charAt(0) === "a" && (node.init === null || node.init.type === "CallExpression" || node.init.type ===
					"ArrayExpression")) {
				return;
			} else if (node.id.name.charAt(0) === "i" && (node.init === null || node.init.type === "CallExpression" || node.init.type ===
					"Literal")) {
				return;
			} else if (node.id.name.charAt(0) === "f" && (node.init === null || node.init.type === "FunctionExpression" || node.init.type ===
					"Literal")) {
				return;
			} else {
				context.report({
					node: node,
					message: "Bad naming of variable"
				});
			}
		}
	};

};

So in my rule i check on the first character and then afterwards whether the type is appropriate to the naming of the variable. Example my first variable oHello = {} needs to be of type ObjectExpression.

I’ve added in null as well because some devs might want to add the init to the variable later, I guess that is a way to get around my rule, maybe that is for a second rule to make sure they are always appropriately initialised.

So my output in the end for my rules is that some of my variables does indeed fail as they should

Now we have created our rule! Congrats.

 

Now let’s start using it in webide.

When you created your plugin and rule it added an empty shell to your js file for your eslint rule. Add the validations to that file so it looks like follows:

/**
 * @fileoverview Ensure a proper naming convention for your variables
 * @author Jakob Kjaer
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = {
	meta: {
		docs: {
			description: "Ensure a proper naming convention for your variables",
			category: "Error",
			recommended: true
		},
		fixable: null, // or "code" or "whitespace"
		schema: [
			// fill in your schema
		]
	},

	create: function (context) {

		// variables should be defined here

		//----------------------------------------------------------------------
		// Helpers
		//----------------------------------------------------------------------

		// any helper functions should go here or else delete this section

		//----------------------------------------------------------------------
		// Public
		//----------------------------------------------------------------------

		return {
			VariableDeclarator: function (node) {
				if (node.id.name.charAt(0) === "s" && (node.init === null || node.init.type === "Literal" || node.init.type === "CallExpression")) {
					return;
				} else if (node.id.name.charAt(0) === "f" && !(node.init === null || node.init.type === "FunctionExpression" || node.init.type ===
						"CallExpression")) {
					return;
				} else if (node.id.name.charAt(0) === "o" &&
					(node.init === null || node.init.type === "CallExpression" || node.init.type ===
						"ObjectExpression")) {
					return;
				} else if (node.id.name.charAt(0) === "a" && (node.init === null || node.init.type === "CallExpression" || node.init.type ===
						"ArrayExpression")) {
					return;
				} else if (node.id.name.charAt(0) === "i" && (node.init === null || node.init.type === "CallExpression" || node.init.type ===
						"Literal")) {
					return;
				} else if (node.id.name.charAt(0) === "f" && (node.init === null || node.init.type === "FunctionExpression" || node.init.type ===
						"Literal")) {
					return;
				} else {
					context.report({
						node: node,
						message: "Bad naming of variable"
					});
				}
			}

		};
	}
};

 

Now that is your rule. You can now test your rule as mentioned in the blog i linked to, where you install the plugings using Mocha.

Now if you follow follow these few steps  you can add your custom rule to webide.

I created it in a seperate folder and linked to that in my project settings. And I now see my rule and can use it actively.

 

Enjoy your new custom linting rules!

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jorge Cabanas
      Jorge Cabanas

      Thanks! Very interesting but I miss some steps here about the integration with WEBIDE. I have already read the blogs and is not much clear 

       

      Can you clarify what exactly is needed to add in the SAP WebIDE folder? Only the rule file .js?

      I didn't get the "Mocha part"

      Kind regards

      Author's profile photo Jakob Marius Kjær
      Jakob Marius Kjær
      Blog Post Author

      Hi Jorge, the mocha part is only for testing. If you want to add this to webide. Download the Js filewith the rule and out in a seperate folder and then reference that folder similar to this

      https://help.sap.com/viewer/825270ffffe74d9f988a0f0066ad59f0/Cloud/en-US/6335f91cb10f4176827747e3e545eeb4.html

      Author's profile photo Jorge Cabanas
      Jorge Cabanas

      Hi Jakob,

      First of all, now I can see the rule. The problem was that, at least in my case, there was no filter when the custom folder was selected. The custom rule was just included among the rest.

      So I didn't notice it before.

       

      I'm keeping researching because with this code there is a problem.
      I have just followed the same code that you provided but I got the next error:

      9:30:20 (Code Check failed for file /XXXXXX/webapp/controller/Main.controller.js) Uncaught TypeError: Error while loading rule 'no-bad-naming-variable': ruleCreator is not a function

      I'm looking at official ESLint website also, ESLint version, etc... any idea will be welcome
      If I get the solution I will post it for anyone who have to deal also with it

      Thanks for the post 🙂

      Author's profile photo Jakob Marius Kjær
      Jakob Marius Kjær
      Blog Post Author

      My eslint rule probably isn't ready for consumption. You are welcome to pull it from GitHub and make any additions. The ruletester is mentioned in the rules.js file as I recall.