Skip to content

Commit

Permalink
refactor: create common validators for rules config
Browse files Browse the repository at this point in the history
  • Loading branch information
KamiKillertO committed Jul 31, 2020
1 parent 134286a commit e0b9cc4
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 132 deletions.
31 changes: 7 additions & 24 deletions lib/rules/attr-name-style/index.js
@@ -1,37 +1,21 @@
/* eslint-disable-next-line */
const { isRegExp } = require("util");
const proc = require("../../process_option");
const match_format = require("../../utils/check_format");
const { is_tag_node } = require("../../knife/tag_utils");
const { stringOrRegexp } = require("../../validate_option");

module.exports = {
name: "attr-name-style",
on: ["dom"],
need: "dom",
validateConfig(format) {
if (typeof format === "string" || isRegExp(format) === true) {
return format;
}
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string or RegExp got ${typeof format}`);
},
validateConfig: stringOrRegexp,
options: [
// REMOVE: For the v1
// Need to duplicate validateConfig to make it works with the old and the new Config system ><
{
validateConfig(format) {
if (typeof format === "string" || isRegExp(format) === true) {
return format;
}
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string or RegExp got ${typeof format}`);
}
validateConfig: stringOrRegexp
},
{
name: "attr-name-ignore-regex",
validateConfig(format) {
if (typeof format === "string" || isRegExp(format) === true) {
return format;
}
throw new Error(`Configuration for rule attr-name-ignore-regex is invalid: Expected string or RegExp got ${typeof format}`);
},
validateConfig: stringOrRegexp,
rules: []
}
]
Expand All @@ -47,12 +31,11 @@ module.exports.lint = function(node, config, { report }) {
let attributes = node.attributes.filter(({ name }) => /^¤+$/.test(name.chars) === false);
const ignore = config["attr-name-ignore-regex"];
if (ignore) {
const R = proc.regex(ignore);
attributes = attributes.filter(({ name }) => R.test(name.chars) === false);
attributes = attributes.filter(({ name }) => match_format(ignore, name.chars) === false);
}

attributes.forEach(({ name }) => {
if (proc.regex(format).test(name.chars) === false) {
if (match_format(format, name.chars) === false) {
report({
code: "E002",
position: name.loc,
Expand Down
20 changes: 4 additions & 16 deletions lib/rules/class-style/index.js
@@ -1,22 +1,12 @@
/* eslint-disable-next-line */
const { isRegExp } = require("util");
const proc = require("../../process_option");
const match_format = require("../../utils/check_format");
const { is_tag_node, attribute_value, has_attribute } = require("../../knife/tag_utils");
const { create_list_value_validator } = require("../../validate_option");

module.exports = {
name: "class-style",
on: ["dom"],
need: "dom",
validateConfig(option) {
if (typeof option !== "string" && isRegExp(option) === false) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string|regexp got ${typeof option}`);
}

if (["none", "lowercase", "underscore", "dash", "camel", "bem"].indexOf(option) === -1 && isRegExp(option) === false) {
throw new Error(`Configuration for rule "${this.name}" is invalid: "${option}" is not accepted. Accepted values are "none", "lowercase", "underscore", "dash", "camel" and "bem".`);
}
return option;
}
validateConfig: create_list_value_validator(["none", "lowercase", "underscore", "dash", "camel", "bem"])
};

function getClasses(class_attribute) {
Expand Down Expand Up @@ -48,9 +38,7 @@ function lint(node, options, { report }) {
const class_attribute = attribute_value(node, "class");
const classes = filterClasses(getClasses(class_attribute), options);

const regex = proc.regex(format);

classes.filter(_class => !regex.test(_class))
classes.filter(_class => !match_format(format, _class))
.forEach(_class => report({
code: "E011",
position: class_attribute.loc, // should be the location of the class and not the class_attribute
Expand Down
47 changes: 42 additions & 5 deletions lib/rules/id-style/__tests__/index.js
Expand Up @@ -109,7 +109,24 @@ describe("legacy linter | id-style", function() {
.to
.throw("Configuration for rule \"id-class-ignore-regex\" is invalid: You provide an empty string value");
});

it("should throw an error if rule config is empty", function() {
const linter = createLinter({ "id-style": "" });

expect(() => linter.lint(""))
.to
.throw("Configuration for rule \"id-style\" is invalid: \"\" is not accepted. Accepted values are \"lowercase\", \"underscore\", \"dash\", \"camel\" and \"bem\"");
});

it("should throw an error if rule config is provided with an invalid format", function() {
const linter = createLinter({ "id-style": "foo" });

expect(() => linter.lint(""))
.to
.throw("Configuration for rule \"id-style\" is invalid: \"foo\" is not accepted. Accepted values are \"lowercase\", \"underscore\", \"dash\", \"camel\" and \"bem\"");
});
});

describe("id-style", function() {
function createLinter(rules) {
return linthtml.fromConfig({ rules });
Expand Down Expand Up @@ -272,9 +289,29 @@ describe("id-style", function() {
});
});

// it("Should throw an error if `id-class-ignore-regex` is empty", function() {
// expect(() => linthtml.fromConfig({ "id-class-ignore-regex": "" }))
// .to
// .throw("Configuration for rule \"id-class-ignore-regex\" is invalid: You provide an empty string value");
// });
it("should throw an error if rule config is empty", function() {
const config = {
"id-style": [
true,
""
]
};

expect(() => createLinter(config))
.to
.throw("Configuration for rule \"id-style\" is invalid: \"\" is not accepted. Accepted values are \"lowercase\", \"underscore\", \"dash\", \"camel\" and \"bem\"");
});

it("should throw an error if rule config is provided with an invalid format", function() {
const config = {
"id-style": [
true,
"foo"
]
};

expect(() => createLinter(config))
.to
.throw("Configuration for rule \"id-style\" is invalid: \"foo\" is not accepted. Accepted values are \"lowercase\", \"underscore\", \"dash\", \"camel\" and \"bem\"");
});
});
46 changes: 10 additions & 36 deletions lib/rules/id-style/index.js
@@ -1,43 +1,26 @@
const proc = require("../../process_option");
/* eslint-disable-next-line */
const { isRegExp } = require("util");
const match_format = require("../../utils/check_format");
const { is_tag_node } = require("../../knife/tag_utils");
const lintClassStyle = require("../class-style").lint;
const {
create_list_value_validator,
create_string_or_regexp_validator
} = require("../../validate_option");

module.exports = {
name: "id-style",
on: ["dom"],
need: "dom",
validateConfig(format) {
if (typeof format === "string" || isRegExp(format) === true) {
return format;
}
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string or RegExp got ${typeof format}`);
},
validateConfig: create_list_value_validator(["lowercase", "underscore", "dash", "camel", "bem"]),
options: [
// REMOVE: For the v1
// Need to duplicate validateConfig to make it works with the old and the new Config system ><
{
need: "dom",
validateConfig(format) {
if (typeof format === "string" || isRegExp(format) === true) {
return format;
}
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string or RegExp got ${typeof format}`);
}
validateConfig: create_list_value_validator(["lowercase", "underscore", "dash", "camel", "bem"])
},
{
name: "id-class-style", // REMOVE: A rule be standalone and not call other rules
validateConfig(option) {
if (typeof option !== "string" && isRegExp(option) === false) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string|regexp got ${typeof option}`);
}

if (["none", "lowercase", "underscore", "dash", "camel", "bem"].indexOf(option) === -1 && isRegExp(option) === false) {
throw new Error(`Configuration for rule "${this.name}" is invalid: "${option}" is not accepted. Accepted values are "none", "lowercase", "underscore", "dash", "camel" and "bem".`);
}
return option;
},
validateConfig: create_list_value_validator(["lowercase", "underscore", "dash", "camel", "bem"]),
rules: ["class-style", "id-style"],
lint(node, opts, { report, rules }) {
if (!!rules["id-style"] === false && rules["id-class-style"]) {
Expand All @@ -51,15 +34,7 @@ module.exports = {
},
{
name: "id-class-ignore-regex",
validateConfig(options) {
if ((typeof options === "string" && options !== "") || isRegExp(options) === true) {
return options;
}
if (typeof options === "string") {
throw new Error(`Configuration for rule "${this.name}" is invalid: You provide an empty string value`);
}
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected string or RegExp got ${typeof options}`);
},
validateConfig: create_string_or_regexp_validator(false),
rules: [] // 'class', 'id-style'
}
]
Expand Down Expand Up @@ -91,8 +66,7 @@ function lint(node, format, ignore, report) {
}
attributes.forEach(attribute => {
const id = attribute.value.chars;
const regex = proc.regex(format);
if (regex.test(id) === false) {
if (match_format(format, id) === false) {
report({
code: "E011",
position: attribute.loc,
Expand Down
12 changes: 3 additions & 9 deletions lib/rules/indent-style/index.js
@@ -1,3 +1,5 @@
const { create_validation_for_numbers } = require("../../validate_option");

module.exports = {
name: "indent-style",
on: ["dom"],
Expand Down Expand Up @@ -28,15 +30,7 @@ module.exports = {
{
name: "indent-width", // ignored if indent-style is "tabs", display warning message ?

validateConfig(option) {
if (typeof option !== "number") {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected number got ${typeof option}`);
}
if (option < 0) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Only positive indent value are allowed.`);
}
return option;
},
validateConfig: create_validation_for_numbers(false),
lint(_, __, { rules }) {
if (rules["indent-style"]) {
return [];
Expand Down
21 changes: 3 additions & 18 deletions lib/rules/line-max-len/index.js
@@ -1,32 +1,17 @@
const { is_text_node } = require("../../knife/tag_utils");
const { get_lines } = require("../../knife/text_node_utils");
const { stringOrRegexp } = require("../../validate_option");
const { create_validation_for_numbers } = require("../../validate_option");

module.exports = {
name: "line-max-len",
on: ["dom"],
need: "dom",
validateConfig(option) {
if (typeof option !== "number") {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected number got ${typeof option}`);
}
if (option < 0) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Only positive indent value are allowed.`);
}
return option;
},
validateConfig: create_validation_for_numbers(false),
options: [
// REMOVE: For the v1
{
validateConfig(option) {
if (typeof option !== "number") {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected number got ${typeof option}`);
}
if (option < 0) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Only positive indent value are allowed.`);
}
return option;
}
validateConfig: create_validation_for_numbers(false)
},
{
name: "line-max-len-ignore-regex",
Expand Down
11 changes: 2 additions & 9 deletions lib/rules/title-max-len/index.js
@@ -1,18 +1,11 @@
const { is_tag_node } = require("../../knife/tag_utils");
const { create_validation_for_numbers } = require("../../validate_option");

module.exports = {
name: "title-max-len",
on: ["dom"],
need: "dom",
validateConfig(option) {
if (typeof option !== "number") {
throw new Error(`Configuration for rule "${this.name}" is invalid: Expected number got ${typeof option}`);
}
if (option < 0) {
throw new Error(`Configuration for rule "${this.name}" is invalid: Only positive indent value are allowed.`);
}
return option;
}
validateConfig: create_validation_for_numbers(false)
};

module.exports.lint = function(node, opts, { report }) {
Expand Down
20 changes: 6 additions & 14 deletions lib/process_option.js → lib/utils/check_format.js
Expand Up @@ -19,19 +19,11 @@ function getRegExp(val) {
}
}

module.exports = {
regex: function(regex) {
return getRegExp(regex);
},
regexGlobal: function(r) {
r = module.exports.regex(r);
return r && new RegExp(r.source, r.ignoreCase ? "gi" : "g");
},
format: function(name) {
const regex = getRegExp(name, function(s) {
return formats[s];
});

return regex && { desc: name, test: regex.test.bind(regex) };
module.exports = function(format, value) {
// return error is provided format does not exist
const R = getRegExp(format);
if (R) {
return R.test(value);
}
throw new Error(`Unknow format ${format}`);
};

0 comments on commit e0b9cc4

Please sign in to comment.