oxlint-plugin-react-doctor 0.7.5-dev.21da48f → 0.7.5-dev.3075e10

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 +3 -62
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5178,10 +5178,8 @@ const STORAGE_GLOBALS = new Set([
5178
5178
  const SENSITIVE_KEY_PATTERN = /token|jwt|secret|password|passwd|credential|api[-_]?key|bearer|private[-_]?key/i;
5179
5179
  const NON_AUTH_TOKEN_PATTERN = /csrf|xsrf|device|fcm|apns|push|design|tokeniz|syntax|css|theme|color/i;
5180
5180
  const STRONG_AUTH_KEY_PATTERN = /jwt|secret|password|passwd|credential|private[-_]?key|api[-_]?key|bearer|access[-_]?token|refresh[-_]?token|auth[-_]?token|id[-_]?token|session/i;
5181
- const PRODUCT_API_KEY_RECORDS_PATTERN = /(?:^|[._:-])(?:created|saved|integration|mailing)[-_]?api[-_]?keys$/i;
5182
5181
  const PRODUCT_API_KEY_COLLECTION_PATTERN = /[._:-](?:created|generated|saved)[-_]?api[-_]?keys$/i;
5183
5182
  const isAuthCredentialKey = (key) => {
5184
- if (PRODUCT_API_KEY_RECORDS_PATTERN.test(key)) return false;
5185
5183
  if (!SENSITIVE_KEY_PATTERN.test(key)) return false;
5186
5184
  if (PRODUCT_API_KEY_COLLECTION_PATTERN.test(key)) return false;
5187
5185
  if (NON_AUTH_TOKEN_PATTERN.test(key) && !STRONG_AUTH_KEY_PATTERN.test(key)) return false;
@@ -24000,26 +23998,6 @@ const STATEFUL_HTML_DESCENDANT_TAGS = new Set([
24000
23998
  "dialog",
24001
23999
  "canvas"
24002
24000
  ]);
24003
- const STATEFUL_HTML_ATTRIBUTE_NAMES = new Set([
24004
- "autofocus",
24005
- "contenteditable",
24006
- "draggable",
24007
- "tabindex"
24008
- ]);
24009
- const isStaticallyFalseAttributeValue = (attribute) => {
24010
- if (!isNodeOfType(attribute, "JSXAttribute") || !attribute.value) return false;
24011
- const value = isNodeOfType(attribute.value, "JSXExpressionContainer") ? attribute.value.expression : attribute.value;
24012
- return isNodeOfType(value, "Literal") && (value.value === false || value.value === "false");
24013
- };
24014
- const hasStatefulHtmlAttribute = (openingElement) => {
24015
- if (!isNodeOfType(openingElement, "JSXOpeningElement")) return false;
24016
- return openingElement.attributes.some((attribute) => {
24017
- if (!isNodeOfType(attribute, "JSXAttribute") || !isNodeOfType(attribute.name, "JSXIdentifier")) return false;
24018
- const attributeName = attribute.name.name.toLowerCase();
24019
- if (!STATEFUL_HTML_ATTRIBUTE_NAMES.has(attributeName)) return false;
24020
- return attributeName === "tabindex" || !isStaticallyFalseAttributeValue(attribute);
24021
- });
24022
- };
24023
24001
  const STATEFUL_DESCENDANT_SCAN_BUDGET = 200;
24024
24002
  const rootIdentifierNameOf = (expression) => {
24025
24003
  let object = expression;
@@ -24037,8 +24015,7 @@ const containsStatefulDescendant = (jsxElement, options = {}) => {
24037
24015
  budget -= 1;
24038
24016
  const node = stack.pop();
24039
24017
  if (isNodeOfType(node, "JSXElement")) {
24040
- const opening = node.openingElement;
24041
- const name = opening.name;
24018
+ const name = node.openingElement.name;
24042
24019
  if (name && isNodeOfType(name, "JSXIdentifier")) {
24043
24020
  const tagName = name.name;
24044
24021
  const firstChar = tagName.charCodeAt(0);
@@ -24046,7 +24023,6 @@ const containsStatefulDescendant = (jsxElement, options = {}) => {
24046
24023
  if (STATEFUL_HTML_DESCENDANT_TAGS.has(tagName)) return true;
24047
24024
  }
24048
24025
  if (name && isNodeOfType(name, "JSXMemberExpression")) return true;
24049
- if (hasStatefulHtmlAttribute(opening)) return true;
24050
24026
  const children = node.children ?? [];
24051
24027
  for (const child of children) stack.push(child);
24052
24028
  continue;
@@ -24606,14 +24582,6 @@ const templateHasOuterMemberIdentity = (template, bindingFunction) => {
24606
24582
  }
24607
24583
  return false;
24608
24584
  };
24609
- const findBareItemNamesReferencedByTemplate = (template, itemNames) => {
24610
- const referencedItemNames = /* @__PURE__ */ new Set();
24611
- for (const expression of template.expressions ?? []) {
24612
- const unwrappedExpression = stripParenExpression(expression);
24613
- if (isNodeOfType(unwrappedExpression, "Identifier") && itemNames.has(unwrappedExpression.name)) referencedItemNames.add(unwrappedExpression.name);
24614
- }
24615
- return referencedItemNames;
24616
- };
24617
24585
  const forLoopTestReadsDataLength = (test) => {
24618
24586
  let didFindLengthRead = false;
24619
24587
  walkAst(test, (child) => {
@@ -24750,11 +24718,9 @@ const noArrayIndexAsKey = defineRule({
24750
24718
  } else if (STATELESS_HTML_LEAF_TAGS.has(elementName.name)) {
24751
24719
  const jsxElement = openingElement.parent;
24752
24720
  if (jsxElement && isNodeOfType(jsxElement, "JSXElement")) {
24753
- const isInlineTextRun = INLINE_TEXT_LEAF_TAGS.has(elementName.name);
24754
- const primitiveItemNames = keyTemplate ? findBareItemNamesReferencedByTemplate(keyTemplate, itemNames) : EMPTY_NAME_SET;
24755
24721
  if (!containsStatefulDescendant(jsxElement, {
24756
- memberRootNames: isInlineTextRun ? itemNames : EMPTY_NAME_SET,
24757
- bareIdentifierNames: primitiveItemNames.size > 0 ? new Set([...derivedNames, ...primitiveItemNames]) : derivedNames
24722
+ memberRootNames: INLINE_TEXT_LEAF_TAGS.has(elementName.name) ? itemNames : EMPTY_NAME_SET,
24723
+ bareIdentifierNames: derivedNames
24758
24724
  })) return;
24759
24725
  }
24760
24726
  }
@@ -35051,30 +35017,6 @@ const guardsRenderShape = (comparison) => {
35051
35017
  }
35052
35018
  return false;
35053
35019
  };
35054
- const isPropsChildrenLength = (node, scopes) => {
35055
- const unwrappedNode = stripParenExpression(node);
35056
- return isNodeOfType(unwrappedNode, "MemberExpression") && !unwrappedNode.computed && isNodeOfType(unwrappedNode.property, "Identifier") && unwrappedNode.property.name === "length" && resolvesToPropsChildren(stripParenExpression(unwrappedNode.object), scopes);
35057
- };
35058
- const isLargeTextLengthComparison = (node, scopes) => {
35059
- const unwrappedNode = stripParenExpression(node);
35060
- if (!isNodeOfType(unwrappedNode, "BinaryExpression")) return false;
35061
- const leftIsLength = isPropsChildrenLength(unwrappedNode.left, scopes);
35062
- const rightIsLength = isPropsChildrenLength(unwrappedNode.right, scopes);
35063
- const thresholdNode = leftIsLength ? unwrappedNode.right : unwrappedNode.left;
35064
- if (!leftIsLength && !rightIsLength || !isNodeOfType(thresholdNode, "Literal")) return false;
35065
- if (typeof thresholdNode.value !== "number" || thresholdNode.value < 1e3) return false;
35066
- return leftIsLength ? unwrappedNode.operator === ">" || unwrappedNode.operator === ">=" : unwrappedNode.operator === "<" || unwrappedNode.operator === "<=";
35067
- };
35068
- const isLargeStringOptimizationGuard = (comparison, scopes) => {
35069
- let current = findTransparentExpressionRoot(comparison);
35070
- while (current.parent) {
35071
- const parent = current.parent;
35072
- if (!isNodeOfType(parent, "LogicalExpression") || parent.operator !== "&&") return false;
35073
- if (isLargeTextLengthComparison(parent.left === current ? parent.right : parent.left, scopes)) return true;
35074
- current = findTransparentExpressionRoot(parent);
35075
- }
35076
- return false;
35077
- };
35078
35020
  const noPolymorphicChildren = defineRule({
35079
35021
  id: "no-polymorphic-children",
35080
35022
  title: "Children type checked at runtime",
@@ -35088,7 +35030,6 @@ const noPolymorphicChildren = defineRule({
35088
35030
  const isStringLiteral = (operand) => isNodeOfType(operand, "Literal") && operand.value === "string";
35089
35031
  if (!isStringLiteral(node.left) && !isStringLiteral(node.right)) return;
35090
35032
  if (!guardsRenderShape(node)) return;
35091
- if (isLargeStringOptimizationGuard(node, context.scopes)) return;
35092
35033
  context.report({
35093
35034
  node,
35094
35035
  message: "Your users hit inconsistent behavior because `typeof children === \"string\"` makes this component switch on what callers pass, so add clear subcomponents like `<Button.Text>` instead."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.7.5-dev.21da48f",
3
+ "version": "0.7.5-dev.3075e10",
4
4
  "description": "React Doctor rules for oxlint.",
5
5
  "keywords": [
6
6
  "accessibility",