Как изменить встроенные операторы require с помощью codemod (jscodeshift)?

Привет, я пытаюсь написать codemod, который перемещает мою инструкцию require из верхней части файла во внутреннюю функцию конструктора класса.

      const moduleA = require('moduleA');
const moduleB = require('../moduleB');

class Example {
  constructor(context) {
    super(context);
    this.lazy("moduleA", () => { new moduleA() }
    this.lazy("moduleB", () => { new moduleB() }
  }

  async callThis() {
     this.moduleA.callThatMethod();
  }
}

Эти операторы require поверх файла занимают много времени, которое используется только в том случае, если этот API вызывается хотя бы один раз. Так как требование в любом случае кэшируется Node.js на уровне процесса. Я пытаюсь переместить require оператор внутри стрелочной функции.

Как ниже

      class Example {
  constructor(context) {
    super(context);
    this.lazy("moduleA", () => { 
       const moduleA = require('moduleA');
       return new moduleA() 
    }
    this.lazy("moduleB", () => {
      const moduleB = require('../moduleB');
      return new moduleB() 
    }
  }

  async callThis() {
     this.moduleA.callThatMethod();
  }
}

У меня проблемы с достижением этого, потому что я не знаю, как выбрать определенную "ленивую" функцию, а затем переместить верхнюю часть требования.

Любая помощь очень ценится, спасибо

1 ответ

Вам не нужен jscodeshift для такого простого преобразования. С помощью моего инструмента Putout вы можете легко удалить файлы верхнего уровня .require, и добавьте его в lazyфункция:

      const isTopLevel = (vars, {parentPath}) => parentPath.isProgram();

export const match = () => ({
    'const moduleA = require("moduleA")': isTopLevel,
    'const moduleB = require("../moduleB")': isTopLevel,
});

export const replace = () => ({
    'const moduleA = require("moduleA")': '',
    'const moduleB = require("../moduleB")': '',
    '() => new moduleA(context)': `{
        const moduleA = require("moduleA");
        return new moduleA();
    }`,
    '() => new moduleB(context)': `{
        const moduleA = require("../moduleB");
        return new moduleB();
    }`,
});

Попытайся

Если вам нужно отфильтровать this.lazyи иметь много разных модулей, вы можете использовать PutoutScript со значениями шаблона __aа также __bиспользуется для определения и замены Identifierиз idа также StringLiteralиз CallExpression calleeвнутри VariableDeclarator initв const moduleA = require('moduleA') VariableDeclaration:

☝️ Это то, с чем вам ДОЛЖЕН иметь дело при постоянном использовании jscodeshift .

      const isTopLevel = ({parentPath}) => parentPath.isProgram();

export const match = () => ({
    // filter out cases where require path contains name
    'const __a = require(__b)': ({__a, __b}, path) => {
        
        if (!isTopLevel(path))
            return false;
        
        // ☝️ __a: Identifier & {name: string}
        // ☝️ __b: StringLiteral & {value: string};
        return __b.value.includes(__a.name);
    },
    
    // filter out 'this.lazy'
    '() => new __a(context)': ({__a}, path) => {
        // ☝️ parentPath: CallExpression & {callee: MemberExpression}
        return compare(path.parentPath.node.callee, 'this.lazy');
    }
});

export const replace = () => ({
    // remove top-level require according to 'match'-condition'
    'const __a = require(__b)': '',
    
    // insert 'require'
    '() => new __a(context)': ({__a}) => {
        return `() => {
            const __a = require("${__a.name}");
            return new __a();
        }`
    },
});

Попытайся

Другие вопросы по тегам