В 2002 году Алекс А. Степанов проводит лекцию в адоби: STL and Its Design Principles - где упоминает кейворд concept (там прям целый слайд про концепты). В 2009 году в свет выходит книга Elements of programming (Stepanov, McJones) и где по-моему нет ни одного алгоритма без концептов. В 2011 новый стандарт языка с++11, где в отложенных (прям очень жаль) фичах фигурируют концепты. В 2014 мир видит творенье Страуструпа - Tour of C++, где глава 5.4 названа Concepts and Generic Programming, хотя язык не поддерживает кейворд concept. Годом ранее, в 2013, Андрю Саттон публикует бумагу Concepts Lite. В стандарте с++14 появляется новая фича digit separators, но нет концептов. В 2017 на реддите обсуждают c++17 и предлагают отдохнуть еще три года. Через три года сочувствующий html разработчик захочет попробовать язык с чистого листа, заюзав и концепты, и модули. Модули привносят важное свойство - уменьшение времени компиляции. Идея в шаг за шагом написании небольших компонентов и комбинировании их после в нечто осознаное, например, линтер. Первым делом добавим функцию print: Компонент для матчинга строки нашего линтера (javascript кода) будет выглядить как-то так: Так как алгоритм выше constexpr, запускаем тесты на каждую! компиляцию модуля: У линтера, кажется, вырисовывается интерфейс: Тут идея вполне очевидная: много компонентов с одинаковым интерфейсом. Можем решить ее с помощью наследования, а можем позаимствовать идею из видео Better Code: Runtime Polymorphism (Sean Parent) -- в двух словах, тот же самый полиморфизм, но удобнее (e.g. extension of built-in types). Продолжим: Первый аргумент отвечает за тип компонента, второй -- обертка над парой итераторов. Обертка исключительно для читаемости: Есть несколько вариантов для типа возвращаемого значения result_t. У линтера на самом деле простая задача и, следовательно, простой результат действия: или мы нашли несоответствие, или все ок. По идее, выбор падает на bool, но на практике интересен линтер чуть-чуть поумнее, например std::optional\<std::size_t\>. Если все ок, возвращаем пустой опшионал, в противном случае - количество проделанных шагов до несоответствия. Если линтер нашел недействительный токен или не нашел искомый, кидаем эксепшн: Компоненты нашего линтера захочется композировать (или компоновать), поэтому пару/тройку связующих: Теперь собственно к разборке ("линтингу") javascript кода. Хедеры (или импорты) javascript файлов выглядят примерно так: Грамматика хедеров тут: https://262.ecma-international.org/6.0/#sec-imports . Компонент для хедеров import_t сигнатурой будет очень похож на все предыдушие компоненты: Внутри хотя будет интереснее, так как грамматику можно описать композицией компонентов (тут прям нужно добавить, что описание декларативное без всяких while и for-loop :) Описание import_t моделирует граф. Если в графах грамматики встречается цикл, уносим его в алгоритм, другими словами, для удобства добиваемся direct acyclic graph. Примером цикла есть токен import_var_list_t выше, который матчит { foo, bar, ...}, алгоритм которого будет петля, которую тоже можно тестировать на каждую компиляцию. Как-то не хочется заключение писать, так как линтер еще ой как далек от завершения. Хочется вспомнить книгу JavaScript: The Good Parts (Douglas Crockford, 8 May 2008), которая, как видно из названия, предлагает юзать только "хороший" сабсет грамматики из "яваскрипта". На сегодняшний день хороший сабсет будет еще меньше (например, for-loop, while -- нежелательны; var, let запрещены), то есть задача создания хорошего и быстрого линтера кажется не такая уж непосильная.