# Advanced configuration: Custom rules

In this walkthrough, we will create a new file locator and rule from scratch.

Our task will be to verify that prettier is configured to enforce single quotes (the singleQuote directive in prettier's configuration).

# File locator

The locator must implement the FileGlob interface. In short, it must expose properties include and exclude (both string arrays) that can be set at runtime based on user configuration. It must also expose findFiles(), which returns a promise that resolves to a list of filenames.

Since we know the name of the file we want to find and the expected location (.prettierrc in the root of the pacakge), there's no need to search for any files. We can simply return a resolved promise.

"use strict";

const prettierRcLocator = {
    findFiles: () => {
        return new Promise((resolve) => {
            resolve(['.prettierrc']);
        });
    }
}

module.exports = {
    ruleSets: [{
        fileLocator: prettierRcLocator,
        checks: []
    }]
};

# Check for singleQuote

Next we will verify that the prettier configuration meets expectations.

# Create the rule

Our rule must expose a name attribute and a check method.

The name is used when printing errors, so should be a unique and descriptive label that will be useful in CI output.

The check method will be passed 1 FileContext object at a time, and must return a promise that resolves to a list of Result objects (Success and Failure being the most common).

const { Success, Failure } = require('@boll/core');

const prettierRcSingleQuoteChecker = {
    name: "PrettierRcSingleQuoteChecker",
    check: (file) => {
        return new Promise((resolve) => {
            const contents = JSON.parse(file.content);
            if(contents.singleQuote) {
                resolve([new Success()]);
            }
            else {
                resolve([new Failure("PrettierRcSingleQuoteChecker", file.filename, 0, "Expected singleQuote to be true, but wasn't!")]);
            }
        });
    }
}

# Register the rule

The rule must be registered with boll so that it can be invoked during the run.

const { RuleRegistryInstance } = require("@boll/core");
RuleRegistryInstance.register("PrettierRcSingleQuoteChecker", () => prettierRcSingleQuoteChecker);

# Putting it altogether

With the locator and check in place, we just need to mention the rule inside the checks block of the exported config. The entire .boll.config.js looks this way after adding this last bit of config.

"use strict";

const { RuleRegistryInstance, Success, Failure } = require('@boll/core');

const prettierRcSingleQuoteChecker = {
    name: "PrettierRcSingleQuoteChecker",
    check: (file) => {
        return new Promise((resolve) => {
            const contents = JSON.parse(file.content);
            if(contents.singleQuote) {
                resolve([new Success()]);
            }
            else {
                resolve([new Failure("PrettierRcSingleQuoteChecker", file.filename, 0, "Expected singleQuote to be true, but wasn't!")]);
            }
        });
    }
};

const prettierRcLocator = {
    findFiles: () => {
        return new Promise((resolve) => {
            resolve(['.prettierrc']);
        });
    }
}

RuleRegistryInstance.register("PrettierRcSingleQuoteChecker", () => prettierRcSingleQuoteChecker);

module.exports = {
    ruleSets: [{
        fileLocator: prettierRcLocator,
        checks: [{rule: "PrettierRcSingleQuoteChecker"}]
    }]
};

Now, running with an incorrect .prettierrc:

{
  "singleQuote": false
}
[/tmp/sample-project]# ./node_modules/.bin/boll run
[PrettierRcSingleQuoteChecker] /private/tmp/sample-project/.prettierrc:0 Expected singleQuote to be true, but wasn't!
@boll/cli detected lint errors

However, after fixing:

{
  "singleQuote": true
}
[/tmp/sample-project]# ./node_modules/.bin/boll run
[/tmp/sample-project]# echo $?
0