UNPKG

eslint-plugin-kisszaya-fsd-plugin

Version:

Plugin to format code by fsd principles

181 lines (180 loc) 7.38 kB
"use strict"; 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("/"); } }