eslint-plugin-sort-export-all
Version:
ESLint rule that helps sort export *
195 lines (189 loc) • 5.21 kB
JavaScript
import naturalCompare from 'natural-compare';
const name = "eslint-plugin-sort-export-all";
const version = "2.1.0";
const hasDocs = /* @__PURE__ */ new Set(["default-import-name"]);
const blobUrl = "https://github.com/nirtamir2/eslint-plugin-sort-export-all/blob/main/src/rules/";
function RuleCreator(urlCreator) {
return function createNamedRule({
name,
meta,
...rule
}) {
return createRule({
meta: {
...meta,
docs: {
...meta.docs,
url: urlCreator(name)
}
},
...rule
});
};
}
function createRule({
create,
defaultOptions,
meta
}) {
return {
create: (context) => {
const optionsWithDefault = context.options.map((options, index) => {
return {
...defaultOptions[index],
...options
};
});
return create(context, optionsWithDefault);
},
defaultOptions,
meta
};
}
const createEslintRule = RuleCreator(
(ruleName) => hasDocs.has(ruleName) ? `${blobUrl}${ruleName}.md` : `${blobUrl}${ruleName}.test.ts`
);
const isValidOrders = {
asc(a, b) {
return a <= b;
},
ascI(a, b) {
return a.toLowerCase() <= b.toLowerCase();
},
ascN(a, b) {
return naturalCompare(a, b) <= 0;
},
ascIN(a, b) {
return naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0;
},
desc(a, b) {
return isValidOrders.asc(b, a);
},
descI(a, b) {
return isValidOrders.ascI(b, a);
},
descN(a, b) {
return isValidOrders.ascN(b, a);
},
descIN(a, b) {
return isValidOrders.ascIN(b, a);
}
};
const RULE_NAME = "sort-export-all";
const sortExportAll = createEslintRule({
name: RULE_NAME,
defaultOptions: [],
meta: {
type: "suggestion",
fixable: "code",
docs: {
description: "require export * to be sorted",
url: "https://github.com/nirtamir2/eslint-plugin-sort-export-all"
},
messages: {
unorderedSortExportAll: `"export * from '{{beforeName}}'" should occur before "export * from '{{afterName}}'".`
},
schema: [
{
type: "string",
enum: ["asc", "desc"]
},
{
type: "object",
properties: {
caseSensitive: {
type: "boolean"
},
natural: {
type: "boolean"
}
},
additionalProperties: false
}
]
},
create: (context) => {
const order = context.options[0] === "desc" ? "desc" : "asc";
const options = context.options[1];
const insensitive = (options && options.caseSensitive) === false;
const natural = Boolean(options && options.natural);
const functionName = order + (insensitive ? "I" : "") + (natural ? "N" : "");
const isValidOrder = isValidOrders[functionName];
if (isValidOrder === null) {
throw new Error("Invalid options");
}
const nodes = [];
return {
ExportAllDeclaration: (node) => {
if (node.type !== "ExportAllDeclaration") {
return;
}
if ("exportKind" in node && node.exportKind === "type") {
return;
}
nodes.push(node);
},
"Program:exit": () => {
const sortedNodes = nodes.toSorted((a, b) => {
return isValidOrder(a.source.value, b.source.value) ? -1 : 1;
});
for (const [index, sortedNode] of sortedNodes.entries()) {
const node = nodes[index];
if (node == null) {
continue;
}
if (node.source.value === sortedNode.source.value) {
continue;
}
const beforeName = sortedNode.source.value;
const afterName = node.source.value;
if (isValidOrder(beforeName, afterName)) {
context.report({
messageId: "unorderedSortExportAll",
node: sortedNode,
...sortedNode.loc === null ? null : { loc: sortedNode.loc },
data: {
beforeName,
afterName
},
fix(fixer) {
if (node == null) return null;
const fixes = [];
const { sourceCode } = context;
const moveExportAllDeclaration = (fromNode, toNode) => {
const prevText = sourceCode.getText(fromNode);
const thisComments = sourceCode.getCommentsBefore(fromNode);
for (const thisComment of thisComments) {
fixes.push(
fixer.insertTextBefore(
toNode,
`${sourceCode.getText(thisComment)}
`
)
);
fixes.push(fixer.remove(thisComment));
}
fixes.push(fixer.replaceText(toNode, prevText));
};
moveExportAllDeclaration(node, sortedNode);
moveExportAllDeclaration(sortedNode, node);
return fixes;
}
});
}
}
}
};
}
});
const plugin = {
meta: {
name,
version
},
// @keep-sorted
rules: {
"sort-export-all": sortExportAll
}
};
export { name as n, plugin as p };