1

我正在应用程序中组织代码。require 语句是杂乱无章的,所以我制作了这个 codemod 来对它们进行排序并将它们添加到页面顶部。

codemod 工作,几乎完美。我有些疑惑:

  • 这是一个好的方法,还是有更正确的方法来使用 API?
  • 如何在sourceStart(所有要求)和其余源代码之间保留空行?
  • 可以在 ES6 导入中使用类似的方法吗?(即用 jscodeshift 对它们进行排序)

我的初始代码:

var path = require('path');
var stylus = require('stylus');
var express = require('express');
var router = express.Router();
var async = require('async');

let restOfCode = 'foo';

我的代码模块:

let requires = j(file.source).find(j.CallExpression, {
    "callee": {
        "name": "require"
    }
}).closest(j.VariableDeclarator);

let sortedNames = requires.__paths.map(node => node.node.id.name).sort(sort); // ["async", "express", "path", "stylus"]
let sortedRequires = [];
requires.forEach(r => {
    let index = sortedNames.indexOf(r.node.id.name);
    sortedRequires[index] = j(r).closest(j.VariableDeclaration).__paths[0]; // <- feels like a hack
});

let sourceStart = j(sortedRequires).toSource();
let sourceRest = j(file.source).find(j.CallExpression, {
    "callee": {
        "name": "require"
    }
}).closest(j.VariableDeclaration)
.replaceWith((vD, i) => {
    // return nothing, it will be replaced on top of document
})
.toSource();

return sourceStart.concat(sourceRest).join('\n'); // is there a better way than [].concat(string).join(newLine) ?

我得到的结果是:

var async = require('async');
var express = require('express');
var path = require('path');
var stylus = require('stylus');
var router = express.Router(); // <- I would expect a empty line before this one

let restOfCode = 'foo';
4

1 回答 1

2

这是一个好的方法,还是有更正确的方法来使用 API?

您不应该__paths直接访问。如果需要访问所有的 NodePath,可以使用该.paths()方法。如果要访问 AST 节点,请使用.nodes().

例如,映射只是

let sortedNames = requires.nodes()(node => node.id.name).sort(sort);

如何在sourceStart(所有要求)和其余源代码之间保留空行?

确实没有什么好的方法可以做到这一点。请参阅此相关的重铸问题。希望有一天,使用 CST 会变得更容易。

可以在 ES6 导入中使用类似的方法吗?(即用 jscodeshift 对它们进行排序)

当然。


FWIW,这是我的版本(基于您的第一个版本):

export default function transformer(file, api) {
    const j = api.jscodeshift;
    const sort = (a, b) => a.declarations[0].id.name.localeCompare(
        b.declarations[0].id.name
    );

    const root = j(file.source);
    const requires = root
      .find(j.CallExpression, {"callee": {"name": "require"}})
      .closest(j.VariableDeclaration);
    const sortedRequires = requires.nodes().sort(sort);

    requires.remove();

    return root
      .find(j.Statement)
      .at(0)
      .insertBefore(sortedRequires)
      .toSource();
    };
}

https://astexplorer.net/#/i8v3GBENZ7

于 2016-06-23T06:06:16.533 回答