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 2
You can do one of three things—
OPTION 1
Webstorm : Setup a file watcher
Open Settings > File watchers, and setup a new one similar to this. Note the node and the script path. You may need to setup duplicates of this for each file type you want to run this on.

OPTION 2
VSCode : Setup a task
Install the Run on Save extension, if you don’t have it already.
In your settings.json, add this:
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.(js|jsx|ts|tsx)$",
"command": "node /path/to/your/serisei-formatter.js ${file}"
}
]
}Make sure you add the path to the script correctly.
OPTION 3
Global : Use it via the terminal
This makes the serisei command available from any directory.
# Go into the repo
cd seri-sei
# Make it executable (macOS/Linux)
chmod +x serisei-formatter.js
# Link it globally
npm link
# Use it anywhere
serisei path/to/file.jsSTEP 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 theOTHERgroup.
STEP 4
Heave a sigh of relief.