Created
October 28, 2024 20:23
-
-
Save nfarina/3e4fbecac32053c4b31053fbccc37b15 to your computer and use it in GitHub Desktop.
React Compiler ESLint Plugin with all errors surfaced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as BabelParser from "@babel/parser"; | |
import BabelTraverse from "@babel/traverse"; | |
import { | |
compileProgram, | |
parsePluginOptions, | |
} from "babel-plugin-react-compiler"; | |
const traverse = BabelTraverse["default"]; | |
const parse = BabelParser.parse; | |
/** | |
* An ESLint plugin that attempts to actually run the React Compiler the way it | |
* does in the Playground. This will tell us if the component or hook has any | |
* issues that prevent it from being compiled. The eslint-plugin-react-compiler | |
* plugin doesn't do this, and instead just checks for a small variety of | |
* "Rules of React" problems. | |
* | |
* I wrote this before I knew about the `__unstable_donotuse_reportAllBailouts` | |
* option in the official plugin. But it turns out to be useful because we | |
* report the "compiler bailouts" with the correct location information, | |
* compared to the official plugin. Also the speed is identical. | |
*/ | |
export default { | |
rules: { | |
"react-compiler": { | |
meta: { | |
type: "problem", | |
docs: { | |
description: "Detect React Compiler issues", | |
category: "Possible Errors", | |
}, | |
}, | |
create(context) { | |
return { | |
Program(node) { | |
const sourceCode = context.sourceCode.text; | |
const filename = context.filename; | |
// Parse the source code to get a Babel AST | |
const ast = parse(sourceCode, { | |
sourceType: "module", | |
plugins: ["jsx", "typescript"], | |
}); | |
// Create a NodePath for the Program | |
let programPath; | |
traverse(ast, { | |
Program(path) { | |
programPath = path; | |
}, | |
}); | |
if (!programPath) { | |
context.report({ | |
node, | |
message: "Failed to create Babel NodePath for Program", | |
}); | |
return; | |
} | |
// Use default plugin options, but override panicThreshold to | |
// "all_errors" so all errors are thrown. | |
const opts = { | |
...parsePluginOptions(), | |
panicThreshold: "all_errors", | |
}; | |
try { | |
compileProgram(programPath, { | |
opts, | |
filename: filename ?? null, | |
comments: ast.comments ?? [], | |
code: sourceCode, | |
}); | |
} catch (error) { | |
for (const detail of error.details ?? []) { | |
context.report({ | |
node: detail.node, | |
message: error.message, | |
loc: detail.options.loc, | |
}); | |
} | |
} | |
}, | |
}; | |
}, | |
}, | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment