Intellicode / eslint-plugin-react-native

React Native plugin for ESLint

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[3.9.1] Crash related to <Text>

mjmasn opened this issue · comments

Hey! 👋

I'm getting Error: Couldn't find a Program after upgrading this package from 3.8.1 to 3.9.1.

Bit of a contrived example below, but seems to reliably trigger the issue and was just about the smallest repro I could manage to find. Not able to post the actual code we're using I'm afraid but it's essentially rendering something like:

Total: 12.34

Seems to be something to do with nested text that has a function defined somewhere inside. In our case there's a reducer for calculating a total.

Some notes:

  • Using a named fn instead of the arrow fn still crashes - i.e. arr.reduce(function add(acc, value) { return acc + value }, 0)
  • Replacing the reducer callback with something else like a string prevents the crash - i.e. arr.reduce('blah', 0) (obviously invalid code though)
  • Defining the reducer callback outside of the JSX also prevents the crash - i.e. const add = (acc, value) => acc + value and arr.reduce(add, 0) <- looks like this is a reasonable workaround for now...

Repro code:

const Comp = () => {
    return (
        <Text>
            <Text>Text</Text> {fn(() => {})}
        </Text>
    )
}
> eslint .


Oops! Something went wrong! :(

ESLint: 7.8.1

Error: Couldn't find a Program
Occurred while linting /Users/REDACTED/REDACTED/REDACTED.tsx:XX
    at Scope.getProgramParent (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/scope/index.js:813:11)
    at Scope.registerBinding (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/scope/index.js:574:25)
    at Scope.crawl (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/scope/index.js:729:14)
    at Scope.init (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/scope/index.js:709:12)
    at NodePath.setScope (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/path/context.js:131:30)
    at NodePath.setContext (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/path/context.js:147:8)
    at NodePath.pushContext (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/path/context.js:213:8)
    at TraversalContext.visitQueue (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/context.js:100:14)
    at TraversalContext.visitMultiple (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/context.js:79:17)
    at TraversalContext.visit (/Users/REDACTED/REDACTED/node_modules/@babel/traverse/lib/context.js:138:19)

I got the same issue using the latest version

Same issue when I use @react-native-community/eslint-config@2.0.0 which depends on eslint-plugin-react-native@3.10.0.

Adding eslint-disable in the file doesn't fix it, so I had to add the file to .eslintignore. Fortunately it was only a single small file for us. 😕

+1

eslint error:
`> eslint "**/*.{js,ts,tsx}" -o ./eslint-report.txt

Oops! Something went wrong! :(

ESLint: 7.13.0

Error: Couldn't find a Program
Occurred while linting /Volumes/T7 Touch/code/react-native-mb-ui/example/src/views/actionsheet/view.tsx:59`

actionsheet/view.tsx:59
<Text onPress={() => setCustomCloseExtra(false)}>取消</Text>

Can confirm this happened to me on a larger project. Version 3.10.0 produces the Error: Couldn't find a Program. Downgrading to 3.8.1 fixes this issue (for the time being).

Same issue here with eslint-plugin-react-native@3.10.0 when trying to use a arrow function inside JSX:

<Button onPress={() => functionWithuseCallback(true)}>Click me</Button>

Came up with a workaround 😄

"rules": {
  "react-native/no-raw-text": "off",
},

I'm also getting this error with both arrow functions on onPress and the Text issue. It happens while coding on VSCode by showing a popup with text "ESLint: Couldn't find a Program Occurred while linting..." and also when trying to commit via precommit hooks.

Package.json:

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "cross-env COMPONENT_LIBRARY_DEVELOPMENT=false expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "fix": "yarn fix:eslint && yarn fix:prettier",
    "fix:eslint": "eslint \"{src}/**/*.{ts,tsx,js,jsx}\" --fix",
    "fix:prettier": "prettier \"{src}/**/*.{ts,tsx,js,jsx,json}\" --write --config ./.prettierrc.json --ignore-path ./.prettierignore",
    "lint": "eslint --config .eslintrc.json --ignore-path .eslintignore",
    "test": "jest --watchAll",
    "storybook": "start-storybook -p 7007",
    "prestorybook": "rnstl",
    "start:component-library": "cross-env COMPONENT_LIBRARY_DEVELOPMENT=true expo start",
    "build-storybook": "build-storybook",
    "build-static-webapp": "cross-env COMPONENT_LIBRARY_DEVELOPMENT=true expo build:web"
  },
  "jest": {
    "preset": "jest-expo"
  },
  "dependencies": {
    "@expo/vector-icons": "^12.0.0",
    "@react-native-community/masked-view": "0.1.10",
    "@react-navigation/bottom-tabs": "5.11.2",
    "@react-navigation/native": "~5.8.10",
    "@react-navigation/stack": "~5.12.8",
    "cross-env": "^7.0.3",
    "expo": "~40.0.0",
    "expo-asset": "~8.2.1",
    "expo-constants": "~9.3.0",
    "expo-firebase-recaptcha": "^1.3.0",
    "expo-font": "~8.4.0",
    "expo-linking": "~2.0.0",
    "expo-splash-screen": "~0.8.0",
    "expo-status-bar": "~1.0.3",
    "expo-web-browser": "~8.6.0",
    "firebase": "^8.3.1",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
    "react-native-dotenv": "^2.5.3",
    "react-native-gesture-handler": "~1.8.0",
    "react-native-safe-area-context": "3.1.9",
    "react-native-screens": "~2.15.0",
    "react-native-web": "~0.13.12",
    "react-native-webview": "^11.3.1",
    "styled-components": "^5.2.1"
  },
  "devDependencies": {
    "@babel/core": "~7.9.0",
    "@commitlint/config-conventional": "^9.0.1",
    "@storybook/addon-a11y": "^6.1.21",
    "@storybook/addon-actions": "^5.3",
    "@storybook/addon-knobs": "^5.3",
    "@storybook/addon-links": "^5.3",
    "@storybook/addon-ondevice-actions": "^5.3.23",
    "@storybook/addon-ondevice-knobs": "^5.3.25",
    "@storybook/react-native": "^5.3.25",
    "@storybook/react-native-server": "^5.3.23",
    "@testing-library/react-native": "^7.2.0",
    "@types/jest": "^26.0.21",
    "@types/react": "~16.9.35",
    "@types/react-native": "~0.63.2",
    "@types/react-test-renderer": "^17.0.1",
    "@types/styled-components": "^5.1.9",
    "@types/styled-components-react-native": "^5.1.1",
    "@typescript-eslint/eslint-plugin": "^3.4.0",
    "@typescript-eslint/parser": "^3.4.0",
    "babel-loader": "^8.2.2",
    "eslint": "^6.6.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-better-styled-components": "^1.1.2",
    "eslint-plugin-import": "^2.22.0",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-react": "^7.23.1",
    "eslint-plugin-react-hooks": "^4.0.6",
    "eslint-plugin-react-native": "^3.10.0",
    "eslint-plugin-sort-destructure-keys": "^1.3.5",
    "eslint-plugin-typescript-sort-keys": "^1.2.0",
    "husky": "^4.2.5",
    "jest-expo": "~40.0.0",
    "lint-staged": "^10.2.11",
    "prettier": "^2.0.5",
    "react-native-storybook-loader": "^2.0.2",
    "react-test-renderer": "^17.0.2",
    "typescript": "~4.0.0"
  },
  "private": true,
  "commitlint": {
    "extends": [
      "@commitlint/config-conventional"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },
  "lint-staged": {
    "src/**/*.{js,jsx,ts,tsx}": [
      "eslint --config .eslintrc.json --ignore-path .eslintignore --fix",
      "prettier --write --config .prettierrc.json --ignore-path .prettierignore",
      "git add"
    ]
  },
  "config": {
    "react-native-storybook-loader": {
      "searchDir": [
        "./src/components"
      ],
      "pattern": "**/__stories__/*.story.tsx",
      "outputFile": "./src/storybook/storyLoader.js"
    }
  }
}

.eslintrc.json

{
  "env": {
    "browser": true,
    "react-native/react-native": true,
    "commonjs": true,
    "node": true,
    "es6": true
  },
  "extends": [
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/typescript",
    "plugin:prettier/recommended",
    "prettier/@typescript-eslint"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": 2020,
    "project": ["./tsconfig.json"],
    "sourceType": "module"
  },
  "plugins": [
    "@typescript-eslint",
    "better-styled-components",
    "import",
    "prettier",
    "react",
    "react-hooks",
    "react-native",
    "sort-destructure-keys",
    "typescript-sort-keys"
  ],
  "rules": {
// Bunch of rules that I won't add

Using node v14.16.0

Have the same issue with "eslint-plugin-react-native": "^3.10.0", when trying to replace

<SomeComponent prop={array.reduce((acc, item) => [...acc, processItem(item)], [])} />

with

const prop = useMemo(
    () => 
        array.reduce(
            (acc, item) => [
                ...acc, 
                processItem(item)
            ],
            []
        ), 
    [array]
);

// ...

<SomeComponent prop={prop} />

Disabled this rule for now, waiting for a proper solution.

This is still present in 3.11.0.

The minimum conditions to reproduce this linting crash are:
=> Having a component with a function passed as a prop AND any kind of children.

So, the minimal reproducible example is the following one:

<MyComponent myFunctionProp={() => {}}>my children</MyComponent>;

To fix this issue, you should define the prop before passing it, like so:

const myFunction = () => {};
<MyComponent myFunctionProp={myFunction}>my children</MyComponent>;

To fix this issue, you should define the prop before passing it, like so:

@VincentJouanne This doesn't work with useCallback hook though 🙁

@Xriot Can you post the minimum reproducible example with a useCallback() ?

Still getting this issue on:

eslint 7.14.0
eslint-plugin-react-native: 3.11.0

:/

Really appreciate the amount of attention this gets from the maintainers.

The minimum conditions to reproduce this linting crash are: => Having a component with a function passed as a prop AND any kind of children.

So, the minimal reproducible example is the following one:

<MyComponent myFunctionProp={() => {}}>my children</MyComponent>;

To fix this issue, you should define the prop before passing it, like so:

const myFunction = () => {};
<MyComponent myFunctionProp={myFunction}>my children</MyComponent>;

no help if I need to pass an arg, sadly

The minimum conditions to reproduce this linting crash are: => Having a component with a function passed as a prop AND any kind of children.
So, the minimal reproducible example is the following one:
<MyComponent myFunctionProp={() => {}}>my children</MyComponent>;
To fix this issue, you should define the prop before passing it, like so:

const myFunction = () => {};
<MyComponent myFunctionProp={myFunction}>my children</MyComponent>;

no help if I need to pass an arg, sadly

what do you mean by that?

The minimum conditions to reproduce this linting crash are: => Having a component with a function passed as a prop AND any kind of children.
So, the minimal reproducible example is the following one:
<MyComponent myFunctionProp={() => {}}>my children</MyComponent>;
To fix this issue, you should define the prop before passing it, like so:

const myFunction = () => {};
<MyComponent myFunctionProp={myFunction}>my children</MyComponent>;

no help if I need to pass an arg, sadly

what do you mean by that?

const onPressButton = id => foo(id)

....

{ myButtons.map((text,id)=><Button onPress={()=>onPressButton(id)}>{text}</Button>) }


ETA: I have worked out a work-around for this - a curried function:

const onPressButton = id => () => foo(id)     <--- notice extra () =>

....

{ myButtons.map((text,id)=><Button onPress={onPressButton(id)}>{text}</Button>) }


I had this problem with the code below

 <Text>
    Something?{' '}
    <TouchableOpacity
      onPress={() => fun()}
    >
      <Text>
        Something
      </Text>
    </TouchableOpacity>
</Text>

I have no idea why, I just tweaked the text to this and the error went away.

 <Text>
    <Text>Something? </Text>
    <TouchableOpacity
      onPress={() => fun()}
    >
      <Text>
        Something
      </Text>
    </TouchableOpacity>
</Text>

Might be related to some structure of nested text RN elements in my case.

#314 should fix this

@hsource still exists

@hsource still exists

That shouldn't be right! What error message are you seeing? If you'd like to test with a build, you can also do yarn add hsource/eslint-plugin-react-native#v4.0.0-wanderlog.2 to use the patched version

Thanks! I'll try it out.
Basically the linter doesn't detect a custom component

For those interested, here is my brief explanation about this issue: #314 (comment)

When will this fix be released @hsource @JLHwung ?

The problem still exists in v4.0.0. Have to temporarily turn the rule off

Had the same problem, fixed it by assigning the value to a constant. Simplified example:

Didn't work:
function displaySomething() { return ( <Text>functionThatReturnsAName(id)</Text> )}

Works:

function displaySomething() { const name = functionThatReturnsAName(id) return ( <Text>{name}</Text> )}

Not sure if this is helpful for anyone but worked for me and it is prettier imo.

Any timeline on the possibility of the PR that fixes it being merged?

commented

Still present in!

eslint: 8.35.0
eslint-plugin-react: 7.32.2
eslint-plugin-react-native: 4.0.0

Having this issue as well...

My config:

eslint@8.44.0
eslint-plugin-react@7.32.2
eslint-plugin-react-native@4.0.0

The error:

$ eslint .

Oops! Something went wrong! :(

ESLint: 8.44.0

Error: Couldn't find a Program
Occurred while linting /home/vibia/platform/services/app-on-site/apps/expo/app/paper/paper.tsx:62
Rule: "react-native/no-raw-text"
    at Scope.getProgramParent (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/scope/index.js:753:11)
    at Scope.crawl (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/scope/index.js:665:32)
    at Scope.init (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/scope/index.js:655:12)
    at NodePath.setScope (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/path/context.js:120:61)
    at NodePath.setContext (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/path/context.js:132:8)
    at NodePath.pushContext (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/path/context.js:189:8)
    at TraversalContext.visitQueue (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/context.js:78:14)
    at TraversalContext.visitSingle (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/context.js:65:19)
    at TraversalContext.visit (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/context.js:109:19)
    at traverseNode (/home/vibia/platform/services/app-on-site/node_modules/eslint-plugin-react-native/node_modules/@babel/traverse/lib/traverse-node.js:18:17)
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed.
Exit code: 2