Skip to main content

Add custom Rules using Plugins

Each plugin is an npm module with a name. It's recommended to use the format linthtml-plugin-<plugin-name>. You can also use scoped packages in the format of @<scope>/linthtml-plugin-<plugin-name> or even @<scope>/linthtml-plugin.

Expose Rules in Plugins​

Plugins can expose additional rules for use in LintHTML. To do so, the plugin must export an array of rules objects under the property rules. Each rules should contains a property name matching the following pattern <plugin-name>/<rule-id>. For example:

// The package `@linthtml/dom-utils` has some util functions
const { is_tag_node, node_tag_name } = require('@linthtml/dom-utils/tags');

module.exports = {
rules: [{
name: "custom/no-center-tag",
lint(node, rule_config, { report }) {
if (!is_tag_node(node)) {
// Node is pure text, comment, CDATA, Doctype, directive or root tag
return;
}
// Node is a tag `span, div, button...`
if (node_tag_name(node, 'name')) {
report({
message: "Do not use deprecated center element, use CSS instead to center content",
position: node.loc
})
}
}
}]
};

To use the rule in LintHTML, you would use same pattern (<plugin-name>/<rule-id>). So to activate/configure the rule "custom/no-center-tag", you would have to write the following in your LintHTML config file.

{
"rules": {
"custom/no-center-tag": "error"
}
}

Rules implementation​

The source file for a rule exports an object with the following properties.

  • name (string): The rule name, this property will be used to print the rule name along side an reported issue.

  • validateConfig (function): This function is optional and will be used to validate the config provided to the rule in the config file. This is usefull when you have a rule that only accept numbers or strings as config or if you want to limit the config possibility.

    For example the rule indent-style only accept tabs, spaces and nonmixed as config.

    const type_error = (option) =>
    `Configuration for rule "indent-style" is invalid: Expected string${allow_reg ? " or RegExp" : ""} got ${typeof option}.`;

    function list_value_error_message(value_list) {
    const list_copy = [...value_list];
    if (value_list.length > 1) {
    const last_value = list_copy.pop();
    return `Accepted values are ${list_copy.map((_) => `"${_}"`).join(", ")} and "${last_value}"`;
    }
    return `Accepted value is ${list_copy[0]}`;
    }

    return {
    name: "indent-style",
    validateConfig(config) {
    const accepted_values = ["tabs", "spaces", "nonmixed"]
    if (typeof option !== "string") {
    throw new Error(type_error(option));
    }

    if (accepted_values.indexOf(option) === -1) {
    throw new Error(
    `Configuration for rule "indent-style" is invalid: "${option}" is not accepted. ${list_value_error_message(
    accepted_values
    )}.`
    );
    }
    },
    lint() {
    //...
    }
    }
  • lint (function): This function will be called for every nodes in the abstract syntax tree (AST as defined here) for the documents that are linted. This function receive in input 3 parameters:

    • node (node spec the node traversed).
    • rule_config (any) the config for the rule. By default, it's the rule config defined in the linthtmlrc.* files but it can also be the config overrides defined in an inline instruction
    • options (object) this parameter contains the following property:
      • report (function) this is the function to use to report a lint issue. This function takes as argument the following object
        • position (Position see here) Location of the issue
        • message (string) Message describing the issue
      • global_config (object) [deprecated] An object containing the config of all activated rules.