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

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

Update repo after prototype presentation

  • Property mode set to 100644
File size: 3.4 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 {string[]} 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
44module.exports = {
45 meta: {
46 docs: {
47 description: 'Enforce using `onChange` or `readonly` attribute when `checked` is used',
48 category: 'Best Practices',
49 recommended: false,
50 url: docsUrl('checked-requires-onchange-or-readonly'),
51 },
52 messages,
53 schema: [{
54 additionalProperties: false,
55 properties: {
56 ignoreMissingProperties: {
57 type: 'boolean',
58 },
59 ignoreExclusiveCheckedAttribute: {
60 type: 'boolean',
61 },
62 },
63 }],
64 },
65 create(context) {
66 const options = Object.assign({}, defaultOptions, context.options[0]);
67
68 function reportMissingProperty(node) {
69 report(
70 context,
71 messages.missingProperty,
72 'missingProperty',
73 { node }
74 );
75 }
76
77 function reportExclusiveCheckedAttribute(node) {
78 report(
79 context,
80 messages.exclusiveCheckedAttribute,
81 'exclusiveCheckedAttribute',
82 { node }
83 );
84 }
85
86 /**
87 * @param {ASTNode} node
88 * @param {Set<string>} propSet
89 * @returns {void}
90 */
91 const checkAttributesAndReport = (node, propSet) => {
92 if (!propSet.has('checked')) {
93 return;
94 }
95
96 if (!options.ignoreExclusiveCheckedAttribute && propSet.has('defaultChecked')) {
97 reportExclusiveCheckedAttribute(node);
98 }
99
100 if (
101 !options.ignoreMissingProperties
102 && !(propSet.has('onChange') || propSet.has('readOnly'))
103 ) {
104 reportMissingProperty(node);
105 }
106 };
107
108 return {
109 JSXOpeningElement(node) {
110 if (ASTUtils.elementType(node) !== 'input') {
111 return;
112 }
113
114 const propSet = extractTargetProps(node.attributes, 'name');
115 checkAttributesAndReport(node, propSet);
116 },
117 CallExpression(node) {
118 if (!isCreateElement(context, node)) {
119 return;
120 }
121
122 const firstArg = node.arguments[0];
123 const secondArg = node.arguments[1];
124 if (
125 !firstArg
126 || firstArg.type !== 'Literal'
127 || firstArg.value !== 'input'
128 ) {
129 return;
130 }
131
132 if (!secondArg || secondArg.type !== 'ObjectExpression') {
133 return;
134 }
135
136 const propSet = extractTargetProps(secondArg.properties, 'key');
137 checkAttributesAndReport(node, propSet);
138 },
139 };
140 },
141};
Note: See TracBrowser for help on using the repository browser.