eslint-plugin-react-x 3.0.0-beta.67 → 3.0.0-beta.69

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 (2) hide show
  1. package/dist/index.js +42 -36
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -147,7 +147,7 @@ const rules$7 = {
147
147
  //#endregion
148
148
  //#region package.json
149
149
  var name$6 = "eslint-plugin-react-x";
150
- var version = "3.0.0-beta.67";
150
+ var version = "3.0.0-beta.69";
151
151
 
152
152
  //#endregion
153
153
  //#region src/utils/create-rule.ts
@@ -1442,15 +1442,15 @@ function create$61(context) {
1442
1442
  node
1443
1443
  });
1444
1444
  },
1445
- "Program:exit"(program) {
1446
- const components = cCollector.ctx.getAllComponents(program);
1447
- const hooks = hCollector.ctx.getAllHooks(program);
1448
- const componentAndHookFns = new Set([...components.map((c) => c.node), ...hooks.map((h) => h.node)]);
1445
+ "Program:exit"(node) {
1446
+ const comps = cCollector.ctx.getAllComponents(node);
1447
+ const hooks = hCollector.ctx.getAllHooks(node);
1448
+ const funcs = [...comps, ...hooks];
1449
1449
  for (const { data, func, messageId, node } of violations) {
1450
1450
  let current = func;
1451
1451
  let insideComponentOrHook = false;
1452
1452
  while (current != null) {
1453
- if (componentAndHookFns.has(current)) {
1453
+ if (funcs.some((f) => f.node === current)) {
1454
1454
  insideComponentOrHook = true;
1455
1455
  break;
1456
1456
  }
@@ -4273,9 +4273,9 @@ function create$7(context) {
4273
4273
  });
4274
4274
  },
4275
4275
  "Program:exit"(node) {
4276
- const components = cCollector.ctx.getAllComponents(node);
4276
+ const comps = cCollector.ctx.getAllComponents(node);
4277
4277
  const hooks = hCollector.ctx.getAllHooks(node);
4278
- const funcs = [...components, ...hooks];
4278
+ const funcs = [...comps, ...hooks];
4279
4279
  for (const { func, node } of [...cExprs, ...nExprs]) {
4280
4280
  if (!funcs.some((f) => f.node === func)) continue;
4281
4281
  context.report({
@@ -4316,12 +4316,13 @@ function create$6(context) {
4316
4316
  * @returns true if the node is part of a null check test in an if statement
4317
4317
  */
4318
4318
  function isInNullCheckTest(node) {
4319
- const { parent } = node;
4319
+ let parent = node.parent;
4320
+ while (ast.isTypeExpression(parent)) parent = parent.parent;
4320
4321
  if (!isMatching({
4321
4322
  type: AST_NODE_TYPES.BinaryExpression,
4322
4323
  operator: P.union("===", "==", "!==", "!=")
4323
4324
  }, parent)) return false;
4324
- const otherSide = parent.left === node ? parent.right : parent.left;
4325
+ const otherSide = parent.left === node || ast.getUnderlyingExpression(parent.left) === node ? parent.right : parent.left;
4325
4326
  if (otherSide.type !== AST_NODE_TYPES.Literal || otherSide.value != null) return false;
4326
4327
  return parent.parent.type === AST_NODE_TYPES.IfStatement && parent.parent.test === parent;
4327
4328
  }
@@ -4336,7 +4337,10 @@ function create$6(context) {
4336
4337
  const op = test.operator;
4337
4338
  if (op !== "===" && op !== "==" && op !== "!==" && op !== "!=") return false;
4338
4339
  const { left, right } = test;
4339
- const checkSides = (a, b) => a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && a.property.type === AST_NODE_TYPES.Identifier && a.property.name === "current" && b.type === AST_NODE_TYPES.Literal && b.value == null;
4340
+ const checkSides = (a, b) => {
4341
+ a = ast.isTypeExpression(a) ? ast.getUnderlyingExpression(a) : a;
4342
+ return a.type === AST_NODE_TYPES.MemberExpression && a.object.type === AST_NODE_TYPES.Identifier && a.object.name === refName && b.type === AST_NODE_TYPES.Literal && b.value == null && ast.getPropertyName(a.property) === "current";
4343
+ };
4340
4344
  return checkSides(left, right) || checkSides(right, left);
4341
4345
  }
4342
4346
  return defineRuleListener(hCollector.visitor, cCollector.visitor, {
@@ -4350,7 +4354,11 @@ function create$6(context) {
4350
4354
  MemberExpression(node) {
4351
4355
  if (!ast.isIdentifier(node.property, "current")) return;
4352
4356
  refAccesses.push({
4353
- isWrite: match(node.parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node).with({ type: AST_NODE_TYPES.UpdateExpression }, (p) => p.argument === node).otherwise(() => false),
4357
+ isWrite: (() => {
4358
+ let parent = node.parent;
4359
+ while (ast.isTypeExpression(parent)) parent = parent.parent;
4360
+ return match(parent).with({ type: AST_NODE_TYPES.AssignmentExpression }, (p) => p.left === node || ast.getUnderlyingExpression(p.left) === node).with({ type: AST_NODE_TYPES.UpdateExpression }, (p) => p.argument === node || ast.getUnderlyingExpression(p.argument) === node).otherwise(() => false);
4361
+ })(),
4354
4362
  node
4355
4363
  });
4356
4364
  },
@@ -7020,7 +7028,8 @@ function create$2(context) {
7020
7028
  if (!context.sourceCode.text.includes("useMemo")) return {};
7021
7029
  return defineRuleListener({ CallExpression(node) {
7022
7030
  if (!core.isUseMemoCall(node)) return;
7023
- const parent = node.parent;
7031
+ let parent = node.parent;
7032
+ while (ast.isTypeExpression(parent)) parent = parent.parent;
7024
7033
  if (!(parent.type === AST_NODE_TYPES.VariableDeclarator || parent.type === AST_NODE_TYPES.AssignmentExpression || parent.type === AST_NODE_TYPES.AssignmentPattern || parent.type === AST_NODE_TYPES.Property || parent.type === AST_NODE_TYPES.ReturnStatement || parent.type === AST_NODE_TYPES.JSXExpressionContainer || parent.type === AST_NODE_TYPES.CallExpression || parent.type === AST_NODE_TYPES.NewExpression || parent.type === AST_NODE_TYPES.ArrayExpression || parent.type === AST_NODE_TYPES.ConditionalExpression || parent.type === AST_NODE_TYPES.LogicalExpression || parent.type === AST_NODE_TYPES.SequenceExpression || parent.type === AST_NODE_TYPES.SpreadElement || parent.type === AST_NODE_TYPES.TemplateLiteral || parent.type === AST_NODE_TYPES.BinaryExpression || parent.type === AST_NODE_TYPES.UnaryExpression || parent.type === AST_NODE_TYPES.MemberExpression || parent.type === AST_NODE_TYPES.TaggedTemplateExpression || parent.type === AST_NODE_TYPES.ChainExpression)) {
7025
7034
  context.report({
7026
7035
  messageId: "notAssignedToVariable",
@@ -7185,34 +7194,31 @@ var unstable_rules_of_props_default = createRule({
7185
7194
  create,
7186
7195
  defaultOptions: []
7187
7196
  });
7197
+ function toControlledName(uncontrolledName) {
7198
+ const [, head, tail] = /^default([A-Z])(.*)$/.exec(uncontrolledName) ?? [];
7199
+ if (head == null || tail == null) return null;
7200
+ return head.toLowerCase() + tail;
7201
+ }
7188
7202
  function create(context) {
7189
- /**
7190
- * Pairs of [controlled prop, uncontrolled prop] that must not appear together
7191
- * on the same JSX element.
7192
- *
7193
- * - `value` → controlled; `defaultValue` → uncontrolled
7194
- * - `checked` → controlled; `defaultChecked` → uncontrolled
7195
- */
7196
- const pairs = [["value", "defaultValue"], ["checked", "defaultChecked"]];
7197
7203
  return defineRuleListener({ JSXOpeningElement(node) {
7198
- const map = /* @__PURE__ */ new Map();
7199
- for (const attr of node.attributes) {
7200
- if (attr.type === AST_NODE_TYPES.JSXSpreadAttribute) continue;
7201
- const { name } = attr.name;
7202
- if (typeof name !== "string") continue;
7203
- map.set(name, attr);
7204
+ const attributes = /* @__PURE__ */ new Map();
7205
+ for (const attribute of node.attributes) {
7206
+ if (attribute.type === AST_NODE_TYPES.JSXSpreadAttribute) continue;
7207
+ const { name: identifier } = attribute.name;
7208
+ if (typeof identifier !== "string") continue;
7209
+ attributes.set(identifier, attribute);
7204
7210
  }
7205
- for (const [controlled, uncontrolled] of pairs) {
7206
- if (!map.has(controlled) || !map.has(uncontrolled)) continue;
7207
- const attr = map.get(uncontrolled);
7208
- if (attr == null) continue;
7211
+ for (const [propName, attrNode] of attributes) {
7212
+ const controlledProp = toControlledName(propName);
7213
+ if (controlledProp == null) continue;
7214
+ if (!attributes.has(controlledProp)) continue;
7209
7215
  context.report({
7210
- data: {
7211
- controlled,
7212
- uncontrolled
7213
- },
7216
+ node: attrNode,
7214
7217
  messageId: "noControlledAndUncontrolledTogether",
7215
- node: attr
7218
+ data: {
7219
+ controlled: controlledProp,
7220
+ uncontrolled: propName
7221
+ }
7216
7222
  });
7217
7223
  }
7218
7224
  } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-react-x",
3
- "version": "3.0.0-beta.67",
3
+ "version": "3.0.0-beta.69",
4
4
  "description": "A set of composable ESLint rules for libraries and frameworks that use React as a UI runtime.",
5
5
  "keywords": [
6
6
  "react",
@@ -45,11 +45,11 @@
45
45
  "string-ts": "^2.3.1",
46
46
  "ts-api-utils": "^2.4.0",
47
47
  "ts-pattern": "^5.9.0",
48
- "@eslint-react/ast": "3.0.0-beta.67",
49
- "@eslint-react/core": "3.0.0-beta.67",
50
- "@eslint-react/eff": "3.0.0-beta.67",
51
- "@eslint-react/shared": "3.0.0-beta.67",
52
- "@eslint-react/var": "3.0.0-beta.67"
48
+ "@eslint-react/ast": "3.0.0-beta.69",
49
+ "@eslint-react/core": "3.0.0-beta.69",
50
+ "@eslint-react/eff": "3.0.0-beta.69",
51
+ "@eslint-react/shared": "3.0.0-beta.69",
52
+ "@eslint-react/var": "3.0.0-beta.69"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/react": "^19.2.14",