Skip to content

Commit

Permalink
Use isNodeValueNotDomNode instead of selectors (#2099)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed May 15, 2023
1 parent a12831e commit 2a0b40f
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 73 deletions.
28 changes: 16 additions & 12 deletions rules/prefer-dom-node-append.js
@@ -1,24 +1,28 @@
'use strict';
const isValueNotUsable = require('./utils/is-value-not-usable.js');
const {methodCallSelector, notDomNodeSelector} = require('./selectors/index.js');
const {isMethodCall} = require('./ast/index.js');
const {isNodeValueNotDomNode, isValueNotUsable} = require('./utils/index.js');

const MESSAGE_ID = 'prefer-dom-node-append';
const messages = {
[MESSAGE_ID]: 'Prefer `Node#append()` over `Node#appendChild()`.',
};
const selector = [
methodCallSelector({
method: 'appendChild',
argumentsLength: 1,
includeOptionalMember: true,
}),
notDomNodeSelector('callee.object'),
notDomNodeSelector('arguments.0'),
].join('');

/** @param {import('eslint').Rule.RuleContext} context */
const create = () => ({
[selector](node) {
CallExpression(node) {
if (
!isMethodCall(node, {
method: 'appendChild',
argumentsLength: 1,
optionalCall: false,
computed: false,
})
|| isNodeValueNotDomNode(node.callee.object)
|| isNodeValueNotDomNode(node.arguments[0])
) {
return;
}

const fix = isValueNotUsable(node)
? fixer => fixer.replaceText(node.callee.property, 'append')
: undefined;
Expand Down
38 changes: 22 additions & 16 deletions rules/prefer-dom-node-remove.js
@@ -1,10 +1,13 @@
'use strict';
const {isParenthesized, hasSideEffect} = require('@eslint-community/eslint-utils');
const {methodCallSelector, notDomNodeSelector} = require('./selectors/index.js');
const needsSemicolon = require('./utils/needs-semicolon.js');
const isValueNotUsable = require('./utils/is-value-not-usable.js');
const {getParenthesizedText} = require('./utils/parentheses.js');
const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object.js');
const {isMethodCall} = require('./ast/index.js');
const {
getParenthesizedText,
isNodeValueNotDomNode,
isValueNotUsable,
needsSemicolon,
shouldAddParenthesesToMemberExpressionObject,
} = require('./utils/index.js');

const ERROR_MESSAGE_ID = 'error';
const SUGGESTION_MESSAGE_ID = 'suggestion';
Expand All @@ -13,16 +16,6 @@ const messages = {
[SUGGESTION_MESSAGE_ID]: 'Replace `parentNode.removeChild(childNode)` with `childNode{{dotOrQuestionDot}}remove()`.',
};

const selector = [
methodCallSelector({
method: 'removeChild',
argumentsLength: 1,
includeOptionalMember: true,
}),
notDomNodeSelector('callee.object'),
notDomNodeSelector('arguments.0'),
].join('');

// TODO: Don't check node.type twice
const isMemberExpressionOptionalObject = node =>
node.parent.type === 'MemberExpression'
Expand All @@ -37,7 +30,20 @@ const create = context => {
const {sourceCode} = context;

return {
[selector](node) {
CallExpression(node) {
if (
!isMethodCall(node, {
method: 'removeChild',
argumentsLength: 1,
optionalCall: false,
computed: false,
})
|| isNodeValueNotDomNode(node.callee.object)
|| isNodeValueNotDomNode(node.arguments[0])
) {
return;
}

const parentNode = node.callee.object;
const childNode = node.arguments[0];

Expand Down
27 changes: 16 additions & 11 deletions rules/prefer-query-selector.js
@@ -1,20 +1,12 @@
'use strict';
const {methodCallSelector, notDomNodeSelector} = require('./selectors/index.js');
const {isStringLiteral, isNullLiteral} = require('./ast/index.js');
const {isNodeValueNotDomNode} = require('./utils/index.js');
const {isMethodCall, isStringLiteral, isNullLiteral} = require('./ast/index.js');

const MESSAGE_ID = 'prefer-query-selector';
const messages = {
[MESSAGE_ID]: 'Prefer `.{{replacement}}()` over `.{{method}}()`.',
};

const selector = [
methodCallSelector({
methods: ['getElementById', 'getElementsByClassName', 'getElementsByTagName'],
argumentsLength: 1,
}),
notDomNodeSelector('callee.object'),
].join('');

const disallowedIdentifierNames = new Map([
['getElementById', 'querySelector'],
['getElementsByClassName', 'querySelectorAll'],
Expand Down Expand Up @@ -96,7 +88,20 @@ const fix = (node, identifierName, preferredSelector) => {

/** @param {import('eslint').Rule.RuleContext} context */
const create = () => ({
[selector](node) {
CallExpression(node) {
if (
!isMethodCall(node, {
methods: ['getElementById', 'getElementsByClassName', 'getElementsByTagName'],
argumentsLength: 1,
optionalCall: false,
optionalMember: false,
computed: false,
})
|| isNodeValueNotDomNode(node.callee.object)
) {
return;
}

const method = node.callee.property.name;
const preferredSelector = disallowedIdentifierNames.get(method);

Expand Down
1 change: 0 additions & 1 deletion rules/selectors/index.js
Expand Up @@ -11,7 +11,6 @@ module.exports = {
emptyObjectSelector: require('./empty-object-selector.js'),
memberExpressionSelector: require('./member-expression-selector.js'),
methodCallSelector: require('./method-call-selector.js'),
notDomNodeSelector: require('./not-dom-node.js').notDomNodeSelector,
referenceIdentifierSelector: require('./reference-identifier-selector.js'),
callExpressionSelector: require('./call-or-new-expression-selector.js').callExpressionSelector,
newExpressionSelector: require('./call-or-new-expression-selector.js').newExpressionSelector,
Expand Down
33 changes: 0 additions & 33 deletions rules/selectors/not-dom-node.js

This file was deleted.

17 changes: 17 additions & 0 deletions rules/utils/index.js
@@ -1,5 +1,22 @@
'use strict';

const {
isParenthesized,
getParenthesizedTimes,
getParentheses,
getParenthesizedRange,
getParenthesizedText,
} = require('./parentheses.js');

module.exports = {
getParentheses,
getParenthesizedRange,
getParenthesizedText,
getParenthesizedTimes,
isNodeValueNotDomNode: require('./is-node-value-not-dom-node.js'),
isNodeValueNotFunction: require('./is-node-value-not-function.js'),
isParenthesized,
isValueNotUsable: require('./is-value-not-usable.js'),
needsSemicolon: require('./needs-semicolon.js'),
shouldAddParenthesesToMemberExpressionObject: require('./should-add-parentheses-to-member-expression-object.js'),
};
21 changes: 21 additions & 0 deletions rules/utils/is-node-value-not-dom-node.js
@@ -0,0 +1,21 @@
'use strict';
const {isUndefined} = require('../ast/index.js');

// AST Types:
// https://github.com/eslint/espree/blob/master/lib/ast-node-types.js#L18
// Only types possible to be `callee` or `argument` are listed
const impossibleNodeTypes = new Set([
'ArrayExpression',
'ArrowFunctionExpression',
'ClassExpression',
'FunctionExpression',
'Literal',
'ObjectExpression',
'TemplateLiteral',
]);

const isNodeValueNotDomNode = node =>
impossibleNodeTypes.has(node.type)
|| isUndefined(node);

module.exports = isNodeValueNotDomNode;

0 comments on commit 2a0b40f

Please sign in to comment.