jscodeshift 那点秘密

重构利器 jscodeshift 的末尾,留下了几个问题:

  • 怎么做到同时满足 JavaScriptTypeScript 的解析?
  • jscodeshift 是如何实现链式调用的?
  • registerMethods 怎么实现,怎么使用?
  • 测试工具 testUtils 做了哪些封装?

上一篇文章中我们举了一个 🌰:

export const sum = (a, b) => {
   
  console.log('计算下面两个数的和:', a, b);
  return a + b;
};

export const minus = (a, b) => {
   
  console.log('计算下面两个数的差:' + a + ',' + b);
  return a - b;
};

export const multiply = (a, b) => {
   
  console.warn('计算下面两个数的积:', a, b);
  return a * b;
};

export const divide = (a, b) => {
   
  console.error(`计算下面两个数相除 ${
     a}, ${
     b}`);
  return a / b;
};

转换器 transform 如下:

module.exports = (fileInfo, api, options) => {
   
  const j = api.jscodeshift;
  
  return j(fileInfo.source)
    .find(j.ExpressionStatement, {
   
      expression: {
   
        callee: {
   
          type: 'MemberExpression',
          object: {
    type: 'Identifier', name: 'console' },
        }
      },
    })
    .remove()
    .toSource();
};

咱们从入口开始分析,先看看这个 transform 文件的几个参数是什么?这部分代码位于 src/Worker.js

function run(data) {
   
  const files = data.files;
  const options = data.options || {
   };
  if (!files.length) {
   
    finish();
    return;
  }
  async.each(
    files,
    function(file, callback) {
   
      fs.readFile(file, async function(err, source) {
   
        if (err) {
   
          updateStatus('error', file, 'File error: ' + err);
          callback();
          return;
        }
        source = source.toString();
        try {
   
          // 获取解析器 🛠️
          const jscodeshift = prepareJscodeshift(options);
          
          // 这里的transform就是我们写在transform.js中的函数,对应的参数就是从这里来的
          const out = await transform(
            // 上述 🌰 中的 fileInfo 参数
            {
   
              path: file,
              source: source,
            },
            // 上述 🌰 中的 api 参数
            {
   
              j: jscodeshift,
              jscodeshift: jscodeshift,
              stats: options.dry ? stats : empty,
              report: msg => report(file, msg),
            },
            // 上述 🌰 中的 options 参数
            options
          );
          // 无结果或者跟源码一样时
          if (!out || out === source) {
   
            updateStatus(out ? 'nochange' : 'skip', file);
            callback();
            return;
          }
          // --print 控制台打印结果
          if (options.print) {
   
            console.log(out); // eslint-disable-line no-console
          }
          
          // --dry 🤪🤪 如果不是陪跑,会将结果写入文件
          if (!options.dry) {
   
            writeFileAtomic(file, out, function(err) {
   
              if (err) {
   
                updateStatus('error', file, 'File writer error: ' + err);
              } else {
   
                updateStatus('ok', file);
              }
              callback();
            });
          } else {
   
            updateStatus('ok', file);
            callback();
          }
        } catch(err) {
   
          updateStatus(
            'error',
            file,
            'Transformation error ('+ err.message.replace(/\n/g, ' ') + ')\n' + trimStackTrace(err.stack)
          );
          callback();
        }
      });
    },
    function(err) {
   
      if (err) {
   
        updateStatus('error', '', 'This should never be shown!');
      }
      free();
    }
  );
}

run 的逻辑很简单,遍历文件调用 transform 函数去转换,同时将处理状态通过调用 notify 同步到父进程。先聚焦在获取解析器上:

/**
 * 获取 jscodeshift 解析器
 */
f
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值