SeriSei
A very opinionated pseudo-formatter that groups and sorts import statements and column-indents TypeScript types, interfaces, and objects.
Make sense of your imports.

Organised in categories, with a commented line length you specify.

Seems familiar?

import axios from "axios";
import { Button } from "components/Button";
import type { User,
UserProfile } from "types/user";
import { motion, AnimatePresence } from "framer-motion";
import { legacyApiCall } from "services/legacy";
import { ADMIN_ROUTES, USER_ROUTES } from "configs/routes";
import { useAuth } from "contexts/AuthContext";
import Image from "next/image";
import { useToast } from "hooks/useToast";
import { 
  DndContext, 
  closestCenter,
    KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
} from "@dnd-kit/core";
import { Sidebar } from "components/Sidebar";
import { debounce } from "utils/performance";
import { oldFormatUser } from "lib/migrations";
import { Header } from "components/Header";
import dayjs from "dayjs";
import { Modal } from "components/Modal";
import { Editor } from "@tiptap/react";
import { useWebSocket } from "hooks/useWebSocket";
import { Row, Column } from "fictoan-react";
import { analyticsService } from "services/analytics";

All neatly organised and grouped.

// EXTERNAL ===============================================
import Image from "next/image";
import axios from "axios";
import { 
    DndContext, 
    closestCenter,
    KeyboardSensor,
    PointerSensor,
    useSensor,
    useSensors
} from "@dnd-kit/core";
import { motion, AnimatePresence } from "framer-motion";
import { useRouter } from "next/router";

// FICTOAN ================================================
import { Row, Column } from "fictoan-react";

// CONTEXTS ===============================================
import { useAuth } from "contexts/AuthContext";

// COMPONENTS =============================================
import { Button } from "components/Button";
import { Header } from "components/Header";
import { Sidebar } from "components/Sidebar";

// CONFIGS ================================================
import { ADMIN_ROUTES, USER_ROUTES } from "configs/routes";
import { chartConfig } from "configs/charts";

// LIB ====================================================
import { oldFormatUser } from "lib/migrations";

// SERVICES ===============================================
import { legacyApiCall } from "services/legacy";
import { userService } from "services/userService";

// HOOKS ==================================================
import { useToast } from "hooks/useToast";

// ASSETS =================================================
import logoSvg from "assets/images/logo.svg";

// TYPES ==================================================
import type { ChartData } from "types/charts";
import type { User, UserProfile } from "types/user";

// UTILS ==================================================
import { debounce } from "utils/performance";

// OTHER ==================================================
import dayjs from "dayjs";
Clarity in your type blocks.

Immediately obvious what is optional, and what is not, with column-indented properties.

Low readability.

interface Project {
    id: string;
    name: string;
    description: string;
    startDate: Date;
    endDate?: Date;
    status: 'active' | 'completed' | 'on-hold' | 'cancelled';
    team: TeamMember[];
    budget: number;
    resources: Resource[];
    dependencies: ProjectDependency[];
    risks?: RiskAssessment[];
    milestones: Milestone[];
    deliverables: boolean;
    metrics?: MetricConfig;
    reporting: ReportFrequency;
    approval: { approved: boolean;
    approver: string; date: Date };
    changeControl: ChangeRequest[];
    communication: CommunicationPlan;
}

Far easier to skim, no?

interface Project {
    id              : string;
    name            : string;
    description     : string;
    startDate       : Date;
    endDate       ? : Date;
    status          : 'active' | 'completed' | 'on-hold' | 'cancelled';
    team            : TeamMember[];
    budget          : number;
    resources       : Resource[];
    dependencies    : ProjectDependency[];
    risks         ? : RiskAssessment[];
    milestones      : Milestone[];
    deliverables    : boolean;
    metrics       ? : MetricConfig;
    reporting       : ReportFrequency;
    approval        : {
        approved : boolean;
        approver : string;
        date     : Date
    };
    changeControl   : ChangeRequest[];
    communication   : CommunicationPlan;
}
How to use this

Right now its in an early beta, so its just a local script, and not an NPM package.

STEP 1

Clone the Seri Sei repo from GitHub.

git clone https://github.com/sujan-s/seri-sei.git

STEP 2

You can do one of three things—

STEP 3

While there are some sensible defaults SeriSei uses, you can customise it with a .seriseirc file in your project root. Here’s how one might look—

# .seriseirc
HEADER_CHAR = =
TO_COLUMN_WIDTH = 120

[groups]
# Use quotes to match the exact package name
// REACT CORE = "react", "react-router-dom", "next/", tanstack, tauri, "react-use", dnd-kit, react-dom

// UI = "fictoan-react", framer
// LOCAL COMPONENTS = components/, Page
// CONFIGS = configs/,
// STATE MANAGEMENT = zustand, store/
// LIB = lib/
// HOOKS = hooks/,
// UTILS = utils/,
// ASSETS = assets
// TYPES = types, typings
// SERVICES = services/
// STYLES = .css, styles/
// OTHER =
  • HEADER_CHAR: The length of the commented import group header.

  • TO_COLUMN_WIDTH: The character used in the group header after the name.

  • [groups]: Here you can setup what goes inside what group. Quotes match the exact package name, while no quotes means a partial match. Anything that doesn’t match goes into the OTHER group.

STEP 4

Heave a sigh of relief.