I have a use case where I want to replace variable function calls, specifically foo.value.toString()
, with a helper function getStringValue(foo)
. If I find it, I can use the fix to replace the text on the CallExpression
node, so my rule fix currently looks like this:
fixer => fixer.replaceText(node, `getStringValue(${identifierNode.getText()})`);
The problem with automatically fixing this error this way is that getStringValue
may or may not have been imported into the file. I want this fix to have the following behavior:
As far as I understand from the documentation, there is no easy way to access the root ESTree node using a fixer
or context
object. The closest is SourceCode.getText()
, which means I have to parse the source text to resolve the import - I'd rather interact with the entire AST directly. What is the best way to perform this automated import process?
P粉5961619152024-03-29 00:56:42
If you want to be slightly unsafe here, you can assume that the user has not redefined the getStringValue
function locally in their files (usually a safe assumption if you have a codebase to which this rule applies ).
In this case, the best way is to use a selector to check the import, for example:
module.exports = { create(context) { let hasImport = false; let lastImport = null; return { ImportDeclaration(node) { lastImport = node; if (isImportICareAbout(node)) { hasImport = true; } }, "My Selector For Other Linting Logic"(node) { // ... context.report({ messageId: "myReport", fix(fixer) { const fixes = [ fixer.replaceText(node, `getStringValue(${identifierNode.name})`), ]; if (!hasImport) { const newImport = 'import { getStringValue } from "module";'; if (lastImport) { // insert after the last import decl fixes.push(fixer.insertTextBefore(lastImport, newImport)); } else { // insert at the start of the file fixes.push(fixer.insertTextAfterRange([0, 0], newImport)); } } return fixes; }, }); }, }; }, };
P粉0989790482024-03-29 00:43:02
It turns out there is an easy way to extract the AST root node from the context
object. It is located at context.getSourceCode().ast
. I rewrote my fix with the following logic:
fixer => { fixer.replaceText(node, `getStringValue(${identifierNode.getText()})`); const body = context.getSourceCode().ast; const importDeclarations = body.filter(statement => statement.type === AST_NODE_TYPES.ImportDeclaration); ... // Check if the declaration has the import and add the appropriate imports if necessary }