Test internal eslint rules (#9929)
This commit is contained in:
1 parent
f1574a9e7a
commit
c55f899b32
6 files changed
+238
-3
No files matched your search
@@ -0,0 +1,28 @@
|
|||||||
|
name: Internal_ESLint_Rules_Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- "scripts/tools/eslint-plugin-prettier-internal-rules"
|
||||||
|
- ".github/workflows/eslint-rules.yml"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "scripts/tools/eslint-plugin-prettier-internal-rules"
|
||||||
|
- ".github/workflows/eslint-rules.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2.3.4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v2.1.4
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: cd scripts/tools/eslint-plugin-prettier-internal-rules && yarn test-coverage
|
||||||
@@ -21,3 +21,5 @@ package-lock.json
|
|||||||
!.yarn/sdks
|
!.yarn/sdks
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
.nyc_output
|
||||||
|
/scripts/tools/eslint-plugin-prettier-internal-rules/node_modules
|
||||||
+6
-2
@@ -53,7 +53,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
messages: {
|
messages: {
|
||||||
[MESSAGE_ID_PREFER_NAME_CHECK]:
|
[MESSAGE_ID_PREFER_NAME_CHECK]:
|
||||||
"Prefer `name {{operator}} {{property}}` over `parent.{{property}} {{operator}} node`",
|
"Prefer `name {{operator}} {{propertyText}}` over `parent.{{property}} {{operator}} node`.",
|
||||||
[MESSAGE_ID_NAME_CHECK_FIRST]:
|
[MESSAGE_ID_NAME_CHECK_FIRST]:
|
||||||
"`name` comparison should be on left side.",
|
"`name` comparison should be on left side.",
|
||||||
},
|
},
|
||||||
@@ -79,7 +79,11 @@ module.exports = {
|
|||||||
context.report({
|
context.report({
|
||||||
node,
|
node,
|
||||||
messageId: MESSAGE_ID_PREFER_NAME_CHECK,
|
messageId: MESSAGE_ID_PREFER_NAME_CHECK,
|
||||||
data: { property: propertyText, operator },
|
data: {
|
||||||
|
property: sourceCode.getText(property),
|
||||||
|
propertyText,
|
||||||
|
operator,
|
||||||
|
},
|
||||||
fix: (fixer) =>
|
fix: (fixer) =>
|
||||||
fixer.replaceText(node, `name ${operator} ${propertyText}`),
|
fixer.replaceText(node, `name ${operator} ${propertyText}`),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,8 +50,14 @@ module.exports = {
|
|||||||
];
|
];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
// avoid report on `const {comments} = node` twice
|
||||||
|
const reported = new Set();
|
||||||
return {
|
return {
|
||||||
[selector](node) {
|
[selector](node) {
|
||||||
|
if (reported.has(node)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ignored.has(fileName)) {
|
if (ignored.has(fileName)) {
|
||||||
const functionNames = ignored.get(fileName);
|
const functionNames = ignored.get(fileName);
|
||||||
if (functionNames === true) {
|
if (functionNames === true) {
|
||||||
@@ -75,6 +81,7 @@ module.exports = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reported.add(node);
|
||||||
context.report({
|
context.report({
|
||||||
node,
|
node,
|
||||||
messageId,
|
messageId,
|
||||||
|
|||||||
@@ -5,5 +5,9 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"author": "fisker",
|
"author": "fisker",
|
||||||
"main": "./index.js",
|
"main": "./index.js",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test.js",
|
||||||
|
"test-coverage": "npx nyc node test.js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const path = require("path");
|
||||||
|
const { outdent } = require("outdent");
|
||||||
|
const { RuleTester } = require("eslint");
|
||||||
|
const { rules } = require(".");
|
||||||
|
|
||||||
|
const test = (ruleId, tests) => {
|
||||||
|
new RuleTester({ parserOptions: { ecmaVersion: 2021 } }).run(
|
||||||
|
ruleId,
|
||||||
|
rules[ruleId],
|
||||||
|
tests
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
test("better-parent-property-check-in-needs-parens", {
|
||||||
|
valid: ["function needsParens() {return parent.test === node;}"],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: 'return parent.type === "MemberExpression" && name === "object";',
|
||||||
|
errors: [{ message: "`name` comparison should be on left side." }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "return parent.test === node;",
|
||||||
|
output: 'return name === "test";',
|
||||||
|
errors: [
|
||||||
|
{ message: 'Prefer `name === "test"` over `parent.test === node`.' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "return parent.test !== node;",
|
||||||
|
output: 'return name !== "test";',
|
||||||
|
errors: [
|
||||||
|
{ message: 'Prefer `name !== "test"` over `parent.test !== node`.' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: 'return parent["property"] === node;',
|
||||||
|
output: 'return name === "property";',
|
||||||
|
errors: [
|
||||||
|
{
|
||||||
|
message:
|
||||||
|
'Prefer `name === "property"` over `parent."property" === node`.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
].map((testCase) => ({
|
||||||
|
...testCase,
|
||||||
|
code: `function needsParens() {${testCase.code}}`,
|
||||||
|
output: `function needsParens() {${testCase.output || testCase.code}}`,
|
||||||
|
filename: "needs-parens.js",
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
test("directly-loc-start-end", {
|
||||||
|
valid: [],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: "options.locStart(node)",
|
||||||
|
output: "locStart(node)",
|
||||||
|
errors: [
|
||||||
|
{ message: "Please import `locStart` function and use it directly." },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "options.locEnd(node)",
|
||||||
|
output: "locEnd(node)",
|
||||||
|
errors: [
|
||||||
|
{ message: "Please import `locEnd` function and use it directly." },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jsx-identifier-case", {
|
||||||
|
valid: [
|
||||||
|
{
|
||||||
|
code: "const isJSXNode = true",
|
||||||
|
options: ["isJSXNode"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: "function isJSXNode(){}",
|
||||||
|
output: "function isJsxNode(){}",
|
||||||
|
errors: [{ message: "Please rename 'isJSXNode' to 'isJsxNode'." }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "const isJSXNode = true",
|
||||||
|
output: "const isJsxNode = true",
|
||||||
|
errors: [{ message: "Please rename 'isJSXNode' to 'isJsxNode'." }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("no-node-comments", {
|
||||||
|
valid: [
|
||||||
|
"const comments = node.notComments",
|
||||||
|
{
|
||||||
|
code: "function functionName() {return node.comments;}",
|
||||||
|
filename: path.join(__dirname, "../../..", "a.js"),
|
||||||
|
options: ["a.js"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "function functionName() {return node.comments;}",
|
||||||
|
filename: path.join(__dirname, "../../..", "a.js"),
|
||||||
|
options: [{ file: "a.js", functions: ["functionName"] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
...[
|
||||||
|
"function functionName() {return node.comments;}",
|
||||||
|
"const {comments} = node",
|
||||||
|
"const {comments: nodeComments} = node",
|
||||||
|
].map((code) => ({
|
||||||
|
code,
|
||||||
|
output: code,
|
||||||
|
errors: [{ message: "Do not access node.comments." }],
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
code: "function notFunctionName() {return node.comments;}",
|
||||||
|
output: "function notFunctionName() {return node.comments;}",
|
||||||
|
filename: path.join(__dirname, "../../..", "a.js"),
|
||||||
|
options: [{ file: "a.js", functions: ["functionName"] }],
|
||||||
|
errors: [{ message: "Do not access node.comments." }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("prefer-fast-path-each", {
|
||||||
|
valid: ["const foo = path.map()"],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: "path.map()",
|
||||||
|
output: "path.each()",
|
||||||
|
errors: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("prefer-is-non-empty-array", {
|
||||||
|
valid: [
|
||||||
|
// `isNonEmptyArray` self is ignored
|
||||||
|
outdent`
|
||||||
|
function isNonEmptyArray(object){
|
||||||
|
return Array.isArray(object) && object.length;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"a.b && a.c.length",
|
||||||
|
"a.b || !a.b.length",
|
||||||
|
'!a["b"] || !a.b.length',
|
||||||
|
],
|
||||||
|
invalid: [
|
||||||
|
...[
|
||||||
|
"a && a.b && a.b.length",
|
||||||
|
"a && a.b && a.b.length !== 0",
|
||||||
|
"a && a.b && a.b.length > 0",
|
||||||
|
"a && Array.isArray(a.b) && a.b.length",
|
||||||
|
"a && Array.isArray(a.b) && a.b.length !== 0",
|
||||||
|
"a && Array.isArray(a.b) && a.b.length > 0",
|
||||||
|
].map((code) => ({
|
||||||
|
code,
|
||||||
|
output: "a && isNonEmptyArray(a.b)",
|
||||||
|
errors: 1,
|
||||||
|
})),
|
||||||
|
...[
|
||||||
|
"!a || !a.b || !a.b.length",
|
||||||
|
"!a || !a.b || a.b.length === 0",
|
||||||
|
"!a || !Array.isArray(a.b) || !a.b.length",
|
||||||
|
"!a || !Array.isArray(a.b) || a.b.length === 0",
|
||||||
|
].map((code) => ({
|
||||||
|
code,
|
||||||
|
output: "!a || !isNonEmptyArray(a.b)",
|
||||||
|
errors: 1,
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
test("require-json-extensions", {
|
||||||
|
valid: ['require("./not-exists")', 'require("./index")'],
|
||||||
|
invalid: [
|
||||||
|
{
|
||||||
|
code: 'require("./package")',
|
||||||
|
filename: __filename,
|
||||||
|
output: 'require("./package.json")',
|
||||||
|
errors: [{ message: 'Missing file extension ".json" for "./package".' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
Reference in new issue
Block a user