组织需求并将它们移动到文档顶部
Organizing requires and moving them to document Top
我正在应用程序中组织代码。 require 语句没有组织,所以我制作了这个 codemod 来对它们进行排序并将它们添加到页面顶部。
The codemod works,几近完美。我有些疑惑:
- 这是一个好的方法,还是有更正确的方法来使用 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';
is this a ok approach, or is there a more correct way to use the API?
您不应该直接访问 __paths
。如果需要访问所有的NodePaths,可以使用.paths()
方法。如果要访问 AST 节点,请使用 .nodes()
.
例如映射只是
let sortedNames = requires.nodes()(node => node.id.name).sort(sort);
how can I keep the empty line between the sourceStart
(all the requires) and the rest of the source code?
确实没有什么好方法可以做到这一点。参见 this related recast issue。希望有一天,有了 CST,这会变得更容易。
can a similar approach be used in ES6 imports? (ie to sort them with 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();
};
}
我正在应用程序中组织代码。 require 语句没有组织,所以我制作了这个 codemod 来对它们进行排序并将它们添加到页面顶部。
The codemod works,几近完美。我有些疑惑:
- 这是一个好的方法,还是有更正确的方法来使用 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';
is this a ok approach, or is there a more correct way to use the API?
您不应该直接访问 __paths
。如果需要访问所有的NodePaths,可以使用.paths()
方法。如果要访问 AST 节点,请使用 .nodes()
.
例如映射只是
let sortedNames = requires.nodes()(node => node.id.name).sort(sort);
how can I keep the empty line between the
sourceStart
(all the requires) and the rest of the source code?
确实没有什么好方法可以做到这一点。参见 this related recast issue。希望有一天,有了 CST,这会变得更容易。
can a similar approach be used in ES6 imports? (ie to sort them with 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();
};
}