source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/checked-requires-onchange-or-readonly.js@ 0c6b92a

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • Property mode set to 100644
File size: 3.5 KB
Line 
1/**
2 * @fileoverview Enforce the use of the 'onChange' or 'readonly' attribute when 'checked' is used'
3 * @author Jaesoekjjang
4 */
5
6'use strict';
7
8const ASTUtils = require('jsx-ast-utils');
9const flatMap = require('array.prototype.flatmap');
10const isCreateElement = require('../util/isCreateElement');
11const report = require('../util/report');
12const docsUrl = require('../util/docsUrl');
13
14const messages = {
15 missingProperty: '`checked` should be used with either `onChange` or `readOnly`.',
16 exclusiveCheckedAttribute: 'Use either `checked` or `defaultChecked`, but not both.',
17};
18
19const targetPropSet = new Set(['checked', 'onChange', 'readOnly', 'defaultChecked']);
20
21const defaultOptions = {
22 ignoreMissingProperties: false,
23 ignoreExclusiveCheckedAttribute: false,
24};
25
26/**
27 * @param {object[]} properties
28 * @param {string} keyName
29 * @returns {Set<string>}
30 */
31function extractTargetProps(properties, keyName) {
32 return new Set(
33 flatMap(
34 properties,
35 (prop) => (
36 prop[keyName] && targetPropSet.has(prop[keyName].name)
37 ? [prop[keyName].name]
38 : []
39 )
40 )
41 );
42}
43
44/** @type {import('eslint').Rule.RuleModule} */
45module.exports = {
46 meta: {
47 docs: {
48 description: 'Enforce using `onChange` or `readonly` attribute when `checked` is used',
49 category: 'Best Practices',
50 recommended: false,
51 url: docsUrl('checked-requires-onchange-or-readonly'),
52 },
53 messages,
54 schema: [{
55 additionalProperties: false,
56 properties: {
57 ignoreMissingProperties: {
58 type: 'boolean',
59 },
60 ignoreExclusiveCheckedAttribute: {
61 type: 'boolean',
62 },
63 },
64 }],
65 },
66 create(context) {
67 const options = Object.assign({}, defaultOptions, context.options[0]);
68
69 function reportMissingProperty(node) {
70 report(
71 context,
72 messages.missingProperty,
73 'missingProperty',
74 { node }
75 );
76 }
77
78 function reportExclusiveCheckedAttribute(node) {
79 report(
80 context,
81 messages.exclusiveCheckedAttribute,
82 'exclusiveCheckedAttribute',
83 { node }
84 );
85 }
86
87 /**
88 * @param {ASTNode} node
89 * @param {Set<string>} propSet
90 * @returns {void}
91 */
92 const checkAttributesAndReport = (node, propSet) => {
93 if (!propSet.has('checked')) {
94 return;
95 }
96
97 if (!options.ignoreExclusiveCheckedAttribute && propSet.has('defaultChecked')) {
98 reportExclusiveCheckedAttribute(node);
99 }
100
101 if (
102 !options.ignoreMissingProperties
103 && !(propSet.has('onChange') || propSet.has('readOnly'))
104 ) {
105 reportMissingProperty(node);
106 }
107 };
108
109 return {
110 JSXOpeningElement(node) {
111 if (ASTUtils.elementType(node) !== 'input') {
112 return;
113 }
114
115 const propSet = extractTargetProps(node.attributes, 'name');
116 checkAttributesAndReport(node, propSet);
117 },
118 CallExpression(node) {
119 if (!isCreateElement(context, node)) {
120 return;
121 }
122
123 const firstArg = node.arguments[0];
124 const secondArg = node.arguments[1];
125 if (
126 !firstArg
127 || firstArg.type !== 'Literal'
128 || firstArg.value !== 'input'
129 ) {
130 return;
131 }
132
133 if (!secondArg || secondArg.type !== 'ObjectExpression') {
134 return;
135 }
136
137 const propSet = extractTargetProps(secondArg.properties, 'key');
138 checkAttributesAndReport(node, propSet);
139 },
140 };
141 },
142};
Note: See TracBrowser for help on using the repository browser.