Skip to Content

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!

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply