javascript 元编程之-代码修改代码

javascript 元编程之-代码修改代码

引言

重构代码是个体力活,特别是在确定重构方案后,剩下就是按方案调整代码,然后进行测试。

如何有好又快的调整到位代码,这是件不容易的事。

简单的代码,可以使用正则表达示进行,如果稍微复杂一点代码,正则表达示就无能为力了。

如我上一篇中讲的修改方法javascript 元编程之 method_missing,我可以在工程中修改一处,如果要修改 50 次接口呢? 我得想想这次重构值不值得了。

还能不能让我随心所欲的写代码了。。。

于是我找到了 jscodeshift,让我能用代码重构我的代码的工具。

jscodeshift 让我有了用代码操作代码的工具。

实现

实例我就使用我上篇文章中的 method_missing 项目,我想把我项目中的接口调用(用url),都调整成 method_missing 调用方式。

如下:


// old
$.ajax('/api/web/project/content/target/mod', {
  type: 'post',
  dataType: 'json',
  data: {
    tid: it.targetId,
    targetImgId: img.objectId,
    pid: pid
  }
}).done(function (data, status, jqXhr) {
  self.hideLoading();
  if (data && data.code === 200 && data.data) {
    it.target = data.data
    // self.paginationConf.onChange()
  }
}).fail(() => {

}).always(() => {

})

// new
this.$api.update_project_content_target_mod({
    tid: it.targetId,
    targetImgId: img.objectId,
    pid: pid
}).then(function (data, status, jqXhr) {
  self.hideLoading();
  if (data && data.code === 200 && data.data) {
    it.target = data.data
    // self.paginationConf.onChange()
  }
}).catch(() => {

}).finally(() => {

})

可以看出新的代码中,把老代码中的 $.ajax 换成了 this.$api,然后用参数生成调用方法名。

最后不仅调整了参数的个数,还调整了参数的值。

想想正则怎么写?

正则应该无能为力。

这时 jscodeshift 就上场了,它能把代码解析成 ast , 然后我们修改 ast,ast 再变成代码。

我的代码如下:


const adapt = require('vue-jscodeshift-adapter');

// 修改 $.ajax
function transform(fileInfo, api) {
  const j = api.jscodeshift

  return j(fileInfo.source)
    .find(j.CallExpression, { callee: { object: { name: '$' }, property: { name: 'ajax' } } })
    .replaceWith(p => {
      const url = p.node.arguments[0]
      const setting = p.node.arguments[1]
      const urlStr = url.value.replace('/api/web/', '').split('/')
      let method = 'get'
      let newSetting

      setting.properties.forEach(i => {
        if (i.key.name.toLowerCase() === 'type') {
          if (i.value.value.toLowerCase() === 'post') {
            method = 'update'
          }
        } else if (i.key.name.toLowerCase() === 'data') {
          newSetting = i.value
        }
      });

      urlStr.unshift(method);

      return j.callExpression(
        j.memberExpression(
          j.memberExpression(j.identifier('this'), j.identifier('$api'), false),
          j.identifier(urlStr.join('_')), false
        ), [newSetting])
    })
    .toSource();
}

// 修改 done
function transform1(fileInfo, api) {
  const j = api.jscodeshift

  return j(fileInfo.source)
    .find(j.MemberExpression, { property: { name: 'done' } })
    .replaceWith(p => {
      p.node.property.name = 'then'
      return p.node
    })
    .toSource();
}

// 修改 fail
function transform2(fileInfo, api) {
  const j = api.jscodeshift

  return j(fileInfo.source)
    .find(j.MemberExpression, { property: { name: 'fail' } })
    .replaceWith(p => {
      p.node.property.name = 'catch'
      return p.node
    })
    .toSource();
}

// 修改 always
function transform3(fileInfo, api) {
  const j = api.jscodeshift

  return j(fileInfo.source)
    .find(j.MemberExpression, { property: { name: 'always' } })
    .replaceWith(p => {
      p.node.property.name = 'finally'
      return p.node
    })
    .toSource();
}

module.exports = adapt(transform);
// module.exports = adapt(transform1);
// module.exports = adapt(transform2);
// module.exports = adapt(transform3);

如何使用


# 使用 bash 循环调用
jscodeshift -t src/myTransforms.js filepath

因为我的代码是 vue 的单文件模块,所以我用的了一个第三方插件 vue-jscodeshift-adapter。

总结

jscodeshift 对于大型工程是重构是很有帮助的。可以让你快速改写大量的代码,而且方便测试。

参考链接

  1. vue-jscodeshift-adapter
  2. write-code-to-rewrite-your-code
  3. jscodeshift
  4. astexplorer
posted @ 2019-08-17 21:36  htoooth  阅读(685)  评论(0编辑  收藏  举报