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.