@bigbinary/eslint-plugin-neeto 1.7.6 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +142 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -140,6 +140,7 @@ of the issues identified in JavaScript code.
140
140
  - [use-permissions-prop-in-private-route](./docs/src/rules/use-permissions-prop-in-private-route.md)
141
141
  - [use-webpack-alias](./docs/src/rules/use-webpack-alias.md)
142
142
  - [use-neetoui-action-block-in-formik-forms](./docs/src/rules/use-neetoui-action-block-in-formik-forms.md)
143
+ - [prefer-radio-buttons-for-few-options](./docs/src/rules/prefer-radio-buttons-for-few-options.md)
143
144
 
144
145
  ## Overriding rules
145
146
 
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@
38
38
  var commonResolve$2 = loadJS$2("node_modules/@bigbinary/neeto-commons-frontend/configs/webpack/resolve.js");
39
39
  var resolve$2 = ramda.mergeDeepLeft(projectResolve$2, commonResolve$2);
40
40
  var rules = {
41
+ "@bigbinary/neeto/prefer-radio-buttons-for-few-options": "warn",
41
42
  "@bigbinary/neeto/switch-children-must-be-route-or-redirect": "error",
42
43
  "@bigbinary/neeto/use-dayjs-from-neeto-commons-fronted": "error",
43
44
  "@bigbinary/neeto/use-neetoui-action-block-in-formik-forms": "warn",
@@ -330,7 +331,7 @@
330
331
  }
331
332
 
332
333
  var name = "@bigbinary/eslint-plugin-neeto";
333
- var version = "1.7.5";
334
+ var version = "1.7.6";
334
335
  var main = "dist/index.js";
335
336
  var license = "UNLICENSED";
336
337
  var scripts = {
@@ -753,6 +754,7 @@
753
754
  var HELP_URL_SHOULD_USE_PERMALINK = "Help URL must use a permalink (/p/...) instead of an article link (/articles/...).";
754
755
  var HELP_URL_INCORRECT_FORMAT = "Incorrect help URL format. Please use the 'help.neeto<product>.com' format instead of 'neeto<product>help.neetokb.com'.";
755
756
  var INVALID_SWITCH_CHILD_MESSAGE = "Switch component can only contain Route, Redirect, or PrivateRoute as direct children";
757
+ var PREFER_RADIO_BUTTONS_FOR_FEW_OPTIONS = "Consider using Radio buttons instead of Dropdown/Select when there are fewer than 4 options.";
756
758
 
757
759
  var PACKAGES_TO_CHECK = ["@bigbinary/neeto-molecules", "@bigbinary/neetoui", "@bigbinary/neeto-commons-frontend"];
758
760
 
@@ -9174,6 +9176,144 @@
9174
9176
  }
9175
9177
  };
9176
9178
 
9179
+ var MIN_OPTIONS_THRESHOLD = 4;
9180
+ var DROPDOWN_COMPONENT_NAMES = ["Dropdown", "Select", "DropdownMenu", "SelectInput", "MultiSelect", "Menu"];
9181
+ var OPTION_ELEMENT_NAMES = ["option", "Option", "MenuItem", "MenuItemButton"];
9182
+ var DROPDOWN_COMPONENT_PATTERN = {
9183
+ type: TYPES.JSX_ELEMENT,
9184
+ openingElement: {
9185
+ type: TYPES.JSX_OPENING_ELEMENT,
9186
+ name: {
9187
+ type: TYPES.JSX_IDENTIFIER,
9188
+ name: ramda.includes(ramda.__, DROPDOWN_COMPONENT_NAMES)
9189
+ }
9190
+ }
9191
+ };
9192
+ var OPTION_ELEMENT_PATTERN = {
9193
+ type: TYPES.JSX_ELEMENT,
9194
+ openingElement: {
9195
+ type: TYPES.JSX_OPENING_ELEMENT,
9196
+ name: {
9197
+ type: TYPES.JSX_IDENTIFIER,
9198
+ name: ramda.includes(ramda.__, OPTION_ELEMENT_NAMES)
9199
+ }
9200
+ }
9201
+ };
9202
+ var OPTIONS_ARRAY_PATTERN = {
9203
+ type: TYPES.JSX_ATTRIBUTE,
9204
+ name: {
9205
+ type: TYPES.JSX_IDENTIFIER,
9206
+ name: "options"
9207
+ },
9208
+ value: {
9209
+ type: TYPES.JSX_EXPRESSION_CONTAINER
9210
+ }
9211
+ };
9212
+ var SPREAD_ATTRIBUTE_PATTERN = {
9213
+ type: TYPES.JSX_SPREAD_ATTRIBUTE,
9214
+ argument: {
9215
+ type: TYPES.OBJECT_EXPRESSION
9216
+ }
9217
+ };
9218
+ var SPREAD_OPTION_PROPERTY_PATTERN = {
9219
+ type: TYPES.PROPERTY,
9220
+ key: {
9221
+ type: TYPES.IDENTIFIER,
9222
+ name: "options"
9223
+ }
9224
+ };
9225
+
9226
+ var isImportedVariable = function isImportedVariable(node, context) {
9227
+ if (node.type !== TYPES.IDENTIFIER) return false;
9228
+ var scope = context.sourceCode.getScope(node);
9229
+ var variable = scope.set.get(node.name);
9230
+ if (!variable || ramda.isEmpty(variable.defs)) return false;
9231
+ var def = variable.defs[0];
9232
+ return def.type === "ImportBinding";
9233
+ };
9234
+ var resolveVariableReference = function resolveVariableReference(node, context) {
9235
+ var _def$node;
9236
+ if (node.type !== TYPES.IDENTIFIER) return null;
9237
+ var scope = context.sourceCode.getScope(node);
9238
+ var variable = scope.set.get(node.name);
9239
+ if (!variable || ramda.isEmpty(variable.defs)) return null;
9240
+ var def = variable.defs[0];
9241
+ return ((_def$node = def.node) === null || _def$node === void 0 ? void 0 : _def$node.init) || null;
9242
+ };
9243
+ var countArrayElements = function countArrayElements(node, context) {
9244
+ if (node.type === TYPES.ARRAY_EXPRESSION) {
9245
+ return node.elements ? node.elements.length : 0;
9246
+ }
9247
+ if (node.type === TYPES.IDENTIFIER) {
9248
+ if (isImportedVariable(node, context)) return -1;
9249
+ var resolvedNode = resolveVariableReference(node, context);
9250
+ if (resolvedNode) {
9251
+ return countArrayElements(resolvedNode, context);
9252
+ }
9253
+ }
9254
+ return 0;
9255
+ };
9256
+ var countOptions = function countOptions(node, context) {
9257
+ var _node$openingElement, _optionsAttribute$val;
9258
+ var optionCount = 0;
9259
+
9260
+ // Count direct option children
9261
+ if (node.children) {
9262
+ var optionElements = node.children.filter(function (child) {
9263
+ return neetoCist.matches(OPTION_ELEMENT_PATTERN, child);
9264
+ });
9265
+ optionCount += optionElements.length;
9266
+ }
9267
+ var attributes = node === null || node === void 0 ? void 0 : (_node$openingElement = node.openingElement) === null || _node$openingElement === void 0 ? void 0 : _node$openingElement.attributes;
9268
+ if (!attributes) return optionCount;
9269
+
9270
+ // Count options from props passed to the component
9271
+ var optionsAttribute = ramda.find(neetoCist.matches(OPTIONS_ARRAY_PATTERN), attributes);
9272
+ var expression = optionsAttribute === null || optionsAttribute === void 0 ? void 0 : (_optionsAttribute$val = optionsAttribute.value) === null || _optionsAttribute$val === void 0 ? void 0 : _optionsAttribute$val.expression;
9273
+ if (expression) {
9274
+ var elementsCount = countArrayElements(expression, context);
9275
+ optionCount += elementsCount;
9276
+ }
9277
+
9278
+ // Count options from spread props eg: <Component {...{options}} />
9279
+ var spreadAttributes = attributes.filter(function (attribute) {
9280
+ return neetoCist.matches(SPREAD_ATTRIBUTE_PATTERN, attribute);
9281
+ });
9282
+ spreadAttributes.forEach(function (attribute) {
9283
+ if (!attribute.argument) return;
9284
+ if (!(attribute.argument.type === TYPES.OBJECT_EXPRESSION)) return;
9285
+ var optionsProperty = ramda.find(neetoCist.matches(SPREAD_OPTION_PROPERTY_PATTERN), attribute.argument.properties);
9286
+ var optionsPropertyValue = optionsProperty === null || optionsProperty === void 0 ? void 0 : optionsProperty.value;
9287
+ if (!optionsPropertyValue) return;
9288
+ var elementsCount = countArrayElements(optionsPropertyValue, context);
9289
+ optionCount += elementsCount;
9290
+ });
9291
+ return optionCount;
9292
+ };
9293
+ var preferRadioButtonsForFewOptions = {
9294
+ meta: {
9295
+ type: "warn",
9296
+ docs: {
9297
+ url: "https://github.com/bigbinary/eslint-plugin-neeto/blob/main/docs/src/rules/prefer-radio-buttons-for-few-options.md",
9298
+ description: PREFER_RADIO_BUTTONS_FOR_FEW_OPTIONS
9299
+ }
9300
+ },
9301
+ create: function create(context) {
9302
+ return {
9303
+ JSXElement: function JSXElement(node) {
9304
+ if (!neetoCist.matches(DROPDOWN_COMPONENT_PATTERN, node)) return;
9305
+ var optionCount = countOptions(node, context);
9306
+ if (optionCount > 0 && optionCount < MIN_OPTIONS_THRESHOLD) {
9307
+ context.report({
9308
+ node: node,
9309
+ message: PREFER_RADIO_BUTTONS_FOR_FEW_OPTIONS
9310
+ });
9311
+ }
9312
+ }
9313
+ };
9314
+ }
9315
+ };
9316
+
9177
9317
  var NEETO_PACKAGES = ["@bigbinary/neetoui", "@bigbinary/neeto-icons"];
9178
9318
 
9179
9319
  var importedFromNeeto = function importedFromNeeto(context, node) {
@@ -13309,6 +13449,7 @@
13309
13449
 
13310
13450
  var index = {
13311
13451
  rules: {
13452
+ "prefer-radio-buttons-for-few-options": preferRadioButtonsForFewOptions,
13312
13453
  "switch-children-must-be-route-or-redirect": switchChildrenMustBeRouteOrRedirect,
13313
13454
  "use-dayjs-from-neeto-commons-fronted": useDayjsFromNeetoCommonsFronted,
13314
13455
  "use-neetoui-action-block-in-formik-forms": useNeetouiActionBlockInFormikForms,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigbinary/eslint-plugin-neeto",
3
- "version": "1.7.6",
3
+ "version": "1.8.0",
4
4
  "main": "dist/index.js",
5
5
  "license": "UNLICENSED",
6
6
  "scripts": {