Чтобы использовать Angular CLI на полную, разработчики должны знать, что такое схематики. Например, команды ng add, ng update и ng generate используют схематики для добавления, обновления и настройки библиотек и кодогенерации в приложениях. Во время выполнения схематика вы получаете доступ к файловой системе и можете мутировать исходный код приложения так, как вам нужно. «Но, чтобы мутировать код, нужно работать с AST, а это сложно», — возможно, скажете вы, и будете правы! В этой статье расскажу, как мы пытаемся упростить работу с AST и сделать написание схематиков обыденным. А еще покажу, что так же просто можно работать с AST не только в Angular-проектах, а практически в любом проекте на JavaScript/TypeScript.  Технически схематик — это функция, которая принимает два аргумента на вход: специфичные для схематика опции и контекст, который используется для логирования и несет в себе утилитарные функции. Функция возвращает тип Rule. Давайте посмотрим на него внимательнее: Из определения типа понятно, что Rule может быть как синхронным, так и асинхронным. И, как бонус, мы можем вернуть Observable. Из типа Rule остался только один неизвестный интерфейс — Tree. Tree — это виртуальная абстракция для работы с файловой системой, изменения в которой накладываются на реальную файловую систему. Каждая команда ng, которая использует схематики, имеет собственные настройки, но в итоге все сводится именно к вызову вышеописанной функции. Мы широко используем схематики по целому ряду причин. Выполнение миграций при обновлении библиотек. В основном используется при мажорных изменениях и помогает разработчикам более просто мигрировать. Сам Angular всегда использует миграции для переезда между версиями. Мы даже контрибьютили в RenovateBot, чтобы у пользователей была возможность запускать миграции при автоматическом обновлении зависимостей. Настройка библиотек при их добавлении в проект. Позволяет сразу подготовить приложение к использованию: добавить импорт в нужный модуль, заинжектить дефолтные конфиги или внести изменения в процесс сборки. Кодогенерация. Быстрое создание скелетов библиотек, приложений, компонентов, директив, etc. Например, схематики позволяют в одну команду создать лейзи роут вашего приложения со всеми нужными базовыми конфигами. Мы широко используем эту возможность не только для добавления и генерации кода новых фичей, но и для миграции кодовой базы на другой функционал. Каждый пункт можно развернуть в достаточно большой список кейсов, но оставим это на откуп вашей фантазии и комментариям. По итогу можно сказать, что написание схематиков неплохо экономит время пользователей. Но… В какой-то момент мы осознали, что на создание схематика потратили больше ресурсов, чем планировали. Хотя задача заключалась в добавлении одного импорта модуля в главный модуль приложения при миграции. Проблема была в том, что мы решили работать с AST для мутаций. Но это не так просто разработчику, который большую часть времени работает с сущностями Angular и версткой. Например, команда Angular использует typescript API в миграциях. Но как часто вы сталкиваетесь с программным использованием пакета typescript? Как часто вы оперируете нодами из TS-компилятора, чтобы добавить пару новых проперти в объект или элемента в массив? Ниже — пример функции, которая добавляет данные в метаданные модуля (оригинал). Осторожно: код приведен для примера, не советую напрягаться и пытаться понять, что в нем происходит! Выглядит совершенно не вдохновляюще. Поэтому мы решили создать верхнеуровневую библиотеку, которая позволяет писать схематики намного проще. В основе библиотеки лежит ts-morph. По сути, ts-morph — это обертка над компилятором typescript, которая упрощает работу с AST. Представляю вашему вниманию ng-morph. Это набор утилит, который позволит вам писать схематики намного проще и быстрее. Чтобы не быть голословным, предлагаю сразу рассмотреть несколько примеров с его использованием. Задача № 1. Добавить импорт модуля SomeModule в корневой модуль приложения. Решение. Рассмотрим решение построчно: Создаем проект ng-morph и делаем его активным. Это важно, так как все утилитарные функции работают именно в контексте активного проекта. Под проектом нужно понимать класс, который дает API к файловой системе, компилятору и т. д. По точке входа приложения находим главный модуль приложения. Добавляем в импорты найденного модуля новый. Добавляем импорт модуля в файл, где расположен корневой модуль. Сохраняем проект. Теперь сравните это решение с функцией выше из исходников Angular. Если вы будете использовать ng-morph, скорее всего, вам не придется писать что-то подобное. Задача № 2. В проекте неожиданно меняется стиль написания имени для enum на uppercase. Решение. Логичные вопросы: при чем здесь ng-morph? Ведь мы говорим про схематики, неужели нужно настраивать и писать схематики только для того, чтобы переименовать энамы? Все верно. Схематики кажутся слишком сложными для переименования энамов. Но все же давайте посмотрим, что нам может предложить ng-morph: Создаем проект. Тут есть важное отличие: скрипт не завернут в функцию схематика и аргумент tree создается вручную с помощью класса NgMorphHost. Ищем все enum в проекте. Переименовываем все enum. На этом примере мы видим, что ng-morph умеет работать и вне функций схематиков! Да, мы используем ng-morph не только в схематиках и не только в Angular-проектах.  Создавать Искать Изменять Удалять Почти по каждой сущности в TS есть свой набор функций: get*, edit*, add*, remove*. Например, getClass, removeConstrucor, addDecorator. Начали появляться утилитарные функции для работы со специфичными для Angular кейсами: getBootstrapFn — функция, возвращающая CallExpression. getMainModule — функция, которая возвращает декларацию главного модуля. Куча утилитарных функций по изменению метаданных сущностей Angular: addDeclarationToNgModule, addProviderToDirective и т. д. ng-morph также содержит утилиты для работы с json. Например, для работы с зависимостями в package.json: Но если нужна более низкоуровневая работы, всегда можно поработать с ts-morph API, а из него провалиться еще ниже — в API самого typescript. На данный момент roadmap не существует. Мы достаточно быстро реализовали то, чего нам не хватало, и решили показать это сообществу. И, естественно, хочется развивать инструмент дальше. Тем не менее список фич первой необходимости все же есть: Высокоуровневая работа с шаблонами. Высокоуровневая работа со стилями. Наращивание тулинга по работе с сущностями Angular. И мы будем рады, если сообщество Angular поможет нам это сделать! Репозиторий с кодом: Сайт с документацией и примерами: Из известных мне — наша дружественная и лучшая библиотека компонентов для Angular: Frontend-developer