123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- 'use strict';
- const {isNodeMatches, isNodeMatchesNameOrPath} = require('./utils/is-node-matches.js');
- const {
- objectPrototypeMethodSelector,
- methodCallSelector,
- callExpressionSelector,
- } = require('./selectors/index.js');
- const {fixSpaceAroundKeyword} = require('./fix/index.js');
- const MESSAGE_ID = 'prefer-object-has-own';
- const messages = {
- [MESSAGE_ID]: 'Use `Object.hasOwn(…)` instead of `{{description}}(…)`.',
- };
- const objectPrototypeHasOwnProperty = [
- methodCallSelector({method: 'call', argumentsLength: 2}),
- ' > ',
- objectPrototypeMethodSelector({
- path: 'object',
- method: 'hasOwnProperty',
- }),
- '.callee',
- ].join('');
- const lodashHasFunctions = [
- '_.has',
- 'lodash.has',
- 'underscore.has',
- ];
- /** @param {import('eslint').Rule.RuleContext} context */
- const create = context => {
- const {functions: configFunctions} = {
- functions: [],
- ...context.options[0],
- };
- const functions = [...configFunctions, ...lodashHasFunctions];
- return Object.fromEntries(
- [
- {
- selector: objectPrototypeHasOwnProperty,
- description: 'Object.prototype.hasOwnProperty.call',
- },
- {
- selector: `${callExpressionSelector({argumentsLength: 2})} > .callee`,
- test: node => isNodeMatches(node, functions),
- description: node => functions.find(nameOrPath => isNodeMatchesNameOrPath(node, nameOrPath)).trim(),
- },
- ].map(({selector, test, description}) => [
- selector,
- node => {
- if (test && !test(node)) {
- return;
- }
- return {
- node,
- messageId: MESSAGE_ID,
- data: {
- description: typeof description === 'string' ? description : description(node),
- },
- /** @param {import('eslint').Rule.RuleFixer} fixer */
- * fix(fixer) {
- yield fixer.replaceText(node, 'Object.hasOwn');
- if (
- node.object
- && node.object.object
- && node.object.object.type === 'ObjectExpression'
- ) {
- yield * fixSpaceAroundKeyword(fixer, node.parent, context.getSourceCode());
- }
- },
- };
- },
- ]),
- );
- };
- const schema = [
- {
- type: 'object',
- additionalProperties: false,
- properties: {
- functions: {
- type: 'array',
- uniqueItems: true,
- },
- },
- },
- ];
- /** @type {import('eslint').Rule.RuleModule} */
- module.exports = {
- create,
- meta: {
- type: 'suggestion',
- docs: {
- description: 'Prefer `Object.hasOwn(…)` over `Object.prototype.hasOwnProperty.call(…)`.',
- },
- fixable: 'code',
- schema,
- messages,
- },
- };
|