diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 51ba02aea29..6e3b13e33c1 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -925,8 +925,8 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
}
const problem = reportTranslator(...args);
- if (problem.fix && rule.meta && !rule.meta.fixable) {
- throw new Error("Fixable rules should export a `meta.fixable` property.");
+ if (problem.fix && !(rule.meta && rule.meta.fixable)) {
+ throw new Error("Fixable rules must set the `meta.fixable` property to \"code\" or \"whitespace\".");
}
if (problem.suggestions && !(rule.meta && rule.meta.hasSuggestions === true)) {
if (rule.meta && rule.meta.docs && typeof rule.meta.docs.suggestion !== "undefined") {
diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js
index 2b5524923be..8498b7c3c8e 100644
--- a/lib/rule-tester/rule-tester.js
+++ b/lib/rule-tester/rule-tester.js
@@ -921,16 +921,6 @@ class RuleTester {
);
}
- // Rules that produce fixes must have `meta.fixable` property.
- if (result.output !== item.code) {
- assert.ok(
- hasOwnProperty(rule, "meta"),
- "Fixable rules should export a `meta.fixable` property."
- );
-
- // Linter throws if a rule that produced a fix has `meta` but doesn't have `meta.fixable`.
- }
-
assertASTDidntChange(result.beforeAST, result.afterAST);
}
diff --git a/tests/fixtures/rules/make-syntax-error-rule.js b/tests/fixtures/rules/make-syntax-error-rule.js
index 528b4b0f4de..fce60a56c4c 100644
--- a/tests/fixtures/rules/make-syntax-error-rule.js
+++ b/tests/fixtures/rules/make-syntax-error-rule.js
@@ -1,14 +1,19 @@
-module.exports = function(context) {
- return {
- Program: function(node) {
- context.report({
- node: node,
- message: "ERROR",
- fix: function(fixer) {
- return fixer.insertTextAfter(node, "this is a syntax error.");
- }
- });
- }
- };
+module.exports = {
+ meta: {
+ schema: [],
+ fixable: "code"
+ },
+ create(context) {
+ return {
+ Program: function(node) {
+ context.report({
+ node: node,
+ message: "ERROR",
+ fix: function(fixer) {
+ return fixer.insertTextAfter(node, "this is a syntax error.");
+ }
+ });
+ }
+ };
+ }
};
-module.exports.schema = [];
diff --git a/tests/fixtures/testers/rule-tester/fixes-one-problem.js b/tests/fixtures/testers/rule-tester/fixes-one-problem.js
index 9ed9ca71cbd..e692cae3386 100644
--- a/tests/fixtures/testers/rule-tester/fixes-one-problem.js
+++ b/tests/fixtures/testers/rule-tester/fixes-one-problem.js
@@ -5,19 +5,24 @@
"use strict";
-module.exports = context => {
- return {
- Program(node) {
- context.report({
- node,
- message: "No programs allowed."
- });
+module.exports = {
+ meta: {
+ fixable: "code"
+ },
+ create(context) {
+ return {
+ Program(node) {
+ context.report({
+ node,
+ message: "No programs allowed."
+ });
- context.report({
- node,
- message: "Seriously, no programs allowed.",
- fix: fixer => fixer.remove(node)
- });
+ context.report({
+ node,
+ message: "Seriously, no programs allowed.",
+ fix: fixer => fixer.remove(node)
+ });
+ }
}
}
};
diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js
index b2724ae20f9..25533506e6b 100644
--- a/tests/lib/linter/linter.js
+++ b/tests/lib/linter/linter.js
@@ -5106,17 +5106,24 @@ var a = "test2";
it("should use postprocessed problem ranges when applying autofixes", () => {
const code = "foo bar baz";
- linter.defineRule("capitalize-identifiers", context => ({
- Identifier(node) {
- if (node.name !== node.name.toUpperCase()) {
- context.report({
- node,
- message: "Capitalize this identifier",
- fix: fixer => fixer.replaceText(node, node.name.toUpperCase())
- });
- }
+ linter.defineRule("capitalize-identifiers", {
+ meta: {
+ fixable: "code"
+ },
+ create(context) {
+ return {
+ Identifier(node) {
+ if (node.name !== node.name.toUpperCase()) {
+ context.report({
+ node,
+ message: "Capitalize this identifier",
+ fix: fixer => fixer.replaceText(node, node.name.toUpperCase())
+ });
+ }
+ }
+ };
}
- }));
+ });
const fixResult = linter.verifyAndFix(
code,
@@ -5205,15 +5212,23 @@ var a = "test2";
});
it("stops fixing after 10 passes", () => {
- linter.defineRule("add-spaces", context => ({
- Program(node) {
- context.report({
- node,
- message: "Add a space before this node.",
- fix: fixer => fixer.insertTextBefore(node, " ")
- });
+
+ linter.defineRule("add-spaces", {
+ meta: {
+ fixable: "whitespace"
+ },
+ create(context) {
+ return {
+ Program(node) {
+ context.report({
+ node,
+ message: "Add a space before this node.",
+ fix: fixer => fixer.insertTextBefore(node, " ")
+ });
+ }
+ };
}
- }));
+ });
const fixResult = linter.verifyAndFix("a", { rules: { "add-spaces": "error" } });
@@ -5237,10 +5252,10 @@ var a = "test2";
assert.throws(() => {
linter.verify("0", { rules: { "test-rule": "error" } });
- }, /Fixable rules should export a `meta\.fixable` property.\nOccurred while linting :1$/u);
+ }, /Fixable rules must set the `meta\.fixable` property to "code" or "whitespace".\nOccurred while linting :1$/u);
});
- it("should not throw an error if fix is passed and there is no metadata", () => {
+ it("should throw an error if fix is passed and there is no metadata", () => {
linter.defineRule("test-rule", {
create: context => ({
Program(node) {
@@ -5249,7 +5264,21 @@ var a = "test2";
})
});
- linter.verify("0", { rules: { "test-rule": "error" } });
+ assert.throws(() => {
+ linter.verify("0", { rules: { "test-rule": "error" } });
+ }, /Fixable rules must set the `meta\.fixable` property/u);
+ });
+
+ it("should throw an error if fix is passed from a legacy-format rule", () => {
+ linter.defineRule("test-rule", context => ({
+ Program(node) {
+ context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+ }
+ }));
+
+ assert.throws(() => {
+ linter.verify("0", { rules: { "test-rule": "error" } });
+ }, /Fixable rules must set the `meta\.fixable` property/u);
});
});
diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js
index 3eef7982306..082d74c067d 100644
--- a/tests/lib/rule-tester/rule-tester.js
+++ b/tests/lib/rule-tester/rule-tester.js
@@ -1747,7 +1747,7 @@ describe("RuleTester", () => {
{ code: "var foo = bar;", output: "5", errors: 1 }
]
});
- }, "Fixable rules should export a `meta.fixable` property.");
+ }, /Fixable rules must set the `meta\.fixable` property/u);
});
it("should throw an error if a legacy-format rule produces fixes", () => {
@@ -1771,7 +1771,7 @@ describe("RuleTester", () => {
{ code: "var foo = bar;", output: "5", errors: 1 }
]
});
- }, "Fixable rules should export a `meta.fixable` property.");
+ }, /Fixable rules must set the `meta\.fixable` property/u);
});
describe("suggestions", () => {
@@ -2392,17 +2392,24 @@ describe("RuleTester", () => {
assert.throw(() => {
ruleTester.run(
"foo",
- context => ({
- Identifier(node) {
- context.report({
- node,
- message: "make a syntax error",
- fix(fixer) {
- return fixer.replaceText(node, "one two");
+ {
+ meta: {
+ fixable: "code"
+ },
+ create(context) {
+ return {
+ Identifier(node) {
+ context.report({
+ node,
+ message: "make a syntax error",
+ fix(fixer) {
+ return fixer.replaceText(node, "one two");
+ }
+ });
}
- });
+ };
}
- }),
+ },
{
valid: ["one()"],
invalid: []