UNPKG

eslint-plugin-kisszaya-fsd-plugin

Version:

Plugin to format code by fsd principles

122 lines (107 loc) 3.27 kB
import { ESLintUtils } from "@typescript-eslint/utils"; import {ALIAS_START_PATH, SCHEMA, SchemaOptions} from "./schema"; import {getAbsoluteImportPathElems, getPattern, isAbsolute, normalizePath} from "./helpers"; import { ProjectStructureSchema } from "../../types"; export enum MessageIds { ISSUE_ABSOLUTE_IMPORT_SHOULD_BE_FROM_PUBLIC_API = "issue:public-api", } const createRule = ESLintUtils.RuleCreator( (name) => `https://example.com/rule/${name}`, ); export const fsdAbsolutePublicApiImports = createRule< SchemaOptions[], MessageIds >({ name: "absolute-public-api-imports", meta: { fixable: "code", docs: { description: "Absolute imports should be only from public api, not inside module", }, type: "problem", messages: { [MessageIds.ISSUE_ABSOLUTE_IMPORT_SHOULD_BE_FROM_PUBLIC_API]: "Absolute import should be from public api", }, schema: SCHEMA, }, defaultOptions: [], create: (context) => { const alias = context.options[0].alias || ""; const srcPath = context.options[0].srcPath || ALIAS_START_PATH; const projectStructure = context.options[0].projectStructure; return { ImportDeclaration(node) { const importPath = node.source.value; const filename = context.physicalFilename; const normalizedFilename = normalizePath(filename) if (!normalizedFilename.includes(srcPath)) { return; } const checker = new PublicApiImportsChecker(alias, projectStructure); const isAbsolutePath = isAbsolute({ importPath, alias, projectStructure, }); if (!isAbsolutePath) { return; } const { isViolated, requiredPath } = checker.checkPublicApiImportsViolated({ importPath, }); if (isViolated) { return context.report({ node, messageId: MessageIds.ISSUE_ABSOLUTE_IMPORT_SHOULD_BE_FROM_PUBLIC_API, fix: (fixer) => { return fixer.replaceText(node.source, requiredPath ?? ""); }, }); } }, }; }, }); class PublicApiImportsChecker { private readonly alias: string; private readonly projectStructure: ProjectStructureSchema; constructor(alias: string, projectStructure: ProjectStructureSchema) { this.alias = alias; this.projectStructure = projectStructure; } checkPublicApiImportsViolated({ importPath }: { importPath: string }): { isViolated: boolean; requiredPath?: string; } { const importPathElems = getAbsoluteImportPathElems({ importPath, alias: this.alias, }); const pattern = getPattern({ elems: importPathElems, projectStructure: this.projectStructure, }); if (importPathElems.length > pattern.length) { return { isViolated: true, requiredPath: this.getRequiredPath({ pattern, importPathElems }), }; } return { isViolated: false, }; } getRequiredPath({ importPathElems, pattern, }: { pattern: string[]; importPathElems: string[]; }) { return `'${this.alias + importPathElems.slice(0, pattern.length).join("/")}'`; } }