eslint-plugin-kisszaya-fsd-plugin
Version:
Plugin to format code by fsd principles
181 lines (180 loc) • 7.38 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fsdRelativePath = exports.MessageIds = void 0;
const utils_1 = require("@typescript-eslint/utils");
const schema_1 = require("./schema");
const path_1 = __importDefault(require("path"));
const helpers_1 = require("./helpers");
var MessageIds;
(function (MessageIds) {
MessageIds["ISSUE_SHOULD_BE_RELATIVE"] = "issue:relative";
MessageIds["ISSUE_SHOULD_BE_ABSOLUTE"] = "issue:absolute";
})(MessageIds || (exports.MessageIds = MessageIds = {}));
const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://example.com/rule/${name}`);
exports.fsdRelativePath = createRule({
name: "fsd-relative-path",
meta: {
fixable: "code",
docs: {
description: "Imports within one slice should be relative",
},
type: "problem",
messages: {
[MessageIds.ISSUE_SHOULD_BE_RELATIVE]: "Import should be relative",
[MessageIds.ISSUE_SHOULD_BE_ABSOLUTE]: "Import should be absolute",
},
schema: schema_1.SCHEMA,
},
defaultOptions: [],
create: (context) => {
const alias = context.options[0].alias || "";
const srcPath = context.options[0].srcPath || schema_1.ALIAS_START_PATH;
const projectStructure = context.options[0].projectStructure;
return {
ImportDeclaration(node) {
const filename = context.physicalFilename;
const importPath = node.source.value;
const normalizedFilename = (0, helpers_1.normalizePath)(filename);
if (!normalizedFilename.includes(srcPath)) {
return;
}
const checker = new RelativePathChecker(alias, projectStructure, srcPath);
const isRelativePath = checker.isRelative(importPath);
const isAbsolutePath = (0, helpers_1.isAbsolute)({
importPath,
alias,
projectStructure,
});
if (!isRelativePath && !isAbsolutePath) {
return;
}
const { requiredPath: requiredAbsolutePath, shouldBeAbsolute } = checker.shouldBeAbsolute({
filename,
importPath,
});
if (isRelativePath && shouldBeAbsolute) {
return context.report({
node,
messageId: MessageIds.ISSUE_SHOULD_BE_ABSOLUTE,
fix: (fixer) => {
return fixer.replaceText(node.source, requiredAbsolutePath !== null && requiredAbsolutePath !== void 0 ? requiredAbsolutePath : "");
},
});
}
const { requiredPath: requiredRelativePath, shouldBeRelative } = checker.shouldBeRelative({ filename, importPath });
if (isAbsolutePath && shouldBeRelative) {
return context.report({
node,
messageId: MessageIds.ISSUE_SHOULD_BE_RELATIVE,
fix: (fixer) => {
return fixer.replaceText(node.source, requiredRelativePath !== null && requiredRelativePath !== void 0 ? requiredRelativePath : "");
},
});
}
},
};
},
});
class RelativePathChecker {
constructor(alias, projectStructure, srcPath) {
this.alias = alias;
this.srcPath = srcPath;
this.projectStructure = projectStructure;
}
isRelative(importPath) {
return (importPath === "." ||
importPath === ".." ||
importPath.startsWith("./") ||
importPath.startsWith("../"));
}
shouldBeAbsolute({ filename, importPath }) {
if (!importPath.startsWith("../")) {
return { shouldBeAbsolute: false };
}
const importPathElems = this.getRelativeImportPathElems({
importPath,
filename,
});
const importPathPattern = (0, helpers_1.getPattern)({
elems: importPathElems,
projectStructure: this.projectStructure,
});
const filenameElems = (0, helpers_1.getFilenameElems)({ filename, srcPath: this.srcPath });
const filenamePattern = (0, helpers_1.getPattern)({
elems: filenameElems,
projectStructure: this.projectStructure,
});
const isTheSamePattern = this.checkPattern({
pattern: filenamePattern,
importPathElems,
filenameElems,
});
if (isTheSamePattern) {
return { shouldBeAbsolute: false };
}
return {
shouldBeAbsolute: true,
requiredPath: this.getRequiredAbsolutePath({
importPathPattern,
importPathElems,
}),
};
}
getRequiredAbsolutePath({ importPathElems, importPathPattern, }) {
return `'${this.alias + importPathElems.slice(0, importPathPattern.length).join("/")}'`;
}
shouldBeRelative({ filename, importPath }) {
const importPathElems = (0, helpers_1.getAbsoluteImportPathElems)({
importPath,
alias: this.alias,
});
const filenameElems = (0, helpers_1.getFilenameElems)({ filename, srcPath: this.srcPath });
const pattern = (0, helpers_1.getPattern)({
elems: filenameElems,
projectStructure: this.projectStructure,
});
const isTheSamePattern = this.checkPattern({
pattern,
importPathElems,
filenameElems,
});
if (!isTheSamePattern) {
return {
shouldBeRelative: false,
};
}
return {
shouldBeRelative: true,
requiredPath: this.getRequiredRelativePath({
importPathElems,
filenameElems,
}),
};
}
getRequiredRelativePath({ importPathElems, filenameElems, }) {
let result = path_1.default.relative(path_1.default.dirname(path_1.default.join(...filenameElems)), path_1.default.join(...importPathElems));
if (!result.startsWith("..")) {
return `'./${result}'`;
}
return `'${result}'`;
}
checkPattern({ pattern, importPathElems, filenameElems, }) {
let isTheSamePattern = true;
for (let i = 0; i < pattern.length; i++) {
isTheSamePattern = filenameElems[i] === importPathElems[i];
if (!isTheSamePattern) {
break;
}
}
return isTheSamePattern;
}
getRelativeImportPathElems({ filename, importPath, }) {
const normalizedImportPath = filename.includes("\\")
? (0, helpers_1.normalizePath)(path_1.default.win32.resolve(path_1.default.win32.dirname(filename), importPath))
: (0, helpers_1.normalizePath)(path_1.default.win32.resolve(path_1.default.win32.dirname(filename), importPath));
return normalizedImportPath.split(this.srcPath)[1].split("/");
}
}