Skip to content

Instantly share code, notes, and snippets.

@jridgewell
Last active October 30, 2020 03:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jridgewell/b2196fdb1777fc74ff71980a30d4446c to your computer and use it in GitHub Desktop.
Save jridgewell/b2196fdb1777fc74ff71980a30d4446c to your computer and use it in GitHub Desktop.
Sort imports by source location, prioritizing external, sibling, then parents
module.exports = {
create(context) {
const imports = [];
const source = context.getSourceCode();
function sorter(a, b) {
const l = Math.max(a.length, b.length);
for (let i = 0; i < l; i += 1) {
if (a[i] === '.' && b[i] !== '.' && b[i] !== '..') return +1;
if (b[i] === '.' && a[i] !== '.' && a[i] !== '..') return -1;
if (a[i] === '..' && b[i] !== '..') return +1;
if (b[i] === '..' && a[i] !== '..') return -1;
if (a[i] > b[i]) return +1;
if (a[i] < b[i]) return -1;
if (a.length < b.length) return -1;
if (a.length > b.length) return +1;
}
return 0;
}
function process() {
if (imports.length === 0) return;
const nodes = imports.slice();
const sorted = nodes.slice().sort((a, b) => {
return sorter(a.source.value.split('/'), b.source.value.split('/'));
});
imports.length = 0;
const isSorted = sorted.every((v, i) => nodes[i] === v);
if (isSorted) return;
context.report({
node: sorted[0],
message: 'imports must be sorted by source path',
fix(fixer) {
const s = sorted.map((n) => source.getText(n)).join('\n');
return fixer.replaceTextRange([nodes[0].range[0], nodes[nodes.length - 1].range[1]], s);
},
});
}
function sortImports(node) {
const specifiers = node.specifiers.filter((s) => s.type === 'ImportSpecifier');
const sorted = specifiers.slice().sort((a, b) => {
if (a.length < b.length) return -1;
if (a.length > b.length) return +1;
return 0;
});
const isSorted = sorted.every((v, i) => specifiers[i] === v);
if (isSorted) return true;
context.report({
node: sorted[0],
message: 'import specifiers must be sorted alphabetically',
fix(fixer) {
return fixer.replaceTextRange(
[specifiers[0].range[0], specifiers[specifiers.length - 1].range[1]],
sorted.map((n) => source.getText(n)).join(', '),
).join;
},
});
return false;
}
return {
'Program:exit'() {
console.log(context.getFilename());
debugger;
process();
},
ImportDeclaration(node) {
debugger;
if (!sortImports(node)) {
return;
}
if (imports.length === 0) {
return imports.push(node);
}
const last = imports[imports.length - 1];
if (node.loc.start.line > last.loc.end.line + 1) {
process();
}
imports.push(node);
},
};
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment