Skip to content

Commit

Permalink
tools: add require-order rule to detect require with out of order V…
Browse files Browse the repository at this point in the history
…ariableDeclarator
  • Loading branch information
cola119 committed Aug 3, 2022
1 parent 6f1fd0d commit 80c4ae3
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ rules:
node-core/lowercase-name-for-primitive: error
node-core/non-ascii-character: error
node-core/no-array-destructuring: error
node-core/require-order: error
node-core/prefer-primordials:
- error
- name: AggregateError
Expand Down
61 changes: 61 additions & 0 deletions test/parallel/test-eslint-require-order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

const common = require('../common');
if ((!common.hasCrypto) || (!common.hasIntl)) {
common.skip('ESLint tests require crypto and Intl');
}

common.skipIfEslintMissing();

const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
const rule = require('../../tools/eslint-rules/require-order');

new RuleTester({
parserOptions: { ecmaVersion: 6 },
})
.run('require-order', rule, {
valid: [
"const A = require('path')",
'const A = primordials',
"const { A } = require('path')",
'const { A } = primordials',
"const { A, B } = require('path')",
'const { A, B } = primordials',
"const { B: a, A: b } = require('path')",
'const { B: a, A: b } = primordials',
],
invalid: [
{
code: "const { B, A } = require('path')",
errors: [{ message: 'A should occur before B' }]
},
{
code: 'const { B, A } = primordials',
errors: [{ message: 'A should occur before B' }]
},
{
code: "const { A: b, A: a } = require('path')",
errors: [{ message: 'a should occur before b' }]
},
{
code: 'const { A: b, A: a } = primordials',
errors: [{ message: 'a should occur before b' }]
},
{
code: "const { C, B, A } = require('path')",
errors: [{ message: 'B should occur before C' }]
},
{
code: 'const { C, B, A } = primordials',
errors: [{ message: 'B should occur before C' }]
},
{
code: "const { C, A, B } = require('path')",
errors: [{ message: 'A should occur before C' }]
},
{
code: 'const { C, A, B } = primordials',
errors: [{ message: 'A should occur before C' }]
},
]
});
71 changes: 71 additions & 0 deletions tools/eslint-rules/require-order.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

const { isTopLevelRequireCall } = require('./rules-utils.js');

const getRequiredNodesFromRequireCallExpression = (node) => {
if (
node &&
node.parent &&
node.parent.id &&
node.parent.id.type === 'ObjectPattern'
) {
return node.parent.id.properties.map((p) => p.value);
}
};

const isPrimordialsDeclarator = (node) => {
return (
node &&
node.type === 'VariableDeclarator' &&
node.init?.name === 'primordials'
);
};

const getRequiredNodesFromPrimordialsDeclarator = (node) => {
if (
node &&
node.id &&
node.id.type === 'ObjectPattern'
) {
return node.id.properties.map((p) => p.value);
}
};

const findOutOfOrderIndex = (nodes) => {
for (let i = 0; i < nodes.length - 1; i++) {
if (nodes[i].name > nodes[i + 1].name) return i;
}
return -1;
};

module.exports = {
create(context) {
const reportOutOfOrder = (target, requiredNodes, outOfOrderIndex) => {
const before = requiredNodes[outOfOrderIndex];
const after = requiredNodes[outOfOrderIndex + 1];
context.report(
target,
`${after.name} should occur before ${before.name}`
);
};

return {
CallExpression(node) {
if (!isTopLevelRequireCall(node)) return;
const requiredNodes = getRequiredNodesFromRequireCallExpression(node);
if (!requiredNodes) return;
const outOfOrderIndex = findOutOfOrderIndex(requiredNodes);
if (outOfOrderIndex === -1) return;
reportOutOfOrder(node, requiredNodes, outOfOrderIndex);
},
VariableDeclarator(node) {
if (!isPrimordialsDeclarator(node)) return;
const requiredNodes = getRequiredNodesFromPrimordialsDeclarator(node);
if (!requiredNodes) return;
const outOfOrderIndex = findOutOfOrderIndex(requiredNodes);
if (outOfOrderIndex === -1) return;
reportOutOfOrder(node, requiredNodes, outOfOrderIndex);
},
};
},
};

0 comments on commit 80c4ae3

Please sign in to comment.