This article takes care about adding a local rule to an already setup esLint environment. So make sure this is ready and working before starting to use this guide.
Ok at first we need a certain package to make our lives a bit easier.
1 2 3yarn add --dev eslint-plugin-local-rules OR npm install --save-dev eslint-plugin-local-rules
Heads up here. You can also write a custom rule without this plugin and the newest version of ESLint. But this also needs the new config file structure. More on that in here.
Just add this string to the plugins array of your config file.
1 2 3 4 5// .eslintrc.js module.exports = { plugins: ['eslint-plugin-local-rules'], };
Now create a config file in the root of your project where the library looks for local rules. In this example I created a new directory were the local rules live, but you can also define the rules code in here.
1 2 3 4 5// eslint-local-rules.js module.exports = { 'check-for-words': require('./eslint-rules/check-for-words'), };
Here comes the most interesting part. How to write the rule which checks for certain strings in your files scanned by ESLint.
Lets image we have an API which is called from our frontend application, which has certain query parameters. There is one query parameter 'no-cache' and this disables the caching layer for debugging purposes. It can happen that you forgot to remove this query parameter and it can result in an increased bill. With our rule here, we try to prevent this from going to production in the first place.
ESLint has a context function with multiple callbacks each holding the node for different types of strings.
Here comes my example. It does not cover 100% of the cases but its already pretty bullet proof.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64// ./eslint-rules/check-for-words.js const regexCheckLiterals = /caching-none/; const regexTemplateLiteral = /caching-/; function reportIssue (context, node) { context.report({ node, messageId: 'foundWord', }) } module.exports = { meta: { type: 'problem', docs: { description: 'Prevent using the contentful-published and contentful-preview query parameters for content-api', category: 'Best Practices', recommended: true, url: 'In here you can link some docs which explains the problem' }, messages: { foundWord: 'Warning! Usage of caching-none for api is a risk. This can increase the number of API calls and so the bill. \n' + 'Please check the article to clarify the right usage of the api --->', }, schema: [], }, create: function (context) { return { Literal (node) { const value = node.value; if (typeof value === 'string' && regexCheckLiterals.test(value)) { reportIssue(context, node); } }, TemplateLiteral (node) { node.quasis.forEach(quasi => { const value = quasi.value.raw; if (regexTemplateLiteral.test(value)) { reportIssue(context, node); } }) }, BinaryExpression(node) { if ( node.operator === '+' && node.left.type === 'Literal' && node.right.type === 'Literal' ) { const concatenatedValue = `${node.left.value}${node.right.value}`; if (regexCheckLiterals.test(concatenatedValue)) { reportIssue(context, node); } } }, } }, }
At the last step we need to enable the rule in the config file and either make it a warning or throw an error.
1 2 3 4 5 6 7// .eslintrc.js module.exports = { rules: { 'local-rules/check-for-words': 'warn', }, };
This is a very specific use case for an ESLint rule, but you can customise the code to your needs of corse. If there is a special case in you code where this rule should be violated, you can always use the ESLint comments to suppress the error or warning for the next line of code or the entire file like this
1/* eslint-disable local-rules/check-for-words */