Skip to content
| Marketplace
Sign in
Visual Studio Code>Formatters>Sort MembersNew to Visual Studio Code? Get it now.
Sort Members

Sort Members

MSRublev

|
2 installs
| (0) | Free
Сортирует члены TS/JS-классов и Angular-шаблонов: порядок полей, методов, инжектов, декораторов, импортов, отступов.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Sort Members

Инструмент, который физически приводит TS/JS-классы и Angular-шаблоны к единому стилю — не подсвечивает нарушение (как ESLint-правило @typescript-eslint/member-ordering), а сразу переставляет и правит код. Существует в двух формах на одной и той же логике сортировки:

  • VS Code-расширение — сортировка прямо в редакторе: горячая клавиша, кнопка, контекстное меню, Format Document.
  • npm CLI (sort-members) — массовая сортировка всего проекта одной командой в терминале, без открытия файлов в редакторе (например, в CI или разовой миграцией).

Обе формы собираются из одного кода в этом репозитории и дают идентичный результат. Ниже — установка и запуск для каждой.

Установка и запуск: VS Code-расширение

Установка — соберите .vsix и поставьте вручную (расширение не публикуется в VS Code Marketplace):

npm install
npm run compile
npx vsce package        # получится sort-members-<версия>.vsix

Затем в VS Code: Extensions → ... (три точки вверху панели) → Install from VSIX... → выбрать собранный файл.

Настройка — ключ memberOrdering.order в settings.json (подробнее в разделе «Как настроить свой порядок» ниже).

Запуск — в открытом .ts/.tsx/.js/.jsx-файле любым способом:

  • Палитра команд: Ctrl+Shift+P → Sort Members: Sort Class
  • Горячая клавиша: Ctrl+Alt+M (macOS — Cmd+Alt+M)
  • Правый клик в редакторе → Sort Members: Sort Class
  • Кнопка-иконка в тулбаре открытого файла (правый верхний угол редактора)
  • Format Document (Shift+Alt+F), если назначить расширение форматтером по умолчанию:
    "[typescript]": { "editor.defaultFormatter": "sort-members.sort-members" },
    "[typescriptreact]": { "editor.defaultFormatter": "sort-members.sort-members" },
    "[javascript]": { "editor.defaultFormatter": "sort-members.sort-members" }
    

Для .html-файлов — команда Sort Members: Format Template (та же горячая клавиша, кнопка, правый клик — работает так же, но только в HTML).

Команда сортирует все классы в файле за один вызов; повторный вызов на уже отсортированном файле ничего не меняет.

Установка и запуск: npm CLI (sort-members)

Установка — в целевом Angular/TS-проекте (том, который будете сортировать):

npm install --save-dev sort-members

Настройка — файл .sortmembersrc.json в корне проекта (см. раздел «Свой порядок для CLI» ниже); без файла используется порядок по умолчанию.

Запуск — добавьте в scripts package.json вашего проекта:

"scripts": {
  "sort": "sort-members src",
  "sort:ts": "sort-members --ts-only src",
  "sort:html": "sort-members --html-only src"
}

и вызывайте как любой npm-скрипт:

npm run sort         # весь src целиком: .ts/.tsx и .html
npm run sort:ts       # только .ts/.tsx
npm run sort:html     # только .html

Подробности CLI (флаги, обход директорий, локальная разработка без публикации, публикация новой версии) — в разделе «Массовая сортировка без VS Code (CLI)».

Порядок по умолчанию

Категории идут сверху вниз в этом порядке; в скобках — имя категории, как оно записывается в memberOrdering.order (см. следующий раздел).

  1. DI-инъекции — поле вида = inject(...) (injected-field), всегда первое в классе.
  2. Input-поля — и через декоратор @Input(), и через сигнальный API (input(), model()) — трактуются одинаково, сразу после инжектов: public-input-field → protected-input-field → private-input-field.
  3. Output-поля — @Output() и output() тоже равнозначны: public-output-field → protected-output-field → private-output-field.
  4. Static readonly поля: public-static-readonly-field → protected-static-readonly-field → private-static-readonly-field.
  5. Static mutable поля: public-static-field → protected-static-field → private-static-field.
  6. Сигналы состояния — signal(), computed(), effect(): public-state-signal-field → protected-state-signal-field → private-state-signal-field.
  7. Instance readonly поля — всё остальное readonly: обычные поля, @HostBinding, @ViewChild/@ContentChild (и декоратором, и как viewChild()/contentChild()), любые другие декорированные поля — сортируются наравне, только по видимости: public-instance-readonly-field → protected-instance-readonly-field → private-instance-readonly-field.
  8. Instance mutable поля — то же самое, но без readonly: public-instance-field → protected-instance-field → private-instance-field.
  9. Конструктор (constructor).
  10. Lifecycle hooks — по хронологии вызова Angular: ngOnChanges → ngOnInit → ngDoCheck → ngAfterContentInit → ngAfterContentChecked → ngAfterViewInit → ngAfterViewChecked → ngOnDestroy. Только public (Angular не вызывает protected/private версии).
  11. Accessors: get → set.
  12. Static-методы — идут раньше обычных методов: public-static-method → protected-static-method → private-static-method.
  13. Instance-методы — включая @HostListener и любые другие декорированные методы, сортируются наравне с обычными: public-instance-method → protected-instance-method → private-instance-method.

Ключевые идеи: input/output-поля идут единым блоком сразу после инжектов независимо от стиля объявления (декоратор или сигнал); @HostBinding, @HostListener, @ViewChild, @ContentChild не выделены в свои категории — подчиняются тем же правилам видимости/readonly, что и обычные поля/методы; static-методы всегда раньше instance-методов.

Полный список категорий как код — в src/ranking.ts (KNOWN_CATEGORIES).

Гарантия поверх порядка: если поле в инициализаторе читает this.other (например, readonly topics = this._topics.asReadonly()), other всегда окажется выше — даже вопреки категории. Иначе в рантайме this._topics было бы undefined в момент инициализации topics. Это применяется на уровне целых категорий, поэтому вместо чередования пар (_x, x, _y, y, ...) получаются два чистых блока — все private, потом все public.

Index signature и static-блоки никогда не переставляются — остаются на исходных местах.

Что ещё правит команда (кроме порядка)

Помимо перестановки членов, та же команда попутно чинит ещё несколько пунктов из свода правил проекта:

  • Явный модификатор доступа (public/protected/private) — если у поля, метода, конструктора или accessor-а модификатор не указан, добавляется public (это и есть поведение по умолчанию в TS, просто делается явным). Исключение — любой декорированный член (@HostBinding, @HostListener, @Input, @ViewChild и т.п.): модификатор не добавляется, декоратор уже определяет роль члена.
  • Пустые строки между членами класса расставляются заново, независимо от исходного форматирования: между двумя inject()-полями — никогда нет пустой строки (слипаются в один блок вверху класса), между любыми другими соседними членами (в т.ч. внутри одной категории, например двумя @Input()) — всегда ровно одна пустая строка.
  • Группировка импортов — импорты в начале файла разбиваются на два блока через пустую строку: сначала внешние пакеты (@angular/core, rxjs и т.п.), затем локальные (относительные пути, .//../). Порядок внутри каждого блока не меняется (сортировки по алфавиту нет).
  • Пустая строка между case — в switch перед каждой новой необъединённой группой case (не являющейся fallthrough-продолжением предыдущей) добавляется пустая строка, если её ещё нет.
  • JSDoc и обычные комментарии переезжают вместе со своим членом класса при перестановке — ничего не теряется и не рассинхронизируется.
  • // #region / // #endregion — делят тело класса на сегменты: сортировка идёт внутри каждого региона отдельно, член никогда не пересекает его границу. Сама пара region/endregion и текст региона (например, // #region Public API) сохраняются на своих местах.

Все правки идемпотентны — повторный запуск на уже поправленном файле ничего не меняет.

Как настроить свой порядок

Ключ memberOrdering.order в settings.json (глобально или в .vscode/settings.json конкретного проекта):

{
  "memberOrdering.order": [
    "injected-field",
    "constructor",
    "public-instance-method",
    "private-instance-method"
  ]
}
  • Порядок в массиве = порядок в файле. VS Code подсказывает допустимые имена автокомплитом.
  • Категории, которых нет в списке, не исчезают — попадают в конец файла, в исходном относительном порядке между собой.
  • Пустой массив/без настройки → порядок по умолчанию (см. выше).
  • Опечатка в имени категории тихо игнорируется, остальные категории применяются как есть.
  • Изменения подхватываются сразу, без перезагрузки окна.

Свой порядок для CLI

У npm CLI нет settings.json, поэтому порядок задаётся файлом .sortmembersrc.json в корне целевого проекта (там же, откуда запускаете npm run sort) — те же имена категорий, что и в memberOrdering.order:

{
  "order": [
    "injected-field",
    "constructor",
    "public-instance-method",
    "private-instance-method"
  ]
}

Действуют те же правила, что и для VS Code (см. выше): категории, которых нет в списке, уходят в конец файла в исходном порядке; пустой/отсутствующий order → порядок по умолчанию; невалидный JSON или order не массивом строк — CLI печатает предупреждение и использует порядок по умолчанию, ничего не ломая. На HTML-форматирование (sort-members --html-only) этот файл не влияет — порядок атрибутов в шаблонах не настраивается.

Как исключить файлы из сортировки

По умолчанию не трогаются **/*.spec.ts и **/*.spec.tsx — ничего настраивать для этого не нужно.

VS Code — ключ memberOrdering.ignore в settings.json (тот же формат glob-паттернов, что и ниже для CLI):

{
  "memberOrdering.ignore": ["**/*.spec.ts", "**/*.e2e.ts"]
}

CLI — постоянно, полем ignore в .sortmembersrc.json:

{
  "ignore": ["**/*.spec.ts", "**/*.e2e.ts"]
}

или разово флагом (можно указать несколько раз):

node out/cli.js --ignore "**/*.e2e.ts" --ignore "legacy/**" src

Если задать хотя бы один паттерн (в конфиге и/или флагом), он заменяет список по умолчанию, а не дополняет его. Чтобы вернуть сортировку .spec.ts обратно — задайте пустой список: "ignore": [] (или "memberOrdering.ignore": [] в VS Code).

Справочник имён категорий

Полный список того, что можно писать в memberOrdering.order, с расшифровкой:

Имя категории Что это Пример
injected-field Поле-инъекция = inject(...) private readonly svc = inject(Svc);
public-input-field @Input() / input() / model() без модификатора или с public @Input() name!: string;
protected-input-field То же, но protected protected readonly name = input('');
private-input-field То же, но private private readonly name = input('');
public-output-field @Output() / output(), public @Output() closed = new EventEmitter();
protected-output-field То же, protected —
private-output-field То же, private —
public-static-readonly-field static readonly, public static readonly MAX = 5;
protected-static-readonly-field То же, protected —
private-static-readonly-field То же, private —
public-static-field static без readonly, public static counter = 0;
protected-static-field То же, protected —
private-static-field То же, private —
public-state-signal-field signal() / computed() / effect(), public readonly total = computed(...);
protected-state-signal-field То же, protected —
private-state-signal-field То же, private —
public-instance-readonly-field Любое другое readonly-поле экземпляра, public: включает @HostBinding, @ViewChild/@ContentChild, viewChild()/contentChild(), любые декорированные поля @HostBinding('class.x') readonly isX = true;
protected-instance-readonly-field То же, protected —
private-instance-readonly-field То же, private private readonly sub?: Subscription;
public-instance-field То же, но без readonly, public isActive = false;
protected-instance-field То же, protected —
private-instance-field То же, private —
constructor Конструктор класса constructor() {}
public-lifecycle-ngOnChanges … public-lifecycle-ngOnDestroy 8 отдельных категорий — по одной на каждый Angular lifecycle hook, в порядке их вызова ngOnInit(): void {}
get Все get-accessor'ы get value() { ... }
set Все set-accessor'ы set value(v) { ... }
public-static-method static-метод, public static create(): Foo { ... }
protected-static-method То же, protected —
private-static-method То же, private —
public-instance-method Обычный метод экземпляра, public: включает @HostListener и любые другие декорированные методы @HostListener('click') onClick() {}
protected-instance-method То же, protected —
private-instance-method То же, private private loadUser(): void {}

Полный и всегда актуальный список — KNOWN_CATEGORY_NAMES в src/ranking.ts; эта же таблица выше синхронизирована с ним вручную при каждом изменении логики.

Форматирование Angular-шаблонов (.html)

Отдельная команда — Sort Members: Format Template (та же горячая клавиша Ctrl+Alt+M, но действует только в .html-файлах; правый клик в редакторе или Format Document работают так же, как для TS).

Приводит открывающие теги к единому виду:

  • Порядок атрибутов: *ngIf/*ngFor (структурная директива) → #ref → id → class → [class.xxx] → остальные bindings/атрибуты → (event).
  • Если атрибутов 2 и больше — каждый переносится на свою строку, с отступом на один уровень (+2 пробела) от отступа самого тега.

Не трогает: текстовое содержимое, комментарии, тело <script>/<style>.

Осознанно не автоматизировано (риск сломать разметку/CSS выше пользы): БЭМ-нейминг классов (потребовало бы переименования в CSS/SCSS по всему проекту), комментарии к логическим блокам (нечего генерировать осмысленного).

Массовая сортировка без VS Code (CLI)

Чтобы прогнать всю кодовую базу одной командой (без открытия каждого файла вручную), есть CLI-скрипт src/cli.ts (собирается в out/cli.js):

node out/cli.js <путь-к-папке-или-файлу> [ещё пути...]   # .ts/.tsx и .html вместе
node out/cli.js --ts-only <путь>                          # только .ts/.tsx
node out/cli.js --html-only <путь>                        # только .html

Запуск возможен из любой директории — просто укажите полный (абсолютный) путь к cli.js и к папке/файлу проекта, который нужно отсортировать. Пример на Windows (PowerShell), где cli.js лежит в папке этого расширения, а сортируется другой (внешний) Angular-проект:

node "C:\путь\до\этого\расширения\out\cli.js" "C:\путь\до\вашего\проекта\src"
  • Путь может указывать и на папку (рекурсивный обход, node_modules/.git/ dist/out/.angular пропускаются), и на один конкретный файл.
  • Использует ту же логику сортировки, что и команды расширения в VS Code, — результат идентичен ручному запуску.
  • Изменяет файлы на месте и печатает список изменённых.
  • Идемпотентен: повторный запуск на уже отсортированных файлах ничего не меняет и ничего не печатает про них.
  • Перед массовым запуском на реальном проекте убедитесь, что изменения можно отследить/откатить (например, через git status и git diff — правки применяются сразу к файлам на диске, без подтверждения).

Удобный запуск из целевого проекта (npm run sort)

Чтобы вызывать команду так же коротко, как ng serve (без путей к cli.js), у пакета есть bin-запись sort-members.

Вариант A — пакет опубликован в npm (обычная установка):

npm install --save-dev sort-members

Вариант B — локальная разработка без публикации (например, вы правите логику сортировки в этом репозитории и сразу хотите видеть эффект в другом проекте): ставится как file-зависимость, путь после file: — до папки этого расширения на вашем диске:

npm install --save-dev sort-members@file:C:\путь\до\этого\расширения

npm сам создаст симлинк node_modules/.bin/sort-members. При обновлении логики сортировки здесь (npm run compile) достаточно перезапустить npm run sort в целевом проекте — file-зависимость подхватывает изменения без переустановки, т.к. npm создаёт symlink, а не копирует файлы.

В обоих случаях — добавьте в scripts package.json вашего проекта:

"scripts": {
  "sort": "sort-members src",
  "sort:ts": "sort-members --ts-only src",
  "sort:html": "sort-members --html-only src"
}

И запускайте как любой другой npm-скрипт:

npm run sort         # весь src целиком: .ts/.tsx и .html
npm run sort:ts       # только .ts/.tsx
npm run sort:html     # только .html

Без установки зависимости — можно вызвать cli.js и напрямую, указав полный путь к нему при каждом запуске:

node "C:\путь\до\этого\расширения\out\cli.js" src

Публикация пакета в npm

npm run compile
npm login             # один раз на машине
npm publish           # публикует под именем "sort-members" (см. package.json)

Перед публикацией новой версии не забудьте поднять "version" в package.json (npm не даёт дважды опубликовать одну и ту же версию). .npmignore уже настроен так, чтобы в tarball попадали только out/, resources/icon.png, LICENSE, README.md — исходники (src/), карты сборки и тестовые скрипты исключены.

Разработка

npm install
npm run compile   # или F5 — запустит Extension Development Host
npx vsce package  # собрать .vsix
  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft