React19: Add a validator to check plugin compatibility#552
React19: Add a validator to check plugin compatibility#552leventebalogh wants to merge 1 commit intomainfrom
Conversation
Scan plugin module.js bundles for patterns that indicate incompatibility with React 19: removed PropTypes/defaultProps, legacy context, string refs, ReactDOM.render, ReactDOM.findDOMNode, legacy lifecycle methods, and removed React.createFactory.
| var reactPatterns = []reactPattern{ | ||
| { | ||
| rule: react19PropTypes, | ||
| title: "module.js: Uses removed React API propTypes or defaultProps", | ||
| description: "Detected usage of '%s'. propTypes and defaultProps on function components were removed in React 19.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte(".propTypes=")}, | ||
| &containsBytesDetector{pattern: []byte(".defaultProps=")}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19LegacyContext, | ||
| title: "module.js: Uses removed React legacy context API", | ||
| description: "Detected usage of '%s'. contextTypes, childContextTypes, and getChildContext were removed in React 19.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte(".contextTypes=")}, | ||
| &containsBytesDetector{pattern: []byte(".childContextTypes=")}, | ||
| &containsBytesDetector{pattern: []byte("getChildContext")}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19StringRefs, | ||
| title: "module.js: Uses removed React string refs", | ||
| description: "Detected usage of '%s'. String refs were removed in React 19. Use callback refs or React.createRef() instead.", | ||
| detectors: []detector{ | ||
| ®exDetector{regex: regexp.MustCompile(`ref:"[^"]+?"`)}, | ||
| ®exDetector{regex: regexp.MustCompile(`ref:'[^']+'`)}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19CreateFactory, | ||
| title: "module.js: Uses removed React.createFactory", | ||
| description: "Detected usage of '%s'. React.createFactory was removed in React 19. Use JSX instead.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte("createFactory(")}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19FindDOMNode, | ||
| title: "module.js: Uses removed ReactDOM.findDOMNode", | ||
| description: "Detected usage of '%s'. ReactDOM.findDOMNode was removed in React 19. Use DOM refs instead.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte("findDOMNode(")}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19LegacyRender, | ||
| title: "module.js: Uses removed ReactDOM.render or unmountComponentAtNode", | ||
| description: "Detected usage of '%s'. ReactDOM.render and unmountComponentAtNode were removed in React 19. Use createRoot instead.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte("ReactDOM.render(")}, | ||
| &containsBytesDetector{pattern: []byte("unmountComponentAtNode(")}, | ||
| }, | ||
| }, | ||
| { | ||
| rule: react19SecretInternals, | ||
| title: "module.js: Uses React internal __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED", | ||
| description: "Detected usage of '%s'. This internal was removed in React 19.", | ||
| detectors: []detector{ | ||
| &containsBytesDetector{pattern: []byte("__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED")}, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
As far as I can see, these could be semgrep rules? If that's the case there is no need to create a new rule
There was a problem hiding this comment.
+1 all this can work with semgrep and we even have already one for this case
academo
left a comment
There was a problem hiding this comment.
I think most if not all of this check can be a semgrep rule.
|
That's a totally good point, thanks guys, I'll run another circle with this 👍 |
sunker
left a comment
There was a problem hiding this comment.
Just want to flag that Jack's @grafana/react-detect package does exactly this kind of analysis but with a few extras rules. It's published to npm and can be invoked with npx @grafana/react-detect. It also has a --json output mode that could work well for feeding results back into the validator. I think we should use this instead.
What changed?
This PR is trying to add a new validator that is checking if the plugin is compatible with React 19.
It checks:
The rules emit warnings (not errors) so the check is advisory at this point.