oxlint-plugin-react-doctor 0.2.17-dev.5614b32 → 0.2.18-dev.8d13ba3

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 +32 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7346,6 +7346,13 @@ const isImportedFromModule = (contextNode, localIdentifierName, moduleSource) =>
7346
7346
  if (!info) return false;
7347
7347
  return info.source === moduleSource;
7348
7348
  };
7349
+ const isNamespaceImportFromModule = (contextNode, localIdentifierName, moduleSource) => {
7350
+ const lookup = getImportLookup(contextNode);
7351
+ if (!lookup) return false;
7352
+ const info = lookup.get(localIdentifierName);
7353
+ if (!info) return false;
7354
+ return info.isNamespace && info.source === moduleSource;
7355
+ };
7349
7356
  const getImportedNameFromModule = (contextNode, localIdentifierName, moduleSource) => {
7350
7357
  const lookup = getImportLookup(contextNode);
7351
7358
  if (!lookup) return null;
@@ -27048,6 +27055,11 @@ const LEGACY_EXPO_PACKAGE_REPLACEMENTS = new Map([
27048
27055
  ["expo-linear-gradient", "the `backgroundImage` CSS gradient style prop (New Architecture) or expo-linear-gradient's successor"],
27049
27056
  ["react-native-fast-image", "expo-image (drop-in with caching, placeholders, and crossfades)"]
27050
27057
  ]);
27058
+ const EXPO_UI_MODULE_SOURCES = new Set([
27059
+ "@expo/ui",
27060
+ "@expo/ui/swift-ui",
27061
+ "@expo/ui/jetpack-compose"
27062
+ ]);
27051
27063
  const REACT_NATIVE_LIST_COMPONENTS = new Set([
27052
27064
  "FlatList",
27053
27065
  "SectionList",
@@ -27859,6 +27871,24 @@ const collectTextWrapperComponents = (programNode, isTextHandlingRoot) => {
27859
27871
  return wrappers;
27860
27872
  };
27861
27873
  //#endregion
27874
+ //#region src/plugin/rules/react-native/utils/is-expo-ui-component-element.ts
27875
+ const isNamedImportOf = (contextNode, localName, componentName) => {
27876
+ for (const moduleSource of EXPO_UI_MODULE_SOURCES) if (getImportedNameFromModule(contextNode, localName, moduleSource) === componentName) return true;
27877
+ return false;
27878
+ };
27879
+ const isExpoUiNamespaceImport = (contextNode, localName) => {
27880
+ for (const moduleSource of EXPO_UI_MODULE_SOURCES) if (isNamespaceImportFromModule(contextNode, localName, moduleSource)) return true;
27881
+ return false;
27882
+ };
27883
+ const isExpoUiComponentElement = (openingElement, contextNode, componentName) => {
27884
+ if (!openingElement.name) return false;
27885
+ const dottedName = flattenJsxName(openingElement.name);
27886
+ if (!dottedName) return false;
27887
+ const [rootLocalName, secondName] = dottedName.split(".");
27888
+ if (isNamedImportOf(contextNode, rootLocalName, componentName)) return true;
27889
+ return secondName === componentName && isExpoUiNamespaceImport(contextNode, rootLocalName);
27890
+ };
27891
+ //#endregion
27862
27892
  //#region src/plugin/rules/react-native/rn-no-raw-text.ts
27863
27893
  const truncateText = (text) => text.length > 30 ? `${text.slice(0, 30)}...` : text;
27864
27894
  const isRawTextContent = (child) => {
@@ -27918,6 +27948,7 @@ const rnNoRawText = defineRule({
27918
27948
  if (isDomComponentFile) return;
27919
27949
  const elementName = resolveTextBoundaryName(node.openingElement);
27920
27950
  if (elementName && (isTextHandlingComponent(elementName) || autoDetectedWrappers.has(elementName))) return;
27951
+ if (isExpoUiComponentElement(node.openingElement, node, "ListItem")) return;
27921
27952
  if (isInsidePlatformOsWebBranch(node)) return;
27922
27953
  if (isTransparentTextWrapper(elementName) && isInsideTextHandlingComponent(node)) return;
27923
27954
  for (const child of node.children ?? []) {
@@ -28081,6 +28112,7 @@ const rnNoScrollviewMappedList = defineRule({
28081
28112
  create: (context) => ({ JSXElement(node) {
28082
28113
  const elementName = resolveJsxElementName(node.openingElement);
28083
28114
  if (!elementName || !NON_VIRTUALIZED_SCROLL_CONTAINERS.has(elementName)) return;
28115
+ if (isExpoUiComponentElement(node.openingElement, node, "ScrollView")) return;
28084
28116
  for (const child of node.children ?? []) {
28085
28117
  if (!isNodeOfType(child, "JSXExpressionContainer")) continue;
28086
28118
  const expression = child.expression;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxlint-plugin-react-doctor",
3
- "version": "0.2.17-dev.5614b32",
3
+ "version": "0.2.18-dev.8d13ba3",
4
4
  "description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
5
5
  "keywords": [
6
6
  "accessibility",