eslint-plugin-ferramentas
Version:
A bundle of useful ESLint rules
116 lines (115 loc) • 5.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.rule = void 0;
const path_1 = require("path");
const utils_1 = require("../../utils");
const Base_1 = require("../Base");
const Debug_1 = require("../Debug");
const Input_1 = require("./Input");
const Metadata_1 = require("./Metadata");
const messages = {
directoryNotImported: [
"The path '{{pathFromWorkingDirectory}}' is not listed.",
'All imported paths need to be included, either in the groups (so they are sorted) or ignored',
].join('\n'),
shouldSwitch: "Imports from '{{rawPath}}' should be above the import from '{{aux.rawPath}}'",
};
const mapTupple = ([a, b], mapper) => [mapper(a), mapper(b)];
const sorters = {
group: (declarations, sort) => {
const [a, b] = mapTupple(declarations, (declaration) => {
const position = sort.groups.findIndex((directory) => declaration.pathFromWorkingDirectory.startsWith(directory));
if (position >= 0) {
/** There was a match, great, just yield the result */
return position;
}
if (sort.ignore.some((directory) => declaration.pathFromWorkingDirectory.startsWith(directory))) {
/** Import was not found on groupings, but explicity told to be ignored */
return null;
}
/** User misconfigured, needs to add an ignore */
return declaration;
});
if (typeof a === 'number' && typeof b === 'number') {
return a - b;
}
return [a, b].reduce((map, declaration) => (declaration !== null && typeof declaration !== 'number' ? map.set(declaration, { messageId: 'directoryNotImported' }) : map), new Map());
},
depth: (declarations) => {
const [aDepth, bDepth] = mapTupple(declarations, (declaration) => declaration.pathFromWorkingDirectory.split(path_1.sep).length);
return aDepth - bDepth;
},
name: ([aDeclaration, bDeclaration], { asc }) => {
const out = aDeclaration.pathFromWorkingDirectory.localeCompare(bDeclaration.pathFromWorkingDirectory);
return asc ? out : out * -1;
},
};
const rule = (0, Base_1.createRule)({
name: Metadata_1.name,
type: 'layout',
fixable: 'code',
hasSuggestions: true,
docs: {
description: [
'Ensure relative imports appear in a specific order as set on the configuration.',
'The paths must be set with root paths and not from the perspective of the files where the import actually happens.',
].join('\n'),
},
schema: Metadata_1.schema,
messages,
}, (input) => ({ ...(0, Input_1.mapSort)(input), ...(0, Debug_1.mapDebugRuleOptionInput)(input) }), (context) => ({
'ImportDeclaration + ImportDeclaration': (node) => {
const declaration = context.getImportDeclaration(node);
context.debug('declaration', declaration);
const previous = declaration.getPreviousSiblingWithSameTypeOrThrow();
context.debug('previous', previous);
const tuppleRelativeness = mapTupple([declaration, previous], (d) => (0, utils_1.isPathRelative)(d.rawPath));
context.debug('tuppleRelativeness', ...tuppleRelativeness);
if (tuppleRelativeness.includes(false)) {
return;
}
let errors = new Map();
const sortedImports = [previous, declaration].sort((...declarations) => {
for (const sort of context.getOption('sort')) {
context.debug('sort.type', sort.type);
const sorter = sorters[sort.type];
const result = sorter(declarations, sort);
if (typeof result === 'number' && result !== 0) {
context.debug('sort.result', result);
return result;
}
if (result instanceof Map) {
context.debug('sort.error', ...result.keys());
errors = new Map([...errors, ...result]);
}
}
return 0;
});
context.debug('errors', ...errors.keys());
const isSorted = sortedImports[0] === previous;
context.debug('isSorted', isSorted);
if (errors.size === 0 && !isSorted) {
errors.set(declaration, {
messageId: 'shouldSwitch',
/** Swap imports */
fix: (fixer) => [
fixer.replaceTextRange(declaration.getRange(true), previous.toString(true)),
fixer.replaceTextRange(previous.getRange(true), declaration.toString(true)),
],
});
}
for (const [declaration, error] of errors.entries()) {
context.report({
loc: declaration.getLocation(false),
...error,
data: {
rawPath: declaration.rawPath,
pathFromWorkingDirectory: declaration.pathFromWorkingDirectory,
'aux.rawPath': previous.rawPath,
'aux.pathFromWorkingDirectory': previous.pathFromWorkingDirectory,
},
});
}
},
}));
exports.rule = rule;