首页  >  问答  >  正文

如果尚未导入辅助函数,则添加导入声明:带有自定义 ESLint 规则修复程序的增强解决方案

我有一个用例,我想替换变量函数调用,特别是 foo.value.toString() 来使用辅助函数 getStringValue(foo) 。如果我找到它,我可以使用修复程序替换 CallExpression 节点上的文本,因此我的规则修复程序当前如下所示:

fixer => fixer.replaceText(node, `getStringValue(${identifierNode.getText()})`);

以这种方式自动修复此错误的问题是 getStringValue 可能已导入到文件中,也可能尚未导入到文件中。我希望这个修复程序具有以下行为:

  1. 如果该函数已导入到文件中,则无需执行任何其他操作。
  2. 如果该函数未导入,但其包含的文件模块已导入,请将此函数添加到该模块的导入中。
  3. 如果该函数及其包含的文件模块均未导入,则将该模块与该函数一起导入。

据我从文档中了解到,没有简单的方法可以使用 fixercontext 对象访问根 ESTree 节点。最接近的是 SourceCode.getText(),这意味着我必须解析源文本才能解析导入 - 我宁愿直接与整个 AST 交互。执行此自动导入过程的最佳方法是什么?

P粉312195700P粉312195700205 天前297

全部回复(2)我来回复

  • P粉596161915

    P粉5961619152024-03-29 00:56:42

    如果您想在这里稍微不安全,您可以假设用户没有在其文件中本地重新定义 getStringValue 函数(如果您拥有此规则所适用的代码库,通常是一个安全的假设)。

    在这种情况下,最好的方法是使用选择器来检查导入,例如:

    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;
              },
            });
          },
        };
      },
    };

    回复
    0
  • P粉098979048

    P粉0989790482024-03-29 00:43:02

    事实证明,有一种简单的方法可以从 context 对象中提取 AST 根节点。它位于 context.getSourceCode().ast。我用以下逻辑重写了我的修复程序:

    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
    }
    

    回复
    0
  • 取消回复