🔥

Тред (Мышов Саша)


Сегодняшний тред будет про инструменты работы с AST. AST (abstract syntax tree) — это представление исходного текста программы в виде дерева, компилятор использует его для кодогенерации. AST ещё используется для анализа исходного текста программы и его трансформации.

Чем AST может помочь в повседневной работе? Например, для сбора статистики о кодовой базе: какое количество раз и где используется определённая библиотека, вызов задеприкейченного API и т.п.

Причём можно правильно обработать нетривиальные случаи, например, когда библиотека импортируется под неканоничным названием, например import myLodash from 'lodash'.

AST используют бандлеры, для построения графа зависимостей между модулями и правильной сборки большого количество модулей в один бандл.

Есть инструменты, которые анализируют граф зависимостей. С их помощью можно находить модули, которые не используются в проекте, циклические зависимости, также с их помощью можно отрендерить визуальную схему графа.

Dependency Cruiser поддерживает JavaScript (ESM), TypeScript, CoffeeScript, CommonJS, AMD. Для визуализации использует формат dot (GraphViz) github.com/sverweij/depen…

Madge поддерживает только JavaScript (AMD, CommonJS, and ES6 modules), помоимо GraphViz может визуализировать граф с помщью D3 npmjs.com/package/madge

Вот так выглядит часть графа зависимостей Rollup:
notion image

У себя под капотом AST используют линтеры. В eslint есть возможность создавать новые правила с помощью специальных выражений, которые матчатся на узлы AST-дерева. Это может быть полезно для того, чтобы фиксировать договорённости в команде на уровне линтера eslint.org/docs/developer…

Тут немного неправильно. Поддерживает D3 другой Dependo, но он уже не поддерживается 2 года npmjs.com/package/dependo

На базе Babel можно создавать собственные инструменты. Например, в Яндекс Маркете при написании e2e-тестов для поиска React-компонентов в DOM-дерерве используется reselector.

Reselector позволяет использовать компоненты в css-селекторах без добавления служебных классов, всё благодаря парсингу исходного кода в AST github.com/lttb/reselector

Парсер Babel используется в очень многих проектах. Все их можно посмотреть на вкладке "Dependents" на npm npmjs.com/package/@babel…

До монорепизации парсер Babel жил как отдельный проект — "Babylon" npmjs.com/package/babylon

Помимо @babel/parser есть и другие. Один из самых популярных — acorn.js, который тоже используется как основа многих проектов npmjs.com/package/acorn

У него интересная история появления. Его разработал Marijn Haverbeke, как часть проекта по созданию инструмента для умного автодополнения кода на JS — tern.js. Этот проект был проспонсирован сообществом в 2013 году indiegogo.com/projects/tern-…

Tern.js был зарелижен, но не выдержал конкуренцию с TypeScript и Flow. Кроме статической типизации они предоставляют более качественное автодополнение кода по сравнению с tern. В итоге acorn.js стал самостоятельным проектом github.com/acornjs

Ещё один популярный парсер — Esprima, разработанный Ariya Hidayat. Он лежал в основе первых версий eslint npmjs.com/package/esprima

С появлением разных парсеров встал вопрос того, чтобы проекты имели возможность без проблем менять парсер, работающий под капотом. Для решения этой проблемы была разработана спецификация ESTree github.com/estree/estree

Ещё одна категория инструментов — инструменты для написания кодмодов (codemodes). Кодмод — это скрипт, в котором описываются синтаксические трансформации для самых разных целей.

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

Написать кодмод можно, используя любой парсер, например, @babel/parser sitepen.com/blog/codemods-…

Но в Babel есть поддержка для написания кодомодов с помощью специального API. Вот пример такого кодмода, который сделали в Google в рамках проекта по созданию полифилла для BigInt github.com/GoogleChromeLa…

Наибольшей популярностью пользуются специальные инструменты для написания кодмодов: Schematics, jscodeshift.

Schematics — это инструмент экосистемы Angular. Помогает при изменении структуры проекта в том числе на уровне трансформации кода angular.io/guide/schemati…

Но наиболее популярен инструмент от Facebook — jscodeshift. Он поддерживает flow, typescript, jsx. github.com/facebook/jscod…

Вот моя подборка кодмодов для jscodeshift. Заглядывайте, если будете писать свой кодмод, чтобы посмотреть на примеры github.com/myshov/codemod…

Самый интересный кодмод — экспериментальный конвертор функциональных React-компонентов в функциональные Vue-компоненты github.com/myshov/codemod…

При написании кодмодов очень помогает astexplorer — веб-приложение, с помощью которого можно проинспектировать AST-дерево. В нём есть поддержка очень многих языков и парсеров astexplorer.net

Ещё парсеры используются инструментами для анализа кода. Например, для "разминификации" кода github.com/shapesecurity/…

Ещё стоит упомянуть recast — библиотека для недеструктивного изменения исходного кода и генерации сорс мапов. Используется под капотом очень многих проектов в том числе jscodeshift github.com/benjamn/recast

Если хотите поподробнее узнать про AST, рекомендую интересный доклад Кирилла Черкашина из Google "Working with JavaScript Abstract Syntax Trees" (название на английском, но доклад на русском) youtube.com/watch?v=MPoO2x…

Если вас заинтересовала тема кодмодов, рекомендую посмотреть мой доклад, где я в подробностях рассказываю, что это такое и как их писать youtube.com/watch?v=GGb_ib…

На этом тред хочу закончить. Надеюсь, что этот тред вам был полезен и интересен. Спасибо за внимание :)